2026-06-02
Every ROP exploit you've ever seen relies on the same trick: corrupt a saved return address on the stack, and when RET executes, the CPU jumps wherever you wrote. Intel CET's Shadow Stack (SHSTK), shipping on Tiger Lake (2020) and later, makes this trick fail at the hardware level — without recompiling your code.
The mechanism is brutally simple. The CPU maintains a second stack, mapped with a special PTE bit (SHSTK=1), that only CALL and RET can write to via dedicated micro-ops. On CALL, the return address is pushed to both the normal stack and the shadow stack. On RET, the CPU pops from both and compares. Mismatch? #CP (Control Protection) fault, process dies.
The shadow stack pointer lives in SSP, a new register. User code can't write to shadow stack pages with normal MOV — the MMU rejects it. Only WRSS (privileged) and the call/return machinery can. Even memcpy with a crafted pointer can't corrupt it.
Real-world example: glibc 2.39+ on a Tiger Lake or newer CPU with CET_SHSTK in /proc/cpuinfo will enable shadow stacks automatically if the binary's ELF note (NT_GNU_PROPERTY_TYPE_0) advertises IBT|SHSTK support. Compile with -fcf-protection=full. Now classic stack-smashing exploits — overwrite saved RIP, jump to system("/bin/sh") — trigger SIGSEGV with si_code=SEGV_CPERR instead of executing.
The catch: setjmp/longjmp and C++ exceptions. Both unwind the stack past multiple frames, which means SSP must skip ahead too. The kernel exposes INCSSP (increment shadow stack pointer by N) so libc can fast-forward. Custom coroutine libraries that swap stacks without using these APIs will crash on the first return after a swap — boost.context had to add explicit shadow stack management in 1.84.
Rule of thumb: shadow stack pages are allocated at (thread_stack_size / 8) + 4KB per thread — 8 bytes of shadow per stack frame plus a guard page. A process with 100 threads on 8MB stacks burns ~100MB of shadow memory. Not free, but cheap insurance.
Check if your process has it enabled:
grep VmFlags /proc/self/smaps | grep ss — shadow stack VMAs are tagged ssreadelf -n binary | grep -A2 PROPERTY — look for SHSTK in the GNU property notearch_prctl(ARCH_SHSTK_STATUS, ...) — runtime queryRET and faulting on mismatch — but stack-swapping libraries must explicitly manage SSP via INCSSP or crash on return.
