ftrace: Updates for v6.15
Subsystems (3)
Steven Rostedt
maintainercover ftrace: Updates for v6.15
git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
ftrace/for-next
Head SHA1: 391dda1bd7c56de62b96126214f040fe8965561b
Jiapeng Chong (1):
function_graph: Remove the unused variable func
Sasha Levin (1):
tracing: Use hashtable.h for event_hash
Tengda Wu (1):
tracing: Fix use-after-free in print_graph_function_flags during tracer switching
----
kernel/trace/trace_functions_graph.c | 4 +--- kernel/trace/trace_irqsoff.c | 2 -- kernel/trace/trace_output.c | 19 +++++++------------ kernel/trace/trace_sched_wakeup.c | 2 -- 4 files changed, 8 insertions(+), 19 deletions(-)
Steven Rostedt
maintainerPATCH 1/3 function_graph: Remove the unused variable func
From: Jiapeng Chong <[email protected]>
Variable func is not effectively used, so delete it.
kernel/trace/trace_functions_graph.c:925:16: warning: variable ‘func’ set but not used.
This happened because the variable "func" which came from "call->func" was replaced by "ret_func" coming from "graph_ret->func" but "func" wasn't removed after the replacement.
--- kernel/trace/trace_functions_graph.c | 3 --- 1 file changed, 3 deletions(-)
kernel/trace/trace_functions_graph.c +0 -3
@@ -922,7 +922,6 @@ print_graph_entry_leaf(struct trace_iterator *iter,struct ftrace_graph_ent *call;unsigned long long duration;unsigned long ret_func; -unsigned long func;int args_size;int cpu = iter->cpu;int i;
@@ -933,8 +932,6 @@ print_graph_entry_leaf(struct trace_iterator *iter, call = &entry->graph_ent; duration = ret_entry->rettime - ret_entry->calltime; - func = call->func + iter->tr->text_delta; -if (data) {struct fgraph_cpu_data *cpu_data;
Signature · 1 line
2.47.2
Steven Rostedt
maintainerPATCH 2/3 tracing: Fix use-after-free in print_graph_function_flags during tracer switching
In reply to Steven RostedtFrom: Tengda Wu <[email protected]>
Kairui reported a UAF issue in print_graph_function_flags() during ftrace stress testing [1]. This issue can be reproduced if puting a 'mdelay(10)' after 'mutex_unlock(&trace_types_lock)' in s_start(), and executing the following script:
$ echo function_graph > current_tracer $ cat trace > /dev/null & $ sleep 5 # Ensure the 'cat' reaches the 'mdelay(10)' point $ echo timerlat > current_tracer
The root cause lies in the two calls to print_graph_function_flags within print_trace_line during each s_show():
* One through 'iter->trace->print_line()';
* Another through 'event->funcs->trace()', which is hidden in print_trace_fmt() before print_trace_line returns.
Tracer switching only updates the former, while the latter continues to use the print_line function of the old tracer, which in the script above is print_graph_function_flags.
Moreover, when switching from the 'function_graph' tracer to the 'timerlat' tracer, s_start only calls graph_trace_close of the 'function_graph' tracer to free 'iter->private', but does not set it to NULL. This provides an opportunity for 'event->funcs->trace()' to use an invalid 'iter->private'.
To fix this issue, set 'iter->private' to NULL immediately after freeing it in graph_trace_close(), ensuring that an invalid pointer is not passed to other tracers. Additionally, clean up the unnecessary 'iter->private = NULL' during each 'cat trace' when using wakeup and irqsoff tracers.
[1] https://lore.kernel.org/all/[email protected]/
--- kernel/trace/trace_functions_graph.c | 1 + kernel/trace/trace_irqsoff.c | 2 -- kernel/trace/trace_sched_wakeup.c | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-)
kernel/trace/trace_functions_graph.c +1 -0
@@ -1611,6 +1611,7 @@ void graph_trace_close(struct trace_iterator *iter)if (data) {free_percpu (data->cpu_data);kfree (data); + iter->private =NULL ; } }
kernel/trace/trace_irqsoff.c +0 -2
@@ -250,8 +250,6 @@ static void irqsoff_trace_open(struct trace_iterator *iter) {if (is_graph (iter->tr))graph_trace_open (iter); -else - iter->private =NULL ; }static void irqsoff_trace_close (struct trace_iterator *iter)
kernel/trace/trace_sched_wakeup.c +0 -2
@@ -188,8 +188,6 @@ static void wakeup_trace_open(struct trace_iterator *iter) {if (is_graph (iter->tr))graph_trace_open (iter); -else - iter->private =NULL ; }static void wakeup_trace_close (struct trace_iterator *iter)
Signature · 1 line
2.47.2
Steven Rostedt
maintainerPATCH 3/3 tracing: Use hashtable.h for event_hash
In reply to Steven RostedtFrom: Sasha Levin <[email protected]>
Convert the event_hash array in trace_output.c to use the generic hashtable implementation from hashtable.h instead of the manually implemented hash table.
This simplifies the code and makes it more maintainable by using the standard hashtable API defined in hashtable.h.
Rename EVENT_HASHSIZE to EVENT_HASH_BITS to properly reflect its new meaning as the number of bits for the hashtable size.
--- kernel/trace/trace_output.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-)
kernel/trace/trace_output.c +7 -12
@@ -14,16 +14,17 @@#include <linux/idr.h> #include <linux/btf.h> #include <linux/bpf.h> +#include <linux/hashtable.h> #include "trace_output.h" #include "trace_btf.h" -/* must be a power of 2 */ -#define EVENT_HASHSIZE 128 +/* 2^7 = 128 */ +#define EVENT_HASH_BITS 7DECLARE_RWSEM (trace_event_sem); -static struct hlist_head event_hash[EVENT_HASHSIZE ]__read_mostly ; +static DEFINE_HASHTABLE(event_hash, EVENT_HASH_BITS);enum print_line_t trace_print_bputs_msg_only (struct trace_iterator *iter) {
@@ -779,11 +780,8 @@ void print_function_args(struct trace_seq *s, unsigned long *args,struct trace_event *ftrace_find_event (int type) {struct trace_event *event; -unsigned key; - key = type & (EVENT_HASHSIZE -1 ); - -hlist_for_each_entry (event, &event_hash[key], node) { +hash_for_each_possible (event_hash, event, node, type) {if (event->type == type)return event; }
@@ -838,7 +836,6 @@ void trace_event_read_unlock(void)*/ int register_trace_event (struct trace_event *event) { -unsigned key;int ret =0 ;down_write (&trace_event_sem);
@@ -871,9 +868,7 @@ int register_trace_event(struct trace_event *event)if (event->funcs->binary ==NULL ) event->funcs->binary = trace_nop_print; - key = event->type & (EVENT_HASHSIZE -1 ); - -hlist_add_head (&event->node, &event_hash[key]); +hash_add (event_hash, &event->node, event->type); ret = event->type; out:
@@ -888,7 +883,7 @@ EXPORT_SYMBOL_GPL(register_trace_event);*/ int __unregister_trace_event (struct trace_event *event) { -hlist_del (&event->node); +hash_del (&event->node);free_trace_event_type (event->type);return 0 ; }
Signature · 1 line
2.47.2