In January 1997, Casper Dik implemented
a non-executable stack for Solaris,
toggleable system-wide via the
The 12th of April 1997, Solar Designer sent his famous “Linux kernel patch to remove stack exec permission” for Linux 2.30.0 x86 on bugtraq, which was the style at the time. Four months later, he published a followup, formalising ret2libc, along with a suggested “fix”.
The lead to the first public mention of ROP by Tim Newsham, less than one month later, as a possible bypass, which was illustrated in January 1998, by Rafal Wojtczuk: “Defeating Solar Designer’s Non-executable Stack Patch”.
Solardiz’ patch was the foundation of Openwall, an hardened Linux distribution.
The first public ROP exploit on x86 was
dropped by Tim Newsham on bugtraq the 6th of
May 2000 , against
PaX (PAge eXecute) designed PAGEEXEC in August 2000, and it was implemented in and released in October 2000, based on ideas from the plex86 project. It provided non-executable pages for IA-32 (i386) processors, using pagination.
One month later, in November 2000, PAX_MPROTECT was created by PaX Team, and released somewhere in 2001, to prevent:
- creating executable anonymous mappings
- creating executable/writable file mappings
- making an executable/read-only file mapping writable except for performing relocations on an
ET_DYNELF file (non-PIC shared library)
- making a non-executable mapping executable
In January 2001, Securewave released a non-executable stack implementation for Windows NT/2000 called SecureStack.
In July 2002, Artur Grabowski started to implement support for a non-executable stack in OpenBSD, and Theo de Raadt committed a non-executable BSS. One month after, the heap was marked non-executable, also by Artur Grabowski.
SEGMEXEC is released by the PaX
Team, to replace
of pagination, as well as VMA (virtual memory area)
mirroring to detect
and prevent code injection.
In November 2002, OpenBSD 3.2 was released with a non-executable stack and heap on i386, sparc, sparc64, alpha, powerpc, as well a no-exec data and bss on sparc, sparc64, and alpha.
In January 2003, Dale Rahn
.rodata section in a separate segment on OpenBSD, to make it read-only.
In May 2003, Ingo Molnar published ExecShield, an implementation, amongst other things, of a non-executable stack, based on PaX’ work.
was add to PaX in April
While not being exactly a “PAGEEXEC for kernel-land”, it’s based on the same
idea as SEGMEXEC: non-executable pages and read-only things (syscall table,
GDT), as much as
In May 2003, OpenBSD 3.3, came with
W^X for userland on sparc, sparc64, alpha and hppa, preventing memory from
being mapped as writeable and executable at the same time.
In November 2003, spender did a talk about PaX: The Guaranteed End of Arbitrary
featuring an interesting comparison between PaX’
PAGEXEC and OpenBSD’s W^X.
W^X on i386 for userland has been added on OpenBSD
3.4, released in November 2003.
In May 2004, Theo de Raadt spoke about Exploit mitigation on
BSDCan04, explaining that it isn’t possible to
have per-page W^X granularity on architectures without the per-page X-bit,
which is exactly what PaX’
SEGMEXEC is doing.
In August 2004, Windows XP SP2 was released, with a non-executable heap and stack in userland. A month after, in September 2004, RHEL 3 also came with non-executable heap and stack, using ExecShield.
In January 2015, 12 years later, Theo de Raadt announced that thanks to the work of Mike Larkin, no part of the OpenBSD kernel is writeable and executable any more, on amd64. Seven months later, in August 2015, i386 was covered too.
In 2019, OpenBSD made ELF headers non-executable for i386, but only for machines with the NX bit: It doesn’t add anything security-wise, since the odds of finding valid and useful code there is non-existent, but why not.
In 2023, in his CanSecWest, De Raddt said:
OpenBSD was first system to use X/NX on all possible platforms with a policy called W^X (which was a solid step in 2002…)
But PAX had this in October 2000, along with
PAX_MPROTECT one month later;
and Securewave had NX for Windows NT/2000 in 2001.
Having no memory both writeable and executable is an excellent mitigation against the introduction of new code by an attacker, both in kernel-land and in user-land, forcing attackers to use more convoluted ways to achieve arbitrary code execution.
Unfortunately, OpenBSD doesn’t keep track of the mappings, and doesn’t prevent a writeable one from being mapped read-executable, like PaX' MPROTECT or iOS are doing, as mentioned in WX refinments.