Thread (1 message) 1 message, 1 author, 2026-08-25

Re: [PATCH] tracing: Fix use-after-free on field name/type of dynamic probe events

From: Steven Rostedt <rostedt@goodmis.org>
Date: 2026-08-25 13:37:41
Also in: lkml

On Tue, 25 Aug 2026 19:03:03 +0800
henry martin [off-list ref] wrote:
quoted
quoted
When several probes are appended to the same event, they share the
trace_event_call and its field list, which stays the one defined by
the primary probe. Deleting just the primary probe with  
What do you mean by "appended to the same event"? Do you mean eprobes?
 
Not eprobes -- I mean the kprobe multi-probe-per-event feature from the
Fixes: commit (append_trace_kprobe()): two probes registered under one
event name with identical arg names/types but different symbols, so they
share a single trace_event_call. eprobe/uprobe/fprobe are affected too
only because they all define their fields through the same helper
(traceprobe_define_arg_fields()), but the reproducer below is plain
kprobe.
quoted
Can you post a reproducer for this?  
Run as root with KASAN, inside the guest:
Does it matter being inside a guest?
  cd /sys/kernel/tracing
  # primary A: fields are defined from A's args
  echo 'p:kprobes/ev vfs_read  a1=$arg1' >  kprobe_events
  # append B: shares A's event call
  echo 'p:kprobes/ev vfs_write a1=$arg1' >> kprobe_events
  # delete ONLY A (matched by symbol), B survives
  echo '-:kprobes/ev vfs_read'           >> kprobe_events
  # field lookup -> strcmp() on the freed name
  echo 'a1 == 1' > events/kprobes/ev/filter

  BUG: KASAN: slab-use-after-free in strcmp+0xa7/0xb0
   trace_find_event_field
   parse_pred
   process_preds
   create_filter
   apply_event_filter
   event_filter_write

  Freed by: traceprobe_free_probe_arg / trace_probe_cleanup /
            free_trace_kprobe / ... / dyn_event_release
The above is useful information to include in the change log.
Deleting A runs trace_probe_cleanup(A), which frees A's args, then
trace_probe_unlink(A) keeps the trace_probe_event because B is still on
the probe list. The event survives via B while its fields still point at
A's freed arg->name (and, for array args, arg->fmt). Both the delete and
the filter write hold event_mutex, so it is a dangling reference after
removal, not a race -- it triggers every time.
quoted
 
quoted
"-:group/event symbol" frees the trace_probe and its argument
strings, while the event call is kept registered by the remaining
sibling probes. field->name and field->type are left dangling, and
any field lookup - e.g. writing to events/<grp>/<ev>/filter - reads
freed memory:

  BUG: KASAN: slab-use-after-free in strcmp+0xa7/0xb0
  Call trace:
   trace_find_event_field+0xd6/0x220
   parse_pred
   process_preds
   create_filter
   apply_event_filter
   event_filter_write

Make the field own its strings: duplicate name and type with
kstrdup_const() in __trace_define_field() and release them with
kfree_const() in trace_destroy_fields(). Fields of static trace
events still reference their kernel/module rodata string literals
directly, as kstrdup_const()/kfree_const() only touch memory that
was actually allocated.  
Wrong fix.
 
quoted
The issue was found by the autokbug dynamic kernel fuzzer at Tencent
Yunding Lab.

Fixes: ca89bc071d5e4 ("tracing/kprobe: Add multi-probe per event  
support")
quoted
quoted
Signed-off-by: Henry Martin <redacted>
---
 kernel/trace/trace_events.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index c01b10b99f67e..ee3b93fa09ee8 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c  
This is a bug with trace_probes.c and not trace_events.c. This should be
fixed without touching trace_events.c. That is, the trace_probes.c code
 
(or
quoted
trace_eprobes.c if it's only affects eprobes) should handle this issue.
 
Agreed, that was the wrong place. v3 keeps trace_define_field() and all
static events untouched and fixes it where the borrowing happens:
traceprobe_define_arg_fields() now kstrdup()s the name/type, and the
copies are owned by the trace_probe_event (which embeds the event call
and outlives every individual probe), freed in trace_probe_event_free().
It is one helper plus its teardown, both in trace_probe.c, plus two
fields on struct trace_probe_event.

v3 is posted as a reply in this thread, tested with KASAN +
Please post new versions as a separate thread. It helps with tooling.
kasan_multi_shot. The reproducer above triggers the UAF reliably on the
unpatched tree; with the patch, deleting the primary probe leaves
format/filter intact on the surviving event and the report is gone. I
also checked the array-arg
case (arr=+0($arg1):u64[2]), where field->type borrows the kmalloc'd
parg->fmt: the type string survives the primary delete and full teardown
afterwards shows no double-free.

Thanks for the review.
I'll look at your other patch.

Thanks,

-- Steve
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help