Skip to content
This repository has been archived by the owner on Dec 14, 2022. It is now read-only.

Commit

Permalink
fgraph: Handle a case where a tracer ignores set_graph_notrace
Browse files Browse the repository at this point in the history
commit 794de08 upstream.

Both the wakeup and irqsoff tracers can use the function graph tracer when
the display-graph option is set. The problem is that they ignore the notrace
file, and record the entry of functions that would be ignored by the
function_graph tracer. This causes the trace->depth to be recorded into the
ring buffer. The set_graph_notrace uses a trick by adding a large negative
number to the trace->depth when a graph function is to be ignored.

On trace output, the graph function uses the depth to record a stack of
functions. But since the depth is negative, it accesses the array with a
negative number and causes an out of bounds access that can cause a kernel
oops or corrupt data.

Have the print functions handle cases where a tracer still records functions
even when they are in set_graph_notrace.

Also add warnings if the depth is below zero before accessing the array.

Note, the function graph logic will still prevent the return of these
functions from being recorded, which means that they will be left hanging
without a return. For example:

   # echo '*spin*' > set_graph_notrace
   # echo 1 > options/display-graph
   # echo wakeup > current_tracer
   # cat trace
   [...]
      _raw_spin_lock() {
        preempt_count_add() {
        do_raw_spin_lock() {
      update_rq_clock();

Where it should look like:

      _raw_spin_lock() {
        preempt_count_add();
        do_raw_spin_lock();
      }
      update_rq_clock();

Cc: Namhyung Kim <[email protected]>
Fixes: 29ad23b ("ftrace: Add set_graph_notrace filter")
Signed-off-by: Steven Rostedt <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
rostedt authored and gregkh committed Jan 9, 2017
1 parent a035dc6 commit 239b40e
Showing 1 changed file with 14 additions and 3 deletions.
17 changes: 14 additions & 3 deletions kernel/trace/trace_functions_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,10 @@ print_graph_entry_leaf(struct trace_iterator *iter,

cpu_data = per_cpu_ptr(data->cpu_data, cpu);

/* If a graph tracer ignored set_graph_notrace */
if (call->depth < -1)
call->depth += FTRACE_NOTRACE_DEPTH;

/*
* Comments display at + 1 to depth. Since
* this is a leaf function, keep the comments
Expand All @@ -850,7 +854,8 @@ print_graph_entry_leaf(struct trace_iterator *iter,
cpu_data->depth = call->depth - 1;

/* No need to keep this function around for this depth */
if (call->depth < FTRACE_RETFUNC_DEPTH)
if (call->depth < FTRACE_RETFUNC_DEPTH &&
!WARN_ON_ONCE(call->depth < 0))
cpu_data->enter_funcs[call->depth] = 0;
}

Expand Down Expand Up @@ -880,11 +885,16 @@ print_graph_entry_nested(struct trace_iterator *iter,
struct fgraph_cpu_data *cpu_data;
int cpu = iter->cpu;

/* If a graph tracer ignored set_graph_notrace */
if (call->depth < -1)
call->depth += FTRACE_NOTRACE_DEPTH;

cpu_data = per_cpu_ptr(data->cpu_data, cpu);
cpu_data->depth = call->depth;

/* Save this function pointer to see if the exit matches */
if (call->depth < FTRACE_RETFUNC_DEPTH)
if (call->depth < FTRACE_RETFUNC_DEPTH &&
!WARN_ON_ONCE(call->depth < 0))
cpu_data->enter_funcs[call->depth] = call->func;
}

Expand Down Expand Up @@ -1114,7 +1124,8 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
*/
cpu_data->depth = trace->depth - 1;

if (trace->depth < FTRACE_RETFUNC_DEPTH) {
if (trace->depth < FTRACE_RETFUNC_DEPTH &&
!WARN_ON_ONCE(trace->depth < 0)) {
if (cpu_data->enter_funcs[trace->depth] != trace->func)
func_match = 0;
cpu_data->enter_funcs[trace->depth] = 0;
Expand Down

0 comments on commit 239b40e

Please sign in to comment.