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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'trace-v6.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing fixes from Steven Rostedt:

- Initialize hash variables in ftrace subops logic

The fix that simplified the ftrace subops logic opened a path where
some variables could be used without being initialized, and done
subtly where the compiler did not catch it. Initialize those
variables to the EMPTY_HASH, which is the default hash.

- Reinitialize the hash pointers after they are freed

Some of the hash pointers in the subop logic were freed but may still
be referenced later. To prevent use-after-free bugs, initialize them
back to the EMPTY_HASH.

- Free the ftrace hashes when they are replaced

The fix that simplified the subops logic updated some hash pointers,
but left the original hash that they were pointing to where they are
no longer used. This caused a memory leak. Free the hashes that are
pointed to by the pointers when they are replaced.

- Fix size initialization of ftrace direct function hash

The ftrace direct function hash used by BPF initialized the hash size
incorrectly. It checked the size of items to a hard coded 32, which
made the hash bit size of 5. The hash size is supposed to be limited
by the bit size of the hash, as the bitmask is allowed to be greater
than 5. Rework the size check to first pass the number of elements to
fls() and then compare that to FTRACE_HASH_MAX_BITS before allocating
the hash.

- Fix format output of ftrace_graph_ent_entry event

The field depth of the ftrace_graph_ent_entry event is of size 4 but
the output showed it as unsigned long and use "%lu". Change it to
unsigned int and use "%u" in the print format that is displayed to
user space.

- Fix the trace event filter on strings

Events can be filtered on numbers or string values. The return value
checked from strncpy_from_kernel_nofault() and
strncpy_from_user_nofault() was used to determine if reading the
strings would fault or not. It would return fault if the value was
non zero, which is basically meant that it was always considering the
read as a fault.

- Add selftest to test trace event string filtering

In order to catch the breakage of the string filtering, add a self
test to make sure that it continues to work.

* tag 'trace-v6.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
tracing: selftests: Add testing a user string to filters
tracing: Fix filter string testing
ftrace: Fix type of ftrace_graph_ent_entry.depth
ftrace: fix incorrect hash size in register_ftrace_direct()
ftrace: Free ftrace hashes after they are replaced in the subops code
ftrace: Reinitialize hash to EMPTY_HASH after freeing
ftrace: Initialize variables for ftrace_startup/shutdown_subops()

+43 -12
+19 -8
kernel/trace/ftrace.c
··· 1297 1297 return; 1298 1298 free_ftrace_hash(ops->func_hash->filter_hash); 1299 1299 free_ftrace_hash(ops->func_hash->notrace_hash); 1300 + ops->func_hash->filter_hash = EMPTY_HASH; 1301 + ops->func_hash->notrace_hash = EMPTY_HASH; 1300 1302 } 1301 1303 EXPORT_SYMBOL_GPL(ftrace_free_filter); 1302 1304 ··· 3445 3443 size_bits); 3446 3444 if (ret < 0) { 3447 3445 free_ftrace_hash(*filter_hash); 3446 + *filter_hash = EMPTY_HASH; 3448 3447 return ret; 3449 3448 } 3450 3449 } ··· 3475 3472 subops_hash->notrace_hash); 3476 3473 if (ret < 0) { 3477 3474 free_ftrace_hash(*notrace_hash); 3475 + *notrace_hash = EMPTY_HASH; 3478 3476 return ret; 3479 3477 } 3480 3478 } ··· 3494 3490 */ 3495 3491 int ftrace_startup_subops(struct ftrace_ops *ops, struct ftrace_ops *subops, int command) 3496 3492 { 3497 - struct ftrace_hash *filter_hash; 3498 - struct ftrace_hash *notrace_hash; 3493 + struct ftrace_hash *filter_hash = EMPTY_HASH; 3494 + struct ftrace_hash *notrace_hash = EMPTY_HASH; 3499 3495 struct ftrace_hash *save_filter_hash; 3500 3496 struct ftrace_hash *save_notrace_hash; 3501 3497 int ret; ··· 3609 3605 } 3610 3606 } 3611 3607 3608 + free_ftrace_hash(temp_hash.filter_hash); 3609 + free_ftrace_hash(temp_hash.notrace_hash); 3610 + 3612 3611 temp_hash.filter_hash = *filter_hash; 3613 3612 temp_hash.notrace_hash = *notrace_hash; 3614 3613 } ··· 3632 3625 */ 3633 3626 int ftrace_shutdown_subops(struct ftrace_ops *ops, struct ftrace_ops *subops, int command) 3634 3627 { 3635 - struct ftrace_hash *filter_hash; 3636 - struct ftrace_hash *notrace_hash; 3628 + struct ftrace_hash *filter_hash = EMPTY_HASH; 3629 + struct ftrace_hash *notrace_hash = EMPTY_HASH; 3637 3630 int ret; 3638 3631 3639 3632 if (unlikely(ftrace_disabled)) ··· 3706 3699 } 3707 3700 3708 3701 ret = rebuild_hashes(&filter_hash, &notrace_hash, ops); 3709 - if (!ret) 3702 + if (!ret) { 3710 3703 ret = ftrace_update_ops(ops, filter_hash, notrace_hash); 3704 + free_ftrace_hash(filter_hash); 3705 + free_ftrace_hash(notrace_hash); 3706 + } 3711 3707 3712 3708 if (ret) { 3713 3709 /* Put back the original hash */ ··· 5964 5954 5965 5955 /* Make a copy hash to place the new and the old entries in */ 5966 5956 size = hash->count + direct_functions->count; 5967 - if (size > 32) 5968 - size = 32; 5969 - new_hash = alloc_ftrace_hash(fls(size)); 5957 + size = fls(size); 5958 + if (size > FTRACE_HASH_MAX_BITS) 5959 + size = FTRACE_HASH_MAX_BITS; 5960 + new_hash = alloc_ftrace_hash(size); 5970 5961 if (!new_hash) 5971 5962 goto out_unlock; 5972 5963
+2 -2
kernel/trace/trace_entries.h
··· 80 80 F_STRUCT( 81 81 __field_struct( struct ftrace_graph_ent, graph_ent ) 82 82 __field_packed( unsigned long, graph_ent, func ) 83 - __field_packed( unsigned long, graph_ent, depth ) 83 + __field_packed( unsigned int, graph_ent, depth ) 84 84 __dynamic_array(unsigned long, args ) 85 85 ), 86 86 87 - F_printk("--> %ps (%lu)", (void *)__entry->func, __entry->depth) 87 + F_printk("--> %ps (%u)", (void *)__entry->func, __entry->depth) 88 88 ); 89 89 90 90 #ifdef CONFIG_FUNCTION_GRAPH_RETADDR
+2 -2
kernel/trace/trace_events_filter.c
··· 808 808 kstr = ubuf->buffer; 809 809 810 810 /* For safety, do not trust the string pointer */ 811 - if (!strncpy_from_kernel_nofault(kstr, str, USTRING_BUF_SIZE)) 811 + if (strncpy_from_kernel_nofault(kstr, str, USTRING_BUF_SIZE) < 0) 812 812 return NULL; 813 813 return kstr; 814 814 } ··· 827 827 828 828 /* user space address? */ 829 829 ustr = (char __user *)str; 830 - if (!strncpy_from_user_nofault(kstr, ustr, USTRING_BUF_SIZE)) 830 + if (strncpy_from_user_nofault(kstr, ustr, USTRING_BUF_SIZE) < 0) 831 831 return NULL; 832 832 833 833 return kstr;
+20
tools/testing/selftests/ftrace/test.d/filter/event-filter-function.tc
··· 80 80 exit_fail 81 81 fi 82 82 83 + # Check strings too 84 + if [ -f events/syscalls/sys_enter_openat/filter ]; then 85 + DIRNAME=`basename $TMPDIR` 86 + echo "filename.ustring ~ \"*$DIRNAME*\"" > events/syscalls/sys_enter_openat/filter 87 + echo 1 > events/syscalls/sys_enter_openat/enable 88 + echo 1 > tracing_on 89 + ls /bin/sh 90 + nocnt=`grep openat trace | wc -l` 91 + ls $TMPDIR 92 + echo 0 > tracing_on 93 + hitcnt=`grep openat trace | wc -l`; 94 + echo 0 > events/syscalls/sys_enter_openat/enable 95 + if [ $nocnt -gt 0 ]; then 96 + exit_fail 97 + fi 98 + if [ $hitcnt -eq 0 ]; then 99 + exit_fail 100 + fi 101 + fi 102 + 83 103 reset_events_filter 84 104 85 105 exit 0