BadIRET: a Linux kernel privilege escalation rooted in a CPU instruction quirk
BadIRET 漏洞利用分析
BadIRET, tracked as CVE-2014-9322, was a local privilege escalation flaw in the 64-bit Linux kernel's exception handling, fixed in late 2014 and affecting essentially every actively maintained distribution at the time. It is a Linux kernel issue, not a Windows one; some online summaries list it under the wrong vendor.
Where the bug lived
When the CPU returns from kernel mode to user mode via the iret instruction, it can raise an exception if the segment state it is restoring is invalid. The kernel's handler for the general-protection case correctly treated this as equivalent to a fault happening in user space and ran a CPU instruction to switch the privileged per-CPU data pointer back to its user-mode value before continuing. The handler for a closely related case, a missing stack segment, skipped that switch. The two paths were meant to behave identically, but only one of them undid the earlier privileged state. A local process could deliberately engineer the stack-segment case using a now-invalidated custom segment descriptor, causing the kernel to continue running with its internal per-CPU pointer left in the wrong state.
Why that pointer matters
The kernel relies on that per-CPU pointer, normally swapped to a known-safe value on every mode transition, to find real kernel data structures through a fixed offset. With the swap skipped, the pointer could be made to reference memory the local process had already set up, so when subsequent kernel code read what it believed was its own internal state at that fixed offset, it was instead reading attacker-controlled memory.
From read confusion to a write primitive
The research behind this flaw's public write-up showed that a read-confusion bug like this can be escalated step by step: the first kernel code path reachable this way only wrote a couple of fixed, uncontrollable values to an address the attacker could choose. That alone wasn't enough, but it was enough to redirect control into a second code path, further down the same error-handling chain, that performed a similarly placed write using attacker-influenced kernel state. Chained together, carefully prepared fake kernel data structures in user space let a local process eventually gain arbitrary code execution at kernel privilege, defeating contemporary mitigations such as SMEP, though a correctly configured SMAP still blocked the final step.
Why it matters
BadIRET illustrates how two exception-handling paths that are supposed to be equivalent, but diverge in one easily overlooked instruction, can turn a CPU-level quirk into a full privilege escalation. It is also a concrete example of why hardware mitigations introduced after a given kernel version, SMAP in this case, close off exploitation paths that would otherwise work against older or misconfigured systems.
Key takeaways
- CVE-2014-9322 is a Linux kernel bug, affecting the 64-bit iret exception-handling path, not a Windows vulnerability
- Two exception handlers meant to behave identically diverged in one instruction, leaving a privileged pointer in the wrong state
- A read-confusion bug with no directly controllable write can still be escalated by chaining it into further vulnerable code paths
- SMEP alone did not stop exploitation, but SMAP did, showing why layered hardware mitigations matter
- Exception and fault handlers that are supposed to be equivalent deserve the same scrutiny as the common-case code paths
This note has been rewritten and checked for this edition; it is not a copy of the original post.