Kernel: Disallow syscalls from writeable memory
Processes will now crash with SIGSEGV if they attempt making a syscall from PROT_WRITE memory. This neat idea comes from OpenBSD. :^)
This commit is contained in:
parent
ea52fe528a
commit
e56daf547c
Notes:
sideshowbarker
2024-07-19 11:02:00 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e56daf547c1
5 changed files with 27 additions and 5 deletions
|
@ -27,6 +27,7 @@ kinds of crashes.
|
||||||
* `-r`: Write to read-only memory.
|
* `-r`: Write to read-only memory.
|
||||||
* `-T`: Make a syscall while using an invalid stack pointer.
|
* `-T`: Make a syscall while using an invalid stack pointer.
|
||||||
* `-t`: Trigger a page fault while using an invalid stack pointer.
|
* `-t`: Trigger a page fault while using an invalid stack pointer.
|
||||||
|
* `-S`: Make a syscall from writeable memory.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,19 @@ void syscall_trap_entry(RegisterDump regs)
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* calling_region = MM.region_from_vaddr(process, VirtualAddress(regs.eip));
|
||||||
|
if (!calling_region) {
|
||||||
|
dbgprintf("Syscall from %p which has no region\n", regs.eip);
|
||||||
|
handle_crash(regs, "Syscall from unknown region", SIGSEGV);
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calling_region->is_writable()) {
|
||||||
|
dbgprintf("Syscall from writable memory at %p\n", regs.eip);
|
||||||
|
handle_crash(regs, "Syscall from writable memory", SIGSEGV);
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
process.big_lock().lock();
|
process.big_lock().lock();
|
||||||
u32 function = regs.eax;
|
u32 function = regs.eax;
|
||||||
u32 arg1 = regs.edx;
|
u32 arg1 = regs.edx;
|
||||||
|
|
|
@ -289,7 +289,6 @@ Region* MemoryManager::user_region_from_vaddr(Process& process, VirtualAddress v
|
||||||
|
|
||||||
Region* MemoryManager::region_from_vaddr(Process& process, VirtualAddress vaddr)
|
Region* MemoryManager::region_from_vaddr(Process& process, VirtualAddress vaddr)
|
||||||
{
|
{
|
||||||
ASSERT_INTERRUPTS_DISABLED();
|
|
||||||
if (auto* region = kernel_region_from_vaddr(vaddr))
|
if (auto* region = kernel_region_from_vaddr(vaddr))
|
||||||
return region;
|
return region;
|
||||||
return user_region_from_vaddr(process, vaddr);
|
return user_region_from_vaddr(process, vaddr);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/String.h>
|
|
||||||
#include <AK/Badge.h>
|
#include <AK/Badge.h>
|
||||||
#include <AK/Bitmap.h>
|
#include <AK/Bitmap.h>
|
||||||
#include <AK/ByteBuffer.h>
|
#include <AK/ByteBuffer.h>
|
||||||
|
@ -8,6 +7,7 @@
|
||||||
#include <AK/NonnullRefPtrVector.h>
|
#include <AK/NonnullRefPtrVector.h>
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
|
#include <AK/String.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <AK/Weakable.h>
|
#include <AK/Weakable.h>
|
||||||
|
@ -79,6 +79,9 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Region* region_from_vaddr(Process&, VirtualAddress);
|
||||||
|
static const Region* region_from_vaddr(const Process&, VirtualAddress);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryManager(u32 physical_address_for_kernel_page_tables);
|
MemoryManager(u32 physical_address_for_kernel_page_tables);
|
||||||
~MemoryManager();
|
~MemoryManager();
|
||||||
|
@ -96,9 +99,6 @@ private:
|
||||||
|
|
||||||
void create_identity_mapping(PageDirectory&, VirtualAddress, size_t length);
|
void create_identity_mapping(PageDirectory&, VirtualAddress, size_t length);
|
||||||
|
|
||||||
static Region* region_from_vaddr(Process&, VirtualAddress);
|
|
||||||
static const Region* region_from_vaddr(const Process&, VirtualAddress);
|
|
||||||
|
|
||||||
static Region* user_region_from_vaddr(Process&, VirtualAddress);
|
static Region* user_region_from_vaddr(Process&, VirtualAddress);
|
||||||
static Region* kernel_region_from_vaddr(VirtualAddress);
|
static Region* kernel_region_from_vaddr(VirtualAddress);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
#include <Kernel/Syscall.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
@ -24,6 +25,7 @@ int main(int argc, char** argv)
|
||||||
WriteToReadonlyMemory,
|
WriteToReadonlyMemory,
|
||||||
InvalidStackPointerOnSyscall,
|
InvalidStackPointerOnSyscall,
|
||||||
InvalidStackPointerOnPageFault,
|
InvalidStackPointerOnPageFault,
|
||||||
|
SyscallFromWritableMemory,
|
||||||
};
|
};
|
||||||
Mode mode = SegmentationViolation;
|
Mode mode = SegmentationViolation;
|
||||||
|
|
||||||
|
@ -52,6 +54,8 @@ int main(int argc, char** argv)
|
||||||
mode = InvalidStackPointerOnSyscall;
|
mode = InvalidStackPointerOnSyscall;
|
||||||
else if (String(argv[1]) == "-t")
|
else if (String(argv[1]) == "-t")
|
||||||
mode = InvalidStackPointerOnPageFault;
|
mode = InvalidStackPointerOnPageFault;
|
||||||
|
else if (String(argv[1]) == "-S")
|
||||||
|
mode = SyscallFromWritableMemory;
|
||||||
else
|
else
|
||||||
print_usage_and_exit();
|
print_usage_and_exit();
|
||||||
|
|
||||||
|
@ -152,6 +156,11 @@ int main(int argc, char** argv)
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode == SyscallFromWritableMemory) {
|
||||||
|
u8 buffer[] = { 0xb8, Syscall::SC_getuid, 0, 0, 0, 0xcd, 0x82 };
|
||||||
|
((void(*)())buffer)();
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue