aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2016-12-08 20:54:49 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-09 02:32:23 -0500
commit239b40eb6189e49610e1e614c3670f92d74b9c7b (patch)
treebf6c10bcd87c556df9bfae1bfe9f759184357c3f
parenta035dc674dd477e61e5b917c60c30622b6d083f8 (diff)
fgraph: Handle a case where a tracer ignores set_graph_notrace
commit 794de08a16cf1fc1bf785dc48f66d36218cf6d88 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 <namhyung.kim@lge.com> Fixes: 29ad23b00474 ("ftrace: Add set_graph_notrace filter") Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/trace/trace_functions_graph.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 4e480e870474..a17cb1d8415c 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -842,6 +842,10 @@ print_graph_entry_leaf(struct trace_iterator *iter,
842 842
843 cpu_data = per_cpu_ptr(data->cpu_data, cpu); 843 cpu_data = per_cpu_ptr(data->cpu_data, cpu);
844 844
845 /* If a graph tracer ignored set_graph_notrace */
846 if (call->depth < -1)
847 call->depth += FTRACE_NOTRACE_DEPTH;
848
845 /* 849 /*
846 * Comments display at + 1 to depth. Since 850 * Comments display at + 1 to depth. Since
847 * this is a leaf function, keep the comments 851 * this is a leaf function, keep the comments
@@ -850,7 +854,8 @@ print_graph_entry_leaf(struct trace_iterator *iter,
850 cpu_data->depth = call->depth - 1; 854 cpu_data->depth = call->depth - 1;
851 855
852 /* No need to keep this function around for this depth */ 856 /* No need to keep this function around for this depth */
853 if (call->depth < FTRACE_RETFUNC_DEPTH) 857 if (call->depth < FTRACE_RETFUNC_DEPTH &&
858 !WARN_ON_ONCE(call->depth < 0))
854 cpu_data->enter_funcs[call->depth] = 0; 859 cpu_data->enter_funcs[call->depth] = 0;
855 } 860 }
856 861
@@ -880,11 +885,16 @@ print_graph_entry_nested(struct trace_iterator *iter,
880 struct fgraph_cpu_data *cpu_data; 885 struct fgraph_cpu_data *cpu_data;
881 int cpu = iter->cpu; 886 int cpu = iter->cpu;
882 887
888 /* If a graph tracer ignored set_graph_notrace */
889 if (call->depth < -1)
890 call->depth += FTRACE_NOTRACE_DEPTH;
891
883 cpu_data = per_cpu_ptr(data->cpu_data, cpu); 892 cpu_data = per_cpu_ptr(data->cpu_data, cpu);
884 cpu_data->depth = call->depth; 893 cpu_data->depth = call->depth;
885 894
886 /* Save this function pointer to see if the exit matches */ 895 /* Save this function pointer to see if the exit matches */
887 if (call->depth < FTRACE_RETFUNC_DEPTH) 896 if (call->depth < FTRACE_RETFUNC_DEPTH &&
897 !WARN_ON_ONCE(call->depth < 0))
888 cpu_data->enter_funcs[call->depth] = call->func; 898 cpu_data->enter_funcs[call->depth] = call->func;
889 } 899 }
890 900
@@ -1114,7 +1124,8 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
1114 */ 1124 */
1115 cpu_data->depth = trace->depth - 1; 1125 cpu_data->depth = trace->depth - 1;
1116 1126
1117 if (trace->depth < FTRACE_RETFUNC_DEPTH) { 1127 if (trace->depth < FTRACE_RETFUNC_DEPTH &&
1128 !WARN_ON_ONCE(trace->depth < 0)) {
1118 if (cpu_data->enter_funcs[trace->depth] != trace->func) 1129 if (cpu_data->enter_funcs[trace->depth] != trace->func)
1119 func_match = 0; 1130 func_match = 0;
1120 cpu_data->enter_funcs[trace->depth] = 0; 1131 cpu_data->enter_funcs[trace->depth] = 0;