tracing: Fixes for v6.15
Subsystems (3)
Steven Rostedt
maintainercover tracing: Fixes for v6.15
tracing updates for v6.15
- Fix read out of bounds bug in tracing_splice_read_pipe()
The size of the sub page being read can now be greater than a page. But the buffer used in tracing_splice_read_pipe() only allocates a page size. The data copied to the buffer is the amount in sub buffer which can overflow the buffer. Use min((size_t)trace_seq_used(&iter->seq), PAGE_SIZE) to limit the amount copied to the buffer to a max of PAGE_SIZE.
- Fix the test for NULL from "!filter_hash" to "!*filter_hash"
The add_next_hash() function checked for NULL at the wrong pointer level.
- Do not use the array in trace_adjust_address() if there are no elements
The trace_adjust_address() finds the offset of a module that was stored in the persistent buffer when reading the previous boot buffer to see if the address belongs to a module that was loaded in the previous boot. An array is created that matches currently loaded modules with previously loaded modules. The trace_adjust_address() uses that array to find the new offset of the address that's in the previous buffer. But if no module was loaded, it ends up reading the last element in an array that was never allocated. Check if nr_entries is zero and exit out early if it is.
- Remove nested lock of trace_event_sem in print_event_fields()
The print_event_fields() function iterates over the ftrace_events list and requires the trace_event_sem semaphore held for read. But this function is always called with that semaphore held for read. Remove the taking of the semaphore and replace it with lockdep_assert_held_read(&trace_event_sem);
git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
trace/fixes
Head SHA1: 0a8f11f8569e7ed16cbcedeb28c4350f6378fea6
Colin Ian King (1):
ftrace: Fix NULL memory allocation check
Jeongjun Park (1):
tracing: Fix oob write in trace_seq_to_buffer()
Steven Rostedt (2):
tracing: Fix trace_adjust_address() when there is no modules in scratch area
tracing: Do not take trace_event_sem in print_event_fields()
----
kernel/trace/ftrace.c | 2 +- kernel/trace/trace.c | 9 ++++++--- kernel/trace/trace_output.c | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-)
Steven Rostedt
maintainerPATCH 1/4 tracing: Fix oob write in trace_seq_to_buffer()
From: Jeongjun Park <[email protected]>
syzbot reported this bug:
==================================================================
BUG: KASAN: slab-out-of-bounds in trace_seq_to_buffer kernel/trace/trace.c:1830 [inline] BUG: KASAN: slab-out-of-bounds in tracing_splice_read_pipe+0x6be/0xdd0 kernel/trace/trace.c:6822 Write of size 4507 at addr ffff888032b6b000 by task syz.2.320/7260 CPU: 1 UID: 0 PID: 7260 Comm: syz.2.320 Not tainted 6.15.0-rc1-syzkaller-00301-g3bde70a2c827 #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2025 Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:408 [inline] print_report+0xc3/0x670 mm/kasan/report.c:521 kasan_report+0xe0/0x110 mm/kasan/report.c:634 check_region_inline mm/kasan/generic.c:183 [inline] kasan_check_range+0xef/0x1a0 mm/kasan/generic.c:189 __asan_memcpy+0x3c/0x60 mm/kasan/shadow.c:106 trace_seq_to_buffer kernel/trace/trace.c:1830 [inline] tracing_splice_read_pipe+0x6be/0xdd0 kernel/trace/trace.c:6822 .... ==================================================================
It has been reported that trace_seq_to_buffer() tries to copy more data than PAGE_SIZE to buf. Therefore, to prevent this, we should use the smaller of trace_seq_used(&iter->seq) and PAGE_SIZE as an argument.
--- kernel/trace/trace.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/trace/trace.c +3 -2
@@ -6821,13 +6821,14 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,/* Copy the data into the page, so we can start over. */ ret =trace_seq_to_buffer (&iter->seq,page_address (spd.pages[i]), -trace_seq_used (&iter->seq)); +min ((size_t )trace_seq_used (&iter->seq), +PAGE_SIZE ));if (ret <0 ) {__free_page (spd.pages[i]);break ; } spd.partial[i].offset =0 ; - spd.partial[i].len =trace_seq_used (&iter->seq); + spd.partial[i].len = ret;trace_seq_init (&iter->seq); }
Signature · 1 line
2.47.2
Steven Rostedt
maintainerPATCH 2/4 ftrace: Fix NULL memory allocation check
In reply to Steven RostedtFrom: Colin Ian King <[email protected]>
The check for a failed memory location is incorrectly checking the wrong level of pointer indirection by checking !filter_hash rather than !*filter_hash. Fix this.
--- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/ftrace.c +1 -1
@@ -3436,7 +3436,7 @@ static int add_next_hash(struct ftrace_hash **filter_hash, struct ftrace_hash **/* Copy the subops hash */ *filter_hash =alloc_and_copy_ftrace_hash (size_bits, subops_hash->filter_hash); -if (!filter_hash) +if (!*filter_hash)return -ENOMEM ;/* Remove any notrace functions from the copy */ remove_hash (*filter_hash, subops_hash->notrace_hash);
Signature · 1 line
2.47.2
Steven Rostedt
maintainerPATCH 3/4 tracing: Fix trace_adjust_address() when there is no modules in scratch area
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
The function trace_adjust_address() is used to map addresses of modules stored in the persistent memory and are also loaded in the current boot to return the current address for the module.
If there's only one module entry, it will simply use that, otherwise it performs a bsearch of the entry array to find the modules to offset with.
The issue is if there are no modules in the array. The code does not account for that and ends up referencing the first element in the array which does not exist and causes a crash.
If nr_entries is zero, exit out early as if this was a core kernel address.
--- kernel/trace/trace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
kernel/trace/trace.c +3 -1
@@ -6043,8 +6043,10 @@ unsigned long trace_adjust_address(struct trace_array *tr, unsigned long addr) tscratch = tr->scratch;/* if there is no tscrach, module_delta must be NULL. */ module_delta =READ_ONCE (tr->module_delta); -if (!module_delta || tscratch->entries[0 ].mod_addr > addr) +if (!module_delta || !tscratch->nr_entries || + tscratch->entries[0 ].mod_addr > addr) {return addr + tr->text_delta; + }/* Note that entries must be sorted. */ nr_entries = tscratch->nr_entries;
Signature · 1 line
2.47.2
Steven Rostedt
maintainerPATCH 4/4 tracing: Do not take trace_event_sem in print_event_fields()
In reply to Steven RostedtFrom: Steven Rostedt <[email protected]>
On some paths in print_event_fields() it takes the trace_event_sem for read, even though it should always be held when the function is called.
Remove the taking of that mutex and add a lockdep_assert_held_read() to make sure the trace_event_sem is held when print_event_fields() is called.
--- kernel/trace/trace_output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/trace/trace_output.c +2 -2
@@ -1042,11 +1042,12 @@ enum print_line_t print_event_fields(struct trace_iterator *iter,struct trace_event_call *call;struct list_head *head; +lockdep_assert_held_read (&trace_event_sem); +/* ftrace defined events have separate call structures */ if (event->type <= __TRACE_LAST_TYPE) {bool found = false; -down_read (&trace_event_sem);list_for_each_entry (call, &ftrace_events, list) {if (call->event.type == event->type) { found = true;
@@ -1056,7 +1057,6 @@ enum print_line_t print_event_fields(struct trace_iterator *iter,if (call->event.type > __TRACE_LAST_TYPE)break ; } -up_read (&trace_event_sem);if (!found) {trace_seq_printf (&iter->seq,"UNKNOWN TYPE %d\n" , event->type); goto out;
Signature · 1 line
2.47.2