History

ftrace: Fix function_graph tracer interaction with BPF trampoline

Depending on type of BPF programs served by BPF trampoline it can call original function. In such case the trampoline will skip one stack frame while returning. That will confuse function_graph tracer and will cause crashes with bad RIP. Teach graph tracer to skip functions that have BPF trampoline attached.

Alexei Starovoitov committed 6 years ago

Commit ff205761 parent a61f8104 files · +21 −26Browse files

Unified · Split

4 files
  1. arch/x86/kernel/ftrace.c +0 −14
  2. include/linux/ftrace.h +5 −0
  3. kernel/trace/fgraph.c +9 −0
  4. kernel/trace/ftrace.c +7 −12
arch/x86/kernel/ftrace.c+0−14
@@ -1042,20 +1042,6 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, · 1041 unmodified lines
10421042 if (unlikely(atomic_read(&current->tracing_graph_pause)))
10431043 return;
10441044
1045− /*
1046− * If the return location is actually pointing directly to
1047− * the start of a direct trampoline (if we trace the trampoline
1048− * it will still be offset by MCOUNT_INSN_SIZE), then the
1049− * return address is actually off by one word, and we
1050− * need to adjust for that.
1051− */
1052− if (ftrace_direct_func_count) {
1053− if (ftrace_find_direct_func(self_addr + MCOUNT_INSN_SIZE)) {
1054− self_addr = *parent;
1055− parent++;
1056− }
1057− }
1058−
10591045 /*
10601046 * Protect against fault, even if it shouldn't
10611047 * happen. This tool is too much intrusive to
include/linux/ftrace.h+5−0
@@ -264,6 +264,7 @@ int ftrace_modify_direct_caller(struct ftrace_func_entry *entry, · 263 unmodified lines
264264 struct dyn_ftrace *rec,
265265 unsigned long old_addr,
266266 unsigned long new_addr);
267+unsigned long ftrace_find_rec_direct(unsigned long ip);
267268 #else
268269 # define ftrace_direct_func_count 0
269270 static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)
@@ -290,6 +291,10 @@ static inline int ftrace_modify_direct_caller(struct ftrace_func_entry *entry, · 20 unmodified lines
290291 {
291292 return -ENODEV;
292293 }
294+static inline unsigned long ftrace_find_rec_direct(unsigned long ip)
295+{
296+ return 0;
297+}
293298 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
294299
295300 #ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
kernel/trace/fgraph.c+9−0
@@ -101,6 +101,15 @@ int function_graph_enter(unsigned long ret, unsigned long func, · 100 unmodified lines
101101 {
102102 struct ftrace_graph_ent trace;
103103
104+ /*
105+ * Skip graph tracing if the return location is served by direct trampoline,
106+ * since call sequence and return addresses is unpredicatable anymore.
107+ * Ex: BPF trampoline may call original function and may skip frame
108+ * depending on type of BPF programs attached.
109+ */
110+ if (ftrace_direct_func_count &&
111+ ftrace_find_rec_direct(ret - MCOUNT_INSN_SIZE))
112+ return -EBUSY;
104113 trace.func = func;
105114 trace.depth = ++current->curr_ret_depth;
106115
kernel/trace/ftrace.c+7−12
@@ -2364,7 +2364,7 @@ int ftrace_direct_func_count; · 2363 unmodified lines
23642364 * Search the direct_functions hash to see if the given instruction pointer
23652365 * has a direct caller attached to it.
23662366 */
2367−static unsigned long find_rec_direct(unsigned long ip)
2367+unsigned long ftrace_find_rec_direct(unsigned long ip)
23682368 {
23692369 struct ftrace_func_entry *entry;
23702370
@@ -2380,7 +2380,7 @@ static void call_direct_funcs(unsigned long ip, unsigned long pip, · 9 unmodified lines
23802380 {
23812381 unsigned long addr;
23822382
2383− addr = find_rec_direct(ip);
2383+ addr = ftrace_find_rec_direct(ip);
23842384 if (!addr)
23852385 return;
23862386
@@ -2393,11 +2393,6 @@ struct ftrace_ops direct_ops = { · 6 unmodified lines
23932393 | FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_REGS
23942394 | FTRACE_OPS_FL_PERMANENT,
23952395 };
2396−#else
2397−static inline unsigned long find_rec_direct(unsigned long ip)
2398−{
2399− return 0;
2400−}
24012396 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
24022397
24032398 /**
@@ -2417,7 +2412,7 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec) · 13 unmodified lines
24172412
24182413 if ((rec->flags & FTRACE_FL_DIRECT) &&
24192414 (ftrace_rec_count(rec) == 1)) {
2420− addr = find_rec_direct(rec->ip);
2415+ addr = ftrace_find_rec_direct(rec->ip);
24212416 if (addr)
24222417 return addr;
24232418 WARN_ON_ONCE(1);
@@ -2458,7 +2453,7 @@ unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec) · 34 unmodified lines
24582453
24592454 /* Direct calls take precedence over trampolines */
24602455 if (rec->flags & FTRACE_FL_DIRECT_EN) {
2461− addr = find_rec_direct(rec->ip);
2456+ addr = ftrace_find_rec_direct(rec->ip);
24622457 if (addr)
24632458 return addr;
24642459 WARN_ON_ONCE(1);
@@ -3604,7 +3599,7 @@ static int t_show(struct seq_file *m, void *v) · 1139 unmodified lines
36043599 if (rec->flags & FTRACE_FL_DIRECT) {
36053600 unsigned long direct;
36063601
3607− direct = find_rec_direct(rec->ip);
3602+ direct = ftrace_find_rec_direct(rec->ip);
36083603 if (direct)
36093604 seq_printf(m, "\n\tdirect-->%pS", (void *)direct);
36103605 }
@@ -5008,7 +5003,7 @@ int register_ftrace_direct(unsigned long ip, unsigned long addr) · 1397 unmodified lines
50085003 mutex_lock(&direct_mutex);
50095004
50105005 /* See if there's a direct function at @ip already */
5011− if (find_rec_direct(ip))
5006+ if (ftrace_find_rec_direct(ip))
50125007 goto out_unlock;
50135008
50145009 ret = -ENODEV;
@@ -5027,7 +5022,7 @@ int register_ftrace_direct(unsigned long ip, unsigned long addr) · 12 unmodified lines
50275022 if (ip != rec->ip) {
50285023 ip = rec->ip;
50295024 /* Need to check this ip for a direct. */
5030− if (find_rec_direct(ip))
5025+ if (ftrace_find_rec_direct(ip))
50315026 goto out_unlock;
50325027 }
50335028

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t