W^X
1990s
In January 1997, Casper Dik implemented
a non-executable stack for Solaris,
toggleable system-wide via the non_exec_stack
flag.
The 12th of April 1997, Solar Designer sent his famous “Linux kernel patch to remove stack exec permission” for Linux 2.0.30 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”.
Solar Designer’s patch was the foundation of Openwall, an hardened Linux distribution.
2000s
The first public ROP exploit on x86 was
dropped by Tim Newsham on bugtraq the 6th of
May 2000 , against
lpset
.
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_DYN
ELF 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.
In August
2002,
SEGMEXEC is released by the PaX
Team, to replace PAGEEXEC
, using
segmentation instead
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
moved
the .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.
KERNEXEC,
was add to PaX in April
2003.
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,
.rodata
, IDT,
GDT), as much as
possible.
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
Code Execution,
featuring an interesting comparison between PaX’ SEGMEXEC
/PAGEXEC
and OpenBSD’s W^X.
Support for 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
OpenBSD at
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.
2010s
In 2013, spender did a talk at H2HC entitled At ARMs length
yet so far away,
about how he ported KERNEXEC
on ARM.
In January 2015, 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.
2020s
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 refinements.