Skip to content

Commit

Permalink
fgraph: Handle a case where a tracer ignores set_graph_notrace
Browse files Browse the repository at this point in the history
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: stable@vger.kernel.org
Cc: Namhyung Kim <namhyung.kim@lge.com>
Fixes: 29ad23b ("ftrace: Add set_graph_notrace filter")
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (Red Hat) committed Dec 9, 2016
1 parent 656c7f0 commit 794de08
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 794de08

Please sign in to comment.