MAP_STACK and mimmutable
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.
MAP_STACK marking is also present in Linux
since the 13 August 2008,
but was added for different
It’s not really used for anything super-interesting, beside pretty-printing via
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.
In September 2022, De Raadt added
a way to lock memory mappings via the new
This identifies all current mapped memory in a region, and tags the mappings. Such mappings can never be unmapped. No new mmap can be done on top of the mappings. And the permissions cannot be changed. Other than that, the underlying storage memory works fine, it is just the mapping that is locked.
Apparently, De Raadt is “aware of an method used at least once (not on OpenBSD)
which managed to mprotect a region of libc, and then place things there, for
later execution.”, which not only sounds dumb (why would anyone
libc mapping‽), but jumping to
mmap isn’t exactly a new technique. Moreover,
nobody, in any real-life exploit, has ever relied on changing some library mappings to do
anything. The only sighting of this technique was in a zer0pts CTF 2021
but it could trivially have used another technique instead.
In 2023, in his CanSecWest talk, he elaborated on this, saying that it was likely an iPhone exploit, likely the talk from Charlie Miller and Vincenzo Iozzo, at BlackHat 2009, about bypassing code signature,
Interestingly, he also mentioned there that
mimmutable will be used in the
future, for security-related features, building on top of the invariants it
This is at best a partial copy of
21 years after its publication, without giving credit,
and after having argued in April
2003 that it was
violating “POSIX by breaking mprotect”.
A documented bypass
is to simply call
dlopen, since it’ll by default mapped as mutable, because
they can be
dlclose’d and unmapped.
But in all fairness, he never called
mimmutable a security improvement.