From c25cf5fb5680389dadadd98fae19bcd7d96386ca Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 23 Dec 2020 14:18:13 +0100 Subject: [PATCH] Kernel: Panic if we're about to switch to a user thread with IOPL!=0 This is a crude protection against IOPL elevation attacks. If for any reason we find ourselves about to switch to a user mode thread with IOPL != 0, we'll now simply panic the kernel. If this happens, it basically means that something tricked the kernel into incorrectly modifying the IOPL of a thread, so it's no longer safe to trust the kernel anyway. --- Kernel/Arch/i386/CPU.h | 6 ++++++ Kernel/Scheduler.cpp | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/Kernel/Arch/i386/CPU.h b/Kernel/Arch/i386/CPU.h index 39168b3be7..c5883caa51 100644 --- a/Kernel/Arch/i386/CPU.h +++ b/Kernel/Arch/i386/CPU.h @@ -44,6 +44,12 @@ class PageDirectory; class PageTableEntry; static constexpr u32 safe_eflags_mask = 0xdff; +static constexpr u32 iopl_mask = 3u << 12; + +inline u32 get_iopl_from_eflags(u32 eflags) +{ + return (eflags & iopl_mask) >> 12; +} struct [[gnu::packed]] DescriptorTablePointer { diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 7283630f97..e5b0aa8adc 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -356,6 +356,14 @@ bool Scheduler::context_switch(Thread* thread) enter_current(*from_thread, false); ASSERT(thread == Thread::current()); +#if ARCH(I386) + auto iopl = get_iopl_from_eflags(Thread::current()->get_register_dump_from_stack().eflags); + if (thread->process().is_user_process() && iopl != 0) { + dbgln("PANIC: Switched to thread {} with non-zero IOPL={}", Thread::current()->tid().value(), iopl); + Processor::halt(); + } +#endif + return true; }