Skip to contentSkip to conversation

tracing: Fixes for 6.16

PATCH New Steven Rostedt 1 participant 3 messages Jul 19, 2025

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover tracing: Fixes for 6.16

git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
trace/fixes

Head SHA1: b5e8acc14dcb314a9b61ff19dcd9fdd0d88f70df

Steven Rostedt (1):
tracing: Add down_write(trace_event_sem) when adding trace event

Tomas Glozar (1):
tracing/osnoise: Fix crash in timerlat_dump_stack()

----

 kernel/trace/trace_events.c  | 5 +++++
 kernel/trace/trace_osnoise.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
#1 lore raw

PATCH 1/2 tracing/osnoise: Fix crash in timerlat_dump_stack()

From: Tomas Glozar <[email protected]>

We have observed kernel panics when using timerlat with stack saving, with the following dmesg output:

memcpy: detected buffer overflow: 88 byte write of buffer size 0

WARNING: CPU: 2 PID: 8153 at lib/string_helpers.c:1032 __fortify_report+0x55/0xa0
CPU: 2 UID: 0 PID: 8153 Comm: timerlatu/2 Kdump: loaded Not tainted 6.15.3-200.fc42.x86_64 #1 PREEMPT(lazy)
Call Trace:
 <TASK>
 ? trace_buffer_lock_reserve+0x2a/0x60
 __fortify_panic+0xd/0xf
 __timerlat_dump_stack.cold+0xd/0xd
 timerlat_dump_stack.part.0+0x47/0x80
 timerlat_fd_read+0x36d/0x390
 vfs_read+0xe2/0x390
 ? syscall_exit_to_user_mode+0x1d5/0x210
 ksys_read+0x73/0xe0
 do_syscall_64+0x7b/0x160
 ? exc_page_fault+0x7e/0x1a0
 entry_SYSCALL_64_after_hwframe+0x76/0x7e

__timerlat_dump_stack() constructs the ftrace stack entry like this:

struct stack_entry *entry;
...
memcpy(&entry->caller, fstack->calls, size);
entry->size = fstack->nr_entries;

Since commit e7186af7fb26 ("tracing: Add back FORTIFY_SOURCE logic to kernel_stack event structure"), struct stack_entry marks its caller field with __counted_by(size). At the time of the memcpy, entry->size contains garbage from the ringbuffer, which under some circumstances is zero, triggering a kernel panic by buffer overflow.

Populate the size field before the memcpy so that the out-of-bounds check knows the correct size. This is analogous to __ftrace_trace_stack().

Cc John Kacur <[email protected]>
Cc Luis Goncalves <[email protected]>
Cc Attila Fazekas <[email protected]>
Fixes e7186af7fb26 ("tracing: Add back FORTIFY_SOURCE logic to kernel_stack event structure")
---
 kernel/trace/trace_osnoise.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_osnoise.c +1 -1
index 6819b93309ce..fd259da0aa64 100644
@@ -637,8 +637,8 @@ __timerlat_dump_stack(struct trace_buffer *buffer, struct trace_stack *fstack, u
 
 	entry = ring_buffer_event_data(event);
 
-	memcpy(&entry->caller, fstack->calls, size);
 	entry->size = fstack->nr_entries;
+	memcpy(&entry->caller, fstack->calls, size);
 
 	trace_buffer_unlock_commit_nostack(buffer, event);
 }
Signature · 1 line
2.47.2
#2 lore raw

PATCH 2/2 tracing: Add down_write(trace_event_sem) when adding trace event

In reply to Steven Rostedt

From: Steven Rostedt <[email protected]>

When a module is loaded, it adds trace events defined by the module. It may also need to modify the modules trace printk formats to replace enum names with their values.

If two modules are loaded at the same time, the adding of the event to the ftrace_events list can corrupt the walking of the list in the code that is modifying the printk format strings and crash the kernel.

The addition of the event should take the trace_event_sem for write while it adds the new event.

Also add a lockdep_assert_held() on that semaphore in __trace_add_event_dirs() as it iterates the list.

---
 kernel/trace/trace_events.c | 5 +++++
 1 file changed, 5 insertions(+)
kernel/trace/trace_events.c +5 -0
index 120531268abf..d01e5c910ce1 100644
@@ -3136,7 +3136,10 @@ __register_event(struct trace_event_call *call, struct module *mod)
 	if (ret < 0)
 		return ret;
 
+	down_write(&trace_event_sem);
 	list_add(&call->list, &ftrace_events);
+	up_write(&trace_event_sem);
+
 	if (call->flags & TRACE_EVENT_FL_DYNAMIC)
 		atomic_set(&call->refcnt, 0);
 	else
@@ -3750,6 +3753,8 @@ __trace_add_event_dirs(struct trace_array *tr)
 	struct trace_event_call *call;
 	int ret;
 
+	lockdep_assert_held(&trace_event_sem);
+
 	list_for_each_entry(call, &ftrace_events, list) {
 		ret = __trace_add_new_event(call, tr);
 		if (ret < 0)
Signature · 1 line
2.47.2