]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
tracing: Add recursion protection in kernel stack trace recording
authorSteven Rostedt <rostedt@goodmis.org>
Tue, 6 Jan 2026 01:31:41 +0000 (20:31 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 17 Jan 2026 15:35:12 +0000 (16:35 +0100)
commit 5f1ef0dfcb5b7f4a91a9b0e0ba533efd9f7e2cdb upstream.

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/20260102122807.7025fc87@gandalf.local.home/
Cc: stable@vger.kernel.org
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Joel Fernandes <joel@joelfernandes.org>
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Boqun Feng <boqun.feng@gmail.com>
Link: https://patch.msgid.link/20260105203141.515cd49f@gandalf.local.home
Reported-by: Yao Kai <yaokai34@huawei.com>
Tested-by: Yao Kai <yaokai34@huawei.com>
Fixes: 5f5fa7ea89dc ("rcu: Don't use negative nesting depth in __rcu_read_unlock()")
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/linux/trace_recursion.h
kernel/trace/trace.c

index ae04054a1be360e249c337da1905bd13d73f98ca..e6ca052b2a85a7c9b66c18de9571ceb5fbb57b51 100644 (file)
@@ -34,6 +34,13 @@ enum {
        TRACE_INTERNAL_SIRQ_BIT,
        TRACE_INTERNAL_TRANSITION_BIT,
 
+       /* Internal event use recursion bits */
+       TRACE_INTERNAL_EVENT_BIT,
+       TRACE_INTERNAL_EVENT_NMI_BIT,
+       TRACE_INTERNAL_EVENT_IRQ_BIT,
+       TRACE_INTERNAL_EVENT_SIRQ_BIT,
+       TRACE_INTERNAL_EVENT_TRANSITION_BIT,
+
        TRACE_BRANCH_BIT,
 /*
  * Abuse of the trace_recursion.
@@ -58,6 +65,8 @@ enum {
 
 #define TRACE_LIST_START       TRACE_INTERNAL_BIT
 
+#define TRACE_EVENT_START      TRACE_INTERNAL_EVENT_BIT
+
 #define TRACE_CONTEXT_MASK     ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1)
 
 /*
index 304e93597126e5eb786d851e2166a4e1b49b808c..ddff2af3cd3f7d222aa5c132c8c7745e1929be1e 100644 (file)
@@ -3003,6 +3003,11 @@ static void __ftrace_trace_stack(struct trace_array *tr,
        struct ftrace_stack *fstack;
        struct stack_entry *entry;
        int stackidx;
+       int bit;
+
+       bit = trace_test_and_set_recursion(_THIS_IP_, _RET_IP_, TRACE_EVENT_START);
+       if (bit < 0)
+               return;
 
        /*
         * Add one, for this function and the call to save_stack_trace()
@@ -3071,6 +3076,7 @@ static void __ftrace_trace_stack(struct trace_array *tr,
        /* Again, don't let gcc optimize things here */
        barrier();
        __this_cpu_dec(ftrace_stack_reserve);
+       trace_clear_recursion(bit);
 }
 
 static inline void ftrace_trace_stack(struct trace_array *tr,