SMEP / SMAP

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: ret into 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:

  1. Stay in kernel space. Build a full kernel ROP chain (rop-chains) using ntoskrnl/hal.dll gadgets; never deref user memory. Combine with the data-only escalation in arbitrary-read-write-primitives so you never need code injection.
  2. 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.
  3. stac gadget for SMAP only. A short kernel sequence stac; ret toggles AC and lets the next chain step touch user data. Less useful when SMEP also blocks execution.
  4. Exploit without code exec. Token swap, modprobe_path overwrite, core_pattern hijack — all data-only paths that never violate SMEP/SMAP.
  5. 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/cpuinfo shows CPU support; dmesg | grep -i smep shows kernel enablement.
  • Windows: wmic cpu get DataExecutionPrevention_SupportPolicy indirectly; specifically SMEP/SMAP visible via RDMSR 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

See also: cfg-cet-kernel, hvci-vbs, arbitrary-read-write-primitives.