stack_trace_save_user() only refuses to unwind the user stack of tasks
with PF_KTHREAD set. That doesn't cover all tasks without an mm:
- A user task that has already gone through exit_mm(), e.g. when an
event fires from exit_files(), exit_task_work() or the final context
switch in do_exit().
- PID 1 before it execs init, and usermode helper children before they
exec, which are created with user_mode_thread() and don't have
PF_KTHREAD set. E.g. booting with trace_options=userstacktrace and
an event enabled with trace_event= unwinds PID 1's "user stack"
during initcalls.
With the ftrace userstacktrace option enabled, the architecture
unwinders then read the user stack without an mm. That access does not
reliably fail: the user half of the address space belongs to whatever
mm happens to be lazily loaded, if any, so the unwinder may read
another task's memory.
Use is_user_task() instead, which also checks current->mm, as perf
already does for the same reason since commit 76ed27608f7d ("perf:
sched: Fix perf crash with new is_user_task() helper"). This also stops
unwinding the user stack of PF_USER_WORKER threads, which never run in
user space, matching perf.
Fixes: 214d8ca6ee85 ("stacktrace: Provide common infrastructure")
Signed-off-by: James Houghton <[email protected]>
---
kernel/stacktrace.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/kernel/stacktrace.c b/kernel/stacktrace.c
index afb3c116da91..f96a5ec12f6c 100644
--- a/kernel/stacktrace.c
+++ b/kernel/stacktrace.c
@@ -228,8 +228,12 @@ unsigned int stack_trace_save_user(unsigned long *store,
unsigned int size)
.size = size,
};
- /* Trace user stack if not a kernel thread */
- if (current->flags & PF_KTHREAD)
+ /*
+ * Trace user stack only if this is a user task that still has an mm,
+ * i.e. not a kernel thread or user worker, and not a task that has
+ * already gone through exit_mm().
+ */
+ if (!is_user_task(current))
return 0;
arch_stack_walk_user(consume_entry, &c, task_pt_regs(current));
--
2.56.0.307.g5fe7bd680c-goog