summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-12-19 18:16:15 +0100
committerAndreas Kling <kling@serenityos.org>2021-12-19 18:18:38 +0100
commite0521cfb9d2d82bc2f99f39c132db4a0a082ac55 (patch)
treeaa9088aeb9161ee9883d4e6122faf86ff7b8065f /Kernel
parentbc518e39bf7e64dd0edf5ca7b82b4d089ade532a (diff)
downloadserenity-e0521cfb9d2d82bc2f99f39c132db4a0a082ac55.zip
Kernel: Stop ProcFS stack walk on bogus userspace->kernel traversal
Unsurprisingly, the /proc/PID/stacks/TID stack walk had the same arbitrary memory read problem as the perf event stack walk. It would be nice if the kernel had a single stack walk implementation, but that's outside the scope of this commit.
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/Arch/x86/common/Processor.cpp10
1 files changed, 10 insertions, 0 deletions
diff --git a/Kernel/Arch/x86/common/Processor.cpp b/Kernel/Arch/x86/common/Processor.cpp
index c0ca3f2145..d1a3576b7c 100644
--- a/Kernel/Arch/x86/common/Processor.cpp
+++ b/Kernel/Arch/x86/common/Processor.cpp
@@ -471,6 +471,7 @@ Vector<FlatPtr> Processor::capture_stack_trace(Thread& thread, size_t max_frames
auto walk_stack = [&](FlatPtr stack_ptr) {
static constexpr size_t max_stack_frames = 4096;
+ bool is_walking_userspace_stack = false;
stack_trace.append(ip);
size_t count = 1;
while (stack_ptr && stack_trace.size() < max_stack_frames) {
@@ -480,6 +481,15 @@ Vector<FlatPtr> Processor::capture_stack_trace(Thread& thread, size_t max_frames
if (max_frames != 0 && count > max_frames)
break;
+ if (!Memory::is_user_address(VirtualAddress { stack_ptr })) {
+ if (is_walking_userspace_stack) {
+ dbgln("SHENANIGANS! Userspace stack points back into kernel memory");
+ break;
+ }
+ } else {
+ is_walking_userspace_stack = true;
+ }
+
if (Memory::is_user_range(VirtualAddress(stack_ptr), sizeof(FlatPtr) * 2)) {
if (copy_from_user(&retaddr, &((FlatPtr*)stack_ptr)[1]).is_error() || !retaddr)
break;