The user stack trace can fault when examining the trace. Which would call the do_page_fault handler, which would trace again, which would do the user stack trace, which would fault and call do_page_fault again ... Thus this is causing a recursive bug. We need to have a recursion detector here. [ Resubmitted by Jiri Olsa ] [ Eric Dumazet recommended using __this_cpu_* instead of __get_cpu_* ]
Showing the changes to kernel/trace (1 of 1 file). Show all
Unified · Split
| @@ -1284,6 +1284,8 @@ void trace_dump_stack(void) · 1283 unmodified lines | ||
| 1284 | 1284 | __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count()); |
| 1285 | 1285 | } |
| 1286 | 1286 | |
| 1287 | +static DEFINE_PER_CPU(int, user_stack_count); | |
| 1288 | + | |
| 1287 | 1289 | void |
| 1288 | 1290 | ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) |
| 1289 | 1291 | { |
| @@ -1302,6 +1304,18 @@ ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) · 12 unmodified lines | ||
| 1302 | 1304 | if (unlikely(in_nmi())) |
| 1303 | 1305 | return; |
| 1304 | 1306 | |
| 1307 | + /* | |
| 1308 | + * prevent recursion, since the user stack tracing may | |
| 1309 | + * trigger other kernel events. | |
| 1310 | + */ | |
| 1311 | + preempt_disable(); | |
| 1312 | + if (__this_cpu_read(user_stack_count)) | |
| 1313 | + goto out; | |
| 1314 | + | |
| 1315 | + __this_cpu_inc(user_stack_count); | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1305 | 1319 | event = trace_buffer_lock_reserve(buffer, TRACE_USER_STACK, |
| 1306 | 1320 | sizeof(*entry), flags, pc); |
| 1307 | 1321 | if (!event) |
| @@ -1319,6 +1333,11 @@ ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc) · 11 unmodified lines | ||
| 1319 | 1333 | save_stack_trace_user(&trace); |
| 1320 | 1334 | if (!filter_check_discard(call, entry, buffer, event)) |
| 1321 | 1335 | ring_buffer_unlock_commit(buffer, event); |
| 1336 | + | |
| 1337 | + __this_cpu_dec(user_stack_count); | |
| 1338 | + | |
| 1339 | + out: | |
| 1340 | + preempt_enable(); | |
| 1322 | 1341 | } |
| 1323 | 1342 | |
| 1324 | 1343 | #ifdef UNUSED |