Skip to content

Commit 5f1ef0d

Browse files
committed
tracing: Add recursion protection in kernel stack trace recording
A bug was reported about an infinite recursion caused by tracing the rcu events with the kernel stack trace trigger enabled. The stack trace code called back into RCU which then called the stack trace again. Expand the ftrace recursion protection to add a set of bits to protect events from recursion. Each bit represents the context that the event is in (normal, softirq, interrupt and NMI). Have the stack trace code use the interrupt context to protect against recursion. Note, the bug showed an issue in both the RCU code as well as the tracing stacktrace code. This only handles the tracing stack trace side of the bug. The RCU fix will be handled separately. Link: https://lore.kernel.org/all/[email protected]/ Cc: [email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Joel Fernandes <[email protected]> Cc: "Paul E. McKenney" <[email protected]> Cc: Boqun Feng <[email protected]> Link: https://patch.msgid.link/[email protected] Reported-by: Yao Kai <[email protected]> Tested-by: Yao Kai <[email protected]> Fixes: 5f5fa7e ("rcu: Don't use negative nesting depth in __rcu_read_unlock()") Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 5232196 commit 5f1ef0d

2 files changed

Lines changed: 15 additions & 0 deletions

File tree

include/linux/trace_recursion.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ enum {
3434
TRACE_INTERNAL_SIRQ_BIT,
3535
TRACE_INTERNAL_TRANSITION_BIT,
3636

37+
/* Internal event use recursion bits */
38+
TRACE_INTERNAL_EVENT_BIT,
39+
TRACE_INTERNAL_EVENT_NMI_BIT,
40+
TRACE_INTERNAL_EVENT_IRQ_BIT,
41+
TRACE_INTERNAL_EVENT_SIRQ_BIT,
42+
TRACE_INTERNAL_EVENT_TRANSITION_BIT,
43+
3744
TRACE_BRANCH_BIT,
3845
/*
3946
* Abuse of the trace_recursion.
@@ -58,6 +65,8 @@ enum {
5865

5966
#define TRACE_LIST_START TRACE_INTERNAL_BIT
6067

68+
#define TRACE_EVENT_START TRACE_INTERNAL_EVENT_BIT
69+
6170
#define TRACE_CONTEXT_MASK ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1)
6271

6372
/*

kernel/trace/trace.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3012,6 +3012,11 @@ static void __ftrace_trace_stack(struct trace_array *tr,
30123012
struct ftrace_stack *fstack;
30133013
struct stack_entry *entry;
30143014
int stackidx;
3015+
int bit;
3016+
3017+
bit = trace_test_and_set_recursion(_THIS_IP_, _RET_IP_, TRACE_EVENT_START);
3018+
if (bit < 0)
3019+
return;
30153020

30163021
/*
30173022
* Add one, for this function and the call to save_stack_trace()
@@ -3080,6 +3085,7 @@ static void __ftrace_trace_stack(struct trace_array *tr,
30803085
/* Again, don't let gcc optimize things here */
30813086
barrier();
30823087
__this_cpu_dec(ftrace_stack_reserve);
3088+
trace_clear_recursion(bit);
30833089
}
30843090

30853091
static inline void ftrace_trace_stack(struct trace_array *tr,

0 commit comments

Comments
 (0)