SMAP and SMEP: Why the Kernel Can't Touch Your User Pages by Accident

2026-06-03

Before 2012, a classic kernel exploit pattern was: trick the kernel into dereferencing a user-controlled pointer, point it at user memory you've prepared with a fake structure or shellcode, profit. The kernel ran in ring 0 with unrestricted access to every page in the address space — including yours. SMEP (Supervisor Mode Execution Prevention, Ivy Bridge 2012) and SMAP (Supervisor Mode Access Prevention, Broadwell 2014) close this door at the page-walk level.

The mechanism is the User/Supervisor bit (bit 2) already present in every page table entry. When SMEP is enabled (CR4.SMEP=1), the CPU faults if ring 0 tries to execute a page where U/S=1. When SMAP is enabled (CR4.SMAP=1), the CPU faults if ring 0 tries to read or write such a page. No new metadata — the bits were always there; the CPU just started enforcing them in the other direction.

But the kernel legitimately needs to touch user pages — that's what copy_from_user() does. The escape hatch is RFLAGS bit 18, AC (Alignment Check), repurposed as a per-instruction SMAP override. The kernel wraps user access with STAC (set AC) and CLAC (clear AC):

The window is two instructions wide. An attacker who can't control execution between STAC and CLAC can't bypass it. Linux's copy_from_user path on x86-64 is essentially one STAC, a rep movsb, and one CLAC.

Concrete example: CVE-2013-1763 (sock_diag) let an attacker get the kernel to call a function pointer in a user-allocated array. On a pre-SMEP machine, kernel execution jumped to user shellcode and got root. On a SMEP machine with the same bug, the indirect branch faulted instantly — the U/S=1 page wasn't executable from ring 0 — and the kernel oopsed instead of being owned.

Rule of thumb: if your kernel module crashes with a page fault at a user-looking address (below TASK_SIZE, typically below 0x00007fffffffffff) and the fault was a write or read, check whether you forgot copy_from_user and went straight through a pointer. SMAP turned a silent exploit primitive into a loud crash.

Check it on your machine: grep -o 'smep\|smap' /proc/cpuinfo. Disable for debugging with nosmep nosmap on the kernel command line — never in production.

Key Takeaway: SMEP and SMAP repurpose the U/S page bit to fault when ring 0 executes or accesses user pages, turning a whole class of kernel exploits into crashes — with STAC/CLAC as the two-instruction window for legitimate copy_from_user paths.

All newsletters