SMEP / SMAP
TL;DR: SMEP forbids the kernel from executing user-mapped pages; SMAP forbids it from reading/writing them. Together they block the classic “ret to user-mode shellcode” kernel exploitation pattern.
What it is
Two CPU features in CR4 that prevent supervisor (ring 0) code from touching user pages in unsafe ways.
- SMEP (Supervisor Mode Execution Prevention) — CR4.SMEP=1. If the kernel attempts to execute an instruction fetched from a page whose PTE has the User bit set, the CPU raises a page fault. Defeats:
retinto user-mode shellcode from a kernel ROP chain. - SMAP (Supervisor Mode Access Prevention) — CR4.SMAP=1. Reads/writes from kernel to user pages fault unless the kernel has explicitly enabled access via
stac(set RFLAGS.AC). Defeats: kernel chains that dereference user pointers for data steps.
Both are enforced by hardware; bypass requires either flipping the CR4 bit or routing the exploit so it never touches user pages.
Preconditions / where it applies
- x86_64 CPU (Ivy Bridge+ for SMEP, Broadwell+ for SMAP) with the kernel enabling them at boot.
- Kernel-mode primitive (overflow, UAF, type confusion) that you intend to escalate to ring-0 code execution.
- The mitigation matters across Linux, Windows, and macOS — same hardware mechanism, similar bypass approaches.
Technique
Bypass approaches:
- Stay in kernel space. Build a full kernel ROP chain (rop-chains) using
ntoskrnl/hal.dllgadgets; never deref user memory. Combine with the data-only escalation in arbitrary-read-write-primitives so you never need code injection. - Flip CR4. Old, now-blocked trick: ROP into
mov cr4, rax-style gadgets to clear SMEP/SMAP bits, then jump to user payload. Modern Windows pins CR4 via Patch Guard / hypervisor (HVCI); Linux 5.3+ refuses CR4 writes that disable SMEP. Still possible against unpatched targets without VBS. stacgadget for SMAP only. A short kernel sequencestac; rettoggles AC and lets the next chain step touch user data. Less useful when SMEP also blocks execution.- Exploit without code exec. Token swap,
modprobe_pathoverwrite,core_patternhijack — all data-only paths that never violate SMEP/SMAP. - Use kernel-mapped attacker data. Spray data into kernel pool (writing controllable bytes into kernel-resident objects), then ROP into them — payload lives in supervisor pages.
Status check.
- Linux:
grep -E 'smep|smap' /proc/cpuinfoshows CPU support;dmesg | grep -i smepshows kernel enablement. - Windows:
wmic cpu get DataExecutionPrevention_SupportPolicyindirectly; specifically SMEP/SMAP visible viaRDMSR 0x10/CR4 dump under WinDbg.
Detection and defence
- Keep SMEP/SMAP enforced; ensure HVCI/VBS pins CR4 so direct disable is impossible.
- Linux:
nokaslr=0, default-enable SMEP/SMAP; backport KSPP hardening. - Windows: enable VBS+HVCI; combine with kCFI/kCET to also kill kernel ROP that the techniques above rely on.
References
- Intel SDM Vol. 3 — CR4 SMEP/SMAP — architectural reference
- LWN SMAP article — Linux integration
- Connor McGarr — SMEP/SMAP bypass — modern bypass write-up
See also: cfg-cet-kernel, hvci-vbs, arbitrary-read-write-primitives.