For example, doing this with the stack pointer set to an unaligned address will cause a KUBSAN crash:
[#0 testtwo(33:33)]: KUBSAN: load of misaligned address 0x017f0fea of type 'u32'
[#0 testtwo(33:33)]: KUBSAN: at ../../Kernel/Syscalls/sigaction.cpp, line 91, column: 24
[#0 testtwo(33:33)]: Kernel + 0x00609b07 print_location +0x1ed
[#0 testtwo(33:33)]: Kernel + 0x0060ba58 __ubsan_handle_type_mismatch_v1 +0x4f1
[#0 testtwo(33:33)]: Kernel + 0x0056e3d5 Kernel::Process::sys$sigreturn(Kernel::RegisterState&) +0x3d5
[#0 testtwo(33:33)]: Kernel + 0x004bf37d syscall_handler +0x153a
[#0 testtwo(33:33)]: Kernel + 0x004bd807 syscall_asm_entry +0x31
[#0 testtwo(33:33)]: UB is configured to be deadly, halting the system.
However, if you use an aligned stack pointer and it's just above the bottom of the stack (e.g. 4 bytes above), it will cause a segfault as it hits the guard page placed after the stack:
[#0 testtwo(33:33)]: Unrecoverable page fault, read from address V0x00a01000
[testtwo(33:33)]: CRASH: CPU #0 Page Fault in ring 0
[#0 testtwo(33:33)]: Exception code: 0000 (isr: 0000)
[#0 testtwo(33:33)]: pc=0x0008:0xc076e428 eflags=0x00050246
[#0 testtwo(33:33)]: stack=0x0010:0xc6e73cd4
[#0 testtwo(33:33)]: ds=0x0010 es=0x0010 fs=0x0023 gs=0x0030
[#0 testtwo(33:33)]: eax=0x00a00fec ebx=0xc10bc498 ecx=0x00000000 edx=0x00000000
[#0 testtwo(33:33)]: ebp=0xc6e73d6c esp=0xc6e73cd4 esi=0x00a01000 edi=0xc241f094
[#0 testtwo(33:33)]: cr0=0x80010013 cr2=0x00a01000 cr3=0x0a565000 cr4=0x00340ee4
[testtwo(33:33)]: KERNEL PANIC! :^(
[testtwo(33:33)]: Crash in ring 0
[testtwo(33:33)]: at ../../Kernel/Arch/x86/common/Interrupts.cpp:230 in void Kernel::handle_crash(const Kernel::RegisterState&, const char*, int, bool)
[testtwo(33:33)]: Kernel + 0x00468c1c Kernel::__panic(char const*, unsigned int, char const*) +0xb1
[testtwo(33:33)]: Kernel + 0x00620f99 Kernel::handle_crash(Kernel::RegisterState const&, char const*, int, bool) [clone .localalias] +0x23f
[testtwo(33:33)]: Kernel + 0x00621c63 page_fault_handler +0xb2a
[testtwo(33:33)]: Kernel + 0x0061ec08 page_fault_asm_entry +0x26
[testtwo(33:33)]: Kernel + 0x004bf37d syscall_handler +0x153a
[testtwo(33:33)]: Kernel + 0x004bd807 syscall_asm_entry +0x31
I don't think this can be used as an exploit. This is because you can only go over the stack by 60 bytes as the stack pointer must be in a stack region on syscall entry. This is assuming i386: sigreturn reads 64 bytes, the stack pointer must be 4 bytes above the bottom of the stack to make it aligned. This 60 bytes will always be in the guard page and is only read from.
Additionally, since this needs to be invoked via LibSystem, you cannot set esp
before calling syscall
from LibSystem as it will crash on the function call. Thus, a custom syscall API is required to set esp
right before the syscall.
Finally, while the contents of the stack are userspace controlled, the contents will only be used to mess up the state of the calling process.
This is the code I used to cause the crash: sigreturncrashpatch.txt. Run testtwo
to cause the crash.
This came from experimenting with this static analysis report: https://sonarcloud.io/project/issues?id=SerenityOS_serenity&issues=AXuVPA29k92xXUF3qVpJ&open=AXuVPA29k92xXUF3qVpJ
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too