Skip to content

Commit

Permalink
Merge tag 'trace-v6.15-rc2' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/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()
  • Loading branch information
Linus Torvalds committed Apr 19, 2025
2 parents 1ca0f93 + d481ee3 commit fa6ad96
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 12 deletions.
27 changes: 19 additions & 8 deletions kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1297,6 +1297,8 @@ void ftrace_free_filter(struct ftrace_ops *ops)
return;
free_ftrace_hash(ops->func_hash->filter_hash);
free_ftrace_hash(ops->func_hash->notrace_hash);
ops->func_hash->filter_hash = EMPTY_HASH;
ops->func_hash->notrace_hash = EMPTY_HASH;
}
EXPORT_SYMBOL_GPL(ftrace_free_filter);

Expand Down Expand Up @@ -3443,6 +3445,7 @@ static int add_next_hash(struct ftrace_hash **filter_hash, struct ftrace_hash **
size_bits);
if (ret < 0) {
free_ftrace_hash(*filter_hash);
*filter_hash = EMPTY_HASH;
return ret;
}
}
Expand Down Expand Up @@ -3472,6 +3475,7 @@ static int add_next_hash(struct ftrace_hash **filter_hash, struct ftrace_hash **
subops_hash->notrace_hash);
if (ret < 0) {
free_ftrace_hash(*notrace_hash);
*notrace_hash = EMPTY_HASH;
return ret;
}
}
Expand All @@ -3490,8 +3494,8 @@ static int add_next_hash(struct ftrace_hash **filter_hash, struct ftrace_hash **
*/
int ftrace_startup_subops(struct ftrace_ops *ops, struct ftrace_ops *subops, int command)
{
struct ftrace_hash *filter_hash;
struct ftrace_hash *notrace_hash;
struct ftrace_hash *filter_hash = EMPTY_HASH;
struct ftrace_hash *notrace_hash = EMPTY_HASH;
struct ftrace_hash *save_filter_hash;
struct ftrace_hash *save_notrace_hash;
int ret;
Expand Down Expand Up @@ -3605,6 +3609,9 @@ static int rebuild_hashes(struct ftrace_hash **filter_hash, struct ftrace_hash *
}
}

free_ftrace_hash(temp_hash.filter_hash);
free_ftrace_hash(temp_hash.notrace_hash);

temp_hash.filter_hash = *filter_hash;
temp_hash.notrace_hash = *notrace_hash;
}
Expand All @@ -3625,8 +3632,8 @@ static int rebuild_hashes(struct ftrace_hash **filter_hash, struct ftrace_hash *
*/
int ftrace_shutdown_subops(struct ftrace_ops *ops, struct ftrace_ops *subops, int command)
{
struct ftrace_hash *filter_hash;
struct ftrace_hash *notrace_hash;
struct ftrace_hash *filter_hash = EMPTY_HASH;
struct ftrace_hash *notrace_hash = EMPTY_HASH;
int ret;

if (unlikely(ftrace_disabled))
Expand Down Expand Up @@ -3699,8 +3706,11 @@ static int ftrace_hash_move_and_update_subops(struct ftrace_ops *subops,
}

ret = rebuild_hashes(&filter_hash, &notrace_hash, ops);
if (!ret)
if (!ret) {
ret = ftrace_update_ops(ops, filter_hash, notrace_hash);
free_ftrace_hash(filter_hash);
free_ftrace_hash(notrace_hash);
}

if (ret) {
/* Put back the original hash */
Expand Down Expand Up @@ -5954,9 +5964,10 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)

/* Make a copy hash to place the new and the old entries in */
size = hash->count + direct_functions->count;
if (size > 32)
size = 32;
new_hash = alloc_ftrace_hash(fls(size));
size = fls(size);
if (size > FTRACE_HASH_MAX_BITS)
size = FTRACE_HASH_MAX_BITS;
new_hash = alloc_ftrace_hash(size);
if (!new_hash)
goto out_unlock;

Expand Down
4 changes: 2 additions & 2 deletions kernel/trace/trace_entries.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry,
F_STRUCT(
__field_struct( struct ftrace_graph_ent, graph_ent )
__field_packed( unsigned long, graph_ent, func )
__field_packed( unsigned long, graph_ent, depth )
__field_packed( unsigned int, graph_ent, depth )
__dynamic_array(unsigned long, args )
),

F_printk("--> %ps (%lu)", (void *)__entry->func, __entry->depth)
F_printk("--> %ps (%u)", (void *)__entry->func, __entry->depth)
);

#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
Expand Down
4 changes: 2 additions & 2 deletions kernel/trace/trace_events_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ static __always_inline char *test_string(char *str)
kstr = ubuf->buffer;

/* For safety, do not trust the string pointer */
if (!strncpy_from_kernel_nofault(kstr, str, USTRING_BUF_SIZE))
if (strncpy_from_kernel_nofault(kstr, str, USTRING_BUF_SIZE) < 0)
return NULL;
return kstr;
}
Expand All @@ -827,7 +827,7 @@ static __always_inline char *test_ustring(char *str)

/* user space address? */
ustr = (char __user *)str;
if (!strncpy_from_user_nofault(kstr, ustr, USTRING_BUF_SIZE))
if (strncpy_from_user_nofault(kstr, ustr, USTRING_BUF_SIZE) < 0)
return NULL;

return kstr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,26 @@ if [ $misscnt -gt 0 ]; then
exit_fail
fi

# Check strings too
if [ -f events/syscalls/sys_enter_openat/filter ]; then
DIRNAME=`basename $TMPDIR`
echo "filename.ustring ~ \"*$DIRNAME*\"" > events/syscalls/sys_enter_openat/filter
echo 1 > events/syscalls/sys_enter_openat/enable
echo 1 > tracing_on
ls /bin/sh
nocnt=`grep openat trace | wc -l`
ls $TMPDIR
echo 0 > tracing_on
hitcnt=`grep openat trace | wc -l`;
echo 0 > events/syscalls/sys_enter_openat/enable
if [ $nocnt -gt 0 ]; then
exit_fail
fi
if [ $hitcnt -eq 0 ]; then
exit_fail
fi
fi

reset_events_filter

exit 0

0 comments on commit fa6ad96

Please sign in to comment.