Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tracing: Verify event formats that have "%*p.."

The trace event verifier checks the formats of trace events to make sure
that they do not point at memory that is not in the trace event itself or
in data that will never be freed. If an event references data that was
allocated when the event triggered and that same data is freed before the
event is read, then the kernel can crash by reading freed memory.

The verifier runs at boot up (or module load) and scans the print formats
of the events and checks their arguments to make sure that dereferenced
pointers are safe. If the format uses "%*p.." the verifier will ignore it,
and that could be dangerous. Cover this case as well.

Also add to the sample code a use case of "%*pbl".

Link: https://lore.kernel.org/all/bcba4d76-2c3f-4d11-baf0-02905db953dd@oracle.com/

Cc: stable@vger.kernel.org
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fixes: 5013f454a352c ("tracing: Add check of trace event print fmts for dereferencing pointers")
Link: https://lore.kernel.org/20250327195311.2d89ec66@gandalf.local.home
Reported-by: Libo Chen <libo.chen@oracle.com>
Reviewed-by: Libo Chen <libo.chen@oracle.com>
Tested-by: Libo Chen <libo.chen@oracle.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

+13 -2
+7
kernel/trace/trace_events.c
··· 470 470 case '%': 471 471 continue; 472 472 case 'p': 473 + do_pointer: 473 474 /* Find dereferencing fields */ 474 475 switch (fmt[i + 1]) { 475 476 case 'B': case 'R': case 'r': ··· 499 498 continue; 500 499 if (fmt[i + j] == '*') { 501 500 star = true; 501 + /* Handle %*pbl case */ 502 + if (!j && fmt[i + 1] == 'p') { 503 + arg++; 504 + i++; 505 + goto do_pointer; 506 + } 502 507 continue; 503 508 } 504 509 if ((fmt[i + j] == 's')) {
+6 -2
samples/trace_events/trace-events-sample.h
··· 319 319 __assign_cpumask(cpum, cpumask_bits(mask)); 320 320 ), 321 321 322 - TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, 322 + TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s [%d] %*pbl", 323 + __entry->foo, __entry->bar, 323 324 324 325 /* 325 326 * Notice here the use of some helper functions. This includes: ··· 371 370 372 371 __get_str(str), __get_str(lstr), 373 372 __get_bitmask(cpus), __get_cpumask(cpum), 374 - __get_str(vstr)) 373 + __get_str(vstr), 374 + __get_dynamic_array_len(cpus), 375 + __get_dynamic_array_len(cpus), 376 + __get_dynamic_array(cpus)) 375 377 ); 376 378 377 379 /*