For a memory region to be used as a stack, the
flag has to be passed to
mmap; otherwise, upon syscalls and pagefaults, if
the stack-pointer register doesn’t point to such a page, the program gets
Although this feature has been introduced in 2018 in OpenBSD by Theo de Raadt,
based on discussions with Ted Unangst and work done by Stefan Sperling, it was
present in Windows as a function named
documented in Ivan Fratic’s ropguard
project, and removed in
likely because some of the
were both obvious and generic:
- Write a stub that calls
MAP_STACKflag, write your payload there, and jump on it, like done in 2023 by Thalium to pwn a TrustZone applet.
- Write a stub to read the rest of your rop-chain onto the stack and pivot to it.
- Before each syscall, make point
espsomewhere to the stack, and restore its value afterwards, as done in by @qwertyoruiop in yalu102 in 2017.
But checking the stack pointer on every pagefault is a bit more interesting,
unfortunately, someone told me about an OpenBSD-specific bypass, left as an
exercise to the reader:
The commit implementing this mitigation, by Theo de Raadt mentions the following:
Observe that MAP_STACK can only be set/cleared by mmap(), which zeroes the contents of the region – there is no mprotect() equivalent operation, so there is no MAP_STACK-adding gadget.
I guess this means to say that an attacker has no way to directly map a
MAP_STACK. Except that this can be done by calling
directly, and copying the ropchain there before jumping on it, which fits in a
couple of instructions.
This mitigation adds a bit of complexity, but no overhead nor hinders debuggability, and the check-stack-pointer-on-pagefault trick might annoy an attacker for a couple of hours. It’s definitely not worth breaking the ABI for this.