Commit a069a22f authored by Masami Hiramatsu (Google)'s avatar Masami Hiramatsu (Google) Committed by Steven Rostedt (Google)

tracing: fgraph: Fix to add new fgraph_ops to array after ftrace_startup_subops()

Since the register_ftrace_graph() assigns a new fgraph_ops to
fgraph_array before registring it by ftrace_startup_subops(), the new
fgraph_ops can be used in function_graph_enter().

In most cases, it is still OK because those fgraph_ops's hashtable is
already initialized by ftrace_set_filter*() etc.

But if a user registers a new fgraph_ops which does not initialize the
hash list, ftrace_ops_test() in function_graph_enter() causes a NULL
pointer dereference BUG because fgraph_ops->ops.func_hash is NULL.

This can be reproduced by the below commands because function profiler's
fgraph_ops does not initialize the hash list;

 # cd /sys/kernel/tracing
 # echo function_graph > current_tracer
 # echo 1 > function_profile_enabled

To fix this problem, add a new fgraph_ops to fgraph_array after
ftrace_startup_subops(). Thus, until the new fgraph_ops is initialized,
we will see fgraph_stub on the corresponding fgraph_array entry.

Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Cc: Florent Revest <revest@chromium.org>
Cc: Martin KaFai Lau <martin.lau@linux.dev>
Cc: bpf <bpf@vger.kernel.org>
Cc: Sven Schnelle <svens@linux.ibm.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Alan Maguire <alan.maguire@oracle.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Guo Ren <guoren@kernel.org>
Link: https://lore.kernel.org/172398528350.293426.8347220120333730248.stgit@devnote2
Fixes: c132be2c ("function_graph: Have the instances use their own ftrace_ops for filtering")
Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 47ac09b9
...@@ -1206,18 +1206,24 @@ static void init_task_vars(int idx) ...@@ -1206,18 +1206,24 @@ static void init_task_vars(int idx)
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
} }
static void ftrace_graph_enable_direct(bool enable_branch) static void ftrace_graph_enable_direct(bool enable_branch, struct fgraph_ops *gops)
{ {
trace_func_graph_ent_t func = NULL; trace_func_graph_ent_t func = NULL;
trace_func_graph_ret_t retfunc = NULL; trace_func_graph_ret_t retfunc = NULL;
int i; int i;
if (gops) {
func = gops->entryfunc;
retfunc = gops->retfunc;
fgraph_direct_gops = gops;
} else {
for_each_set_bit(i, &fgraph_array_bitmask, for_each_set_bit(i, &fgraph_array_bitmask,
sizeof(fgraph_array_bitmask) * BITS_PER_BYTE) { sizeof(fgraph_array_bitmask) * BITS_PER_BYTE) {
func = fgraph_array[i]->entryfunc; func = fgraph_array[i]->entryfunc;
retfunc = fgraph_array[i]->retfunc; retfunc = fgraph_array[i]->retfunc;
fgraph_direct_gops = fgraph_array[i]; fgraph_direct_gops = fgraph_array[i];
} }
}
if (WARN_ON_ONCE(!func)) if (WARN_ON_ONCE(!func))
return; return;
...@@ -1256,8 +1262,6 @@ int register_ftrace_graph(struct fgraph_ops *gops) ...@@ -1256,8 +1262,6 @@ int register_ftrace_graph(struct fgraph_ops *gops)
ret = -ENOSPC; ret = -ENOSPC;
goto out; goto out;
} }
fgraph_array[i] = gops;
gops->idx = i; gops->idx = i;
ftrace_graph_active++; ftrace_graph_active++;
...@@ -1266,7 +1270,7 @@ int register_ftrace_graph(struct fgraph_ops *gops) ...@@ -1266,7 +1270,7 @@ int register_ftrace_graph(struct fgraph_ops *gops)
ftrace_graph_disable_direct(true); ftrace_graph_disable_direct(true);
if (ftrace_graph_active == 1) { if (ftrace_graph_active == 1) {
ftrace_graph_enable_direct(false); ftrace_graph_enable_direct(false, gops);
register_pm_notifier(&ftrace_suspend_notifier); register_pm_notifier(&ftrace_suspend_notifier);
ret = start_graph_tracing(); ret = start_graph_tracing();
if (ret) if (ret)
...@@ -1281,14 +1285,15 @@ int register_ftrace_graph(struct fgraph_ops *gops) ...@@ -1281,14 +1285,15 @@ int register_ftrace_graph(struct fgraph_ops *gops)
} else { } else {
init_task_vars(gops->idx); init_task_vars(gops->idx);
} }
/* Always save the function, and reset at unregistering */ /* Always save the function, and reset at unregistering */
gops->saved_func = gops->entryfunc; gops->saved_func = gops->entryfunc;
ret = ftrace_startup_subops(&graph_ops, &gops->ops, command); ret = ftrace_startup_subops(&graph_ops, &gops->ops, command);
if (!ret)
fgraph_array[i] = gops;
error: error:
if (ret) { if (ret) {
fgraph_array[i] = &fgraph_stub;
ftrace_graph_active--; ftrace_graph_active--;
gops->saved_func = NULL; gops->saved_func = NULL;
fgraph_lru_release_index(i); fgraph_lru_release_index(i);
...@@ -1324,7 +1329,7 @@ void unregister_ftrace_graph(struct fgraph_ops *gops) ...@@ -1324,7 +1329,7 @@ void unregister_ftrace_graph(struct fgraph_ops *gops)
ftrace_shutdown_subops(&graph_ops, &gops->ops, command); ftrace_shutdown_subops(&graph_ops, &gops->ops, command);
if (ftrace_graph_active == 1) if (ftrace_graph_active == 1)
ftrace_graph_enable_direct(true); ftrace_graph_enable_direct(true, NULL);
else if (!ftrace_graph_active) else if (!ftrace_graph_active)
ftrace_graph_disable_direct(false); ftrace_graph_disable_direct(false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment