Skip to content

Commit

Permalink
extable: Enable RCU if it is not watching in kernel_text_address()
Browse files Browse the repository at this point in the history
If kernel_text_address() is called when RCU is not watching, it can cause an
RCU bug because is_module_text_address(), the is_kprobe_*insn_slot()
and is_bpf_text_address() functions require the use of RCU.

Only enable RCU if it is not currently watching before it calls
is_module_text_address(). The use of rcu_nmi_enter() is used to enable RCU
because kernel_text_address() can happen pretty much anywhere (like an NMI),
and even from within an NMI. It is called via save_stack_trace() that can be
called by any WARN() or tracing function, which can happen while RCU is not
watching (for example, going to or coming from idle, or during CPU take down
or bring up).

Cc: [email protected]
Fixes: 0be964b ("module: Sanitize RCU usage and locking")
Acked-by: Paul E. McKenney <[email protected]>
Signed-off-by: Steven Rostedt (VMware) <[email protected]>
  • Loading branch information
rostedt committed Sep 23, 2017
1 parent 9aadde9 commit e8cac8b
Showing 1 changed file with 30 additions and 5 deletions.
35 changes: 30 additions & 5 deletions kernel/extable.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,42 @@ int __kernel_text_address(unsigned long addr)

int kernel_text_address(unsigned long addr)
{
bool no_rcu;
int ret = 1;

if (core_kernel_text(addr))
return 1;

/*
* If a stack dump happens while RCU is not watching, then
* RCU needs to be notified that it requires to start
* watching again. This can happen either by tracing that
* triggers a stack trace, or a WARN() that happens during
* coming back from idle, or cpu on or offlining.
*
* is_module_text_address() as well as the kprobe slots
* and is_bpf_text_address() require RCU to be watching.
*/
no_rcu = !rcu_is_watching();

/* Treat this like an NMI as it can happen anywhere */
if (no_rcu)
rcu_nmi_enter();

if (is_module_text_address(addr))
return 1;
goto out;
if (is_ftrace_trampoline(addr))
return 1;
goto out;
if (is_kprobe_optinsn_slot(addr) || is_kprobe_insn_slot(addr))
return 1;
goto out;
if (is_bpf_text_address(addr))
return 1;
return 0;
goto out;
ret = 0;
out:
if (no_rcu)
rcu_nmi_exit();

return ret;
}

/*
Expand Down

0 comments on commit e8cac8b

Please sign in to comment.