From 6bfbc5f5f543a399de8d478216ecfde471f9b4c7 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 22 Dec 2020 18:23:34 +0100 Subject: [PATCH] Kernel: Don't allow modifying IOPL via sys$ptrace() or sys$sigreturn() It was possible to overwrite the entire EFLAGS register since we didn't do any masking in the ptrace and sigreturn syscalls. This made it trivial to gain IO privileges by raising IOPL to 3 and then you could talk to hardware to do all kinds of nasty things. Thanks to @allesctf for finding these issues! :^) Their exploit/write-up: https://github.com/allesctf/writeups/blob/master/2020/hxpctf/wisdom2/writeup.md --- Kernel/Arch/i386/CPU.h | 2 ++ Kernel/Ptrace.cpp | 3 ++- Kernel/Syscall.cpp | 8 ++++++++ Kernel/Syscalls/sigaction.cpp | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index c4d736dc15..39168b3be7 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -43,6 +43,8 @@ class MemoryManager; class PageDirectory; class PageTableEntry; +static constexpr u32 safe_eflags_mask = 0xdff; + struct [[gnu::packed]] DescriptorTablePointer { u16 limit; diff --git a/Kernel/Ptrace.cpp b/Kernel/Ptrace.cpp index 97066bf86a..61b6028670 100644 --- a/Kernel/Ptrace.cpp +++ b/Kernel/Ptrace.cpp @@ -183,7 +183,8 @@ void copy_ptrace_registers_into_kernel_registers(RegisterState& kernel_regs, con kernel_regs.esi = ptrace_regs.esi; kernel_regs.edi = ptrace_regs.edi; kernel_regs.eip = ptrace_regs.eip; - kernel_regs.eflags = ptrace_regs.eflags; + + kernel_regs.eflags = (kernel_regs.eflags & ~safe_eflags_mask) | (ptrace_regs.eflags & safe_eflags_mask); } } diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 8e5cd2007b..20416753c2 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -161,6 +161,14 @@ void syscall_handler(TrapFrame* trap) asm volatile("" : "=m"(*ptr)); + static constexpr u32 iopl_mask = 3u << 12; + + if ((regs.eflags & (iopl_mask)) != 0) { + dbgln("Syscall from process with IOPL != 0"); + handle_crash(regs, "Non-zero IOPL on syscall entry", SIGSEGV); + ASSERT_NOT_REACHED(); + } + if (!MM.validate_user_stack(process, VirtualAddress(regs.userspace_esp))) { dbgln("Invalid stack pointer: {:p}", regs.userspace_esp); handle_crash(regs, "Bad stack on syscall entry", SIGSTKFLT); diff --git a/Kernel/Syscalls/sigaction.cpp b/Kernel/Syscalls/sigaction.cpp index a3151c6d1e..a3cfc9d1bf 100644 --- a/Kernel/Syscalls/sigaction.cpp +++ b/Kernel/Syscalls/sigaction.cpp @@ -109,7 +109,7 @@ int Process::sys$sigreturn(RegisterState& registers) registers.eip = *stack_ptr; stack_ptr++; - registers.eflags = *stack_ptr; + registers.eflags = (registers.eflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask); stack_ptr++; registers.userspace_esp = registers.esp;