Recent from talks
Nothing was collected or created yet.
Executable-space protection
View on WikipediaThis article needs additional citations for verification. (April 2013) |
In computer security, executable-space protection marks memory regions as non-executable, such that an attempt to execute machine code in these regions will cause an exception. It relies on hardware features such as the NX bit (no-execute bit), or on software emulation when hardware support is unavailable. Software emulation often introduces a performance cost, or overhead (extra processing time or resources), while hardware-based NX bit implementations have no measurable performance impact.
The Burroughs large systems, starting with the Burroughs 5000 introduced in 1961, implemented executable-space protection using a tagged architecture. All accesses to code and data took place through descriptors, which had memory tags preventing them from being modified; descriptors for code did not allow the code to be modified, and descriptors for data did not allow the data ta be executed as code.
Today, operating systems use executable-space protection to mark writable memory areas, such as the stack and heap, as non-executable, helping to prevent buffer overflow exploits. These attacks rely on some part of memory, usually the stack, being both writable and executable; if it is not, the attack fails.
OS implementations
[edit]Many operating systems implement or have an available executable space protection policy. Here is a list of such systems in alphabetical order, each with technologies ordered from newest to oldest.
A technology supplying Architecture Independent emulation will be functional on all processors which aren't hardware supported. The "Other Supported" line is for processors which allow some grey-area method, where an explicit NX bit doesn't exist yet hardware allows one to be emulated in some way.
Android
[edit]As of Android 2.3 and later, architectures which support it have non-executable pages by default, including non-executable stack and heap.[1][2][3]
FreeBSD
[edit]Initial support for the NX bit, on x86-64 and IA-32 processors that support it, first appeared in FreeBSD -CURRENT on June 8, 2004. It has been in FreeBSD releases since the 5.3 release.
Linux
[edit]The Linux kernel supports the NX bit on x86-64 and IA-32 processors that support it, such as modern 64-bit processors made by AMD, Intel, Transmeta and VIA. The support for this feature in the 64-bit mode on x86-64 CPUs was added in 2004 by Andi Kleen, and later the same year, Ingo Molnár added support for it in 32-bit mode on 64-bit CPUs. These features have been part of the Linux kernel mainline since the release of kernel version 2.6.8 in August 2004.[4]
The availability of the NX bit on 32-bit x86 kernels, which may run on both 32-bit x86 CPUs and 64-bit IA-32-compatible CPUs, is significant because a 32-bit x86 kernel would not normally expect the NX bit that an AMD64 or IA-64 supplies; the NX enabler patch assures that these kernels will attempt to use the NX bit if present.
Some desktop Linux distributions, such as Fedora, Ubuntu and openSUSE, do not enable the HIGHMEM64 option by default in their default kernels, which is required to gain access to the NX bit in 32-bit mode, because the PAE mode that is required to use the NX bit causes boot failures on pre-Pentium Pro (including Pentium MMX) and Celeron M and Pentium M processors without NX support. Other processors that do not support PAE are AMD K6 and earlier, Transmeta Crusoe, VIA C3 and earlier, and Geode GX and LX. VMware Workstation versions older than 4.0, Parallels Workstation versions older than 4.0, and Microsoft Virtual PC and Virtual Server do not support PAE on the guest. Fedora Core 6 and Ubuntu 9.10 and later provide a kernel-PAE package which supports PAE and NX.
NX memory protection has always been available in Ubuntu for any systems that had the hardware to support it and ran the 64-bit kernel or the 32-bit server kernel. The 32-bit PAE desktop kernel (linux-image-generic-pae) in Ubuntu 9.10 and later, also provides the PAE mode needed for hardware with the NX CPU feature. For systems that lack NX hardware, the 32-bit kernels now provide an approximation of the NX CPU feature via software emulation that can help block many exploits an attacker might run from stack or heap memory.
Non-execute functionality has also been present for other non-x86 processors supporting this functionality for many releases.
Exec Shield
[edit]Red Hat kernel developer Ingo Molnár released a Linux kernel patch named Exec Shield to approximate and utilize NX functionality on 32-bit x86 CPUs. The Exec Shield patch was released to the Linux kernel mailing list on May 2, 2003, but was rejected for merging with the base kernel because it involved some intrusive changes to core code in order to handle the complex parts of the emulation. Exec Shield's legacy CPU support approximates NX emulation by tracking the upper code segment limit. This imposes only a few cycles of overhead during context switches, which is for all intents and purposes immeasurable. For legacy CPUs without an NX bit, Exec Shield fails to protect pages below the code segment limit; an mprotect() call to mark higher memory, such as the stack, executable will mark all memory below that limit executable as well. Thus, in these situations, Exec Shield's schemes fails. This is the cost of Exec Shield's low overhead. Exec Shield checks for two ELF header markings, which dictate whether the stack or heap needs to be executable. These are called PT_GNU_STACK and PT_GNU_HEAP respectively. Exec Shield allows these controls to be set for both binary executables and for libraries; if an executable loads a library requiring a given restriction relaxed, the executable will inherit that marking and have that restriction relaxed.
- Hardware Supported Processors: All that Linux supports NX on
- Emulation: NX approximation using the code segment limit on IA-32 (x86) and compatible
- Other Supported: None
- Standard Distribution: Fedora Core and Red Hat Enterprise Linux
- Release Date: May 2, 2003
PaX
[edit]The PaX NX technology can emulate NX functionality, or use a hardware NX bit. PaX works on x86 CPUs that do not have the NX bit, such as 32-bit x86. The Linux kernel still does not ship with PaX (as of May, 2007); the patch must be merged manually.
PaX provides two methods of NX bit emulation, called SEGMEXEC and PAGEEXEC. The SEGMEXEC method imposes a measurable but low overhead, typically less than 1%, which is a constant scalar incurred due to the virtual memory mirroring used for the separation between execution and data accesses.[5] SEGMEXEC also has the effect of halving the task's virtual address space, allowing the task to access less memory than it normally could. This is not a problem until the task requires access to more than half the normal address space, which is rare. SEGMEXEC does not cause programs to use more system memory (i.e. RAM), it only restricts how much they can access. On 32-bit CPUs, this becomes 1.5 GB rather than 3 GB.
PaX supplies a method similar to Exec Shield's approximation in the PAGEEXEC as a speedup; however, when higher memory is marked executable, this method loses its protections. In these cases, PaX falls back to the older, variable-overhead method used by PAGEEXEC to protect pages below the CS limit, which may become quite a high-overhead operation in certain memory access patterns. When the PAGEEXEC method is used on a CPU supplying a hardware NX bit, the hardware NX bit is used, thus no significant overhead is incurred.
PaX supplies mprotect() restrictions to prevent programs from marking memory in ways that produce memory useful for a potential exploit. This policy causes certain applications to cease to function, but it can be disabled for affected programs.
PaX allows individual control over the following functions of the technology for each binary executable:
- PAGEEXEC
- SEGMEXEC
- mprotect() restrictions
- Trampoline emulation
- Randomized executable base
- Randomized mmap() base
PaX ignores both PT_GNU_STACK and PT_GNU_HEAP. In the past, PaX had a configuration option to honor these settings but that option has been removed for security reasons, as it was deemed not useful. The same results of PT_GNU_STACK can normally be attained by disabling mprotect() restrictions, as the program will normally mprotect() the stack on load. This may not always be true; for situations where this fails, simply disabling both PAGEEXEC and SEGMEXEC will effectively remove all executable space restrictions, giving the task the same protections on its executable space as a non-PaX system.
- Hardware Supported Processors: Alpha, AMD64, IA-64, MIPS (32 and 64 bit), PA-RISC, PowerPC, SPARC
- Emulation: IA-32 (x86)
- Other Supported: PowerPC (32 and 64 bit), SPARC (32 and 64 bit)
- Standard Distribution: Alpine Linux
- Release Date: October 1, 2000
macOS
[edit]macOS for Intel supports the NX bit on all CPUs supported by Apple (from Mac OS X 10.4.4 – the first Intel release – onwards). Mac OS X 10.4 only supported NX stack protection. In Mac OS X 10.5, all 64-bit executables have NX stack and heap; W^X protection. This includes x86-64 (Core 2 or later) and 64-bit PowerPC on the G5 Macs.
NetBSD
[edit]As of NetBSD 2.0 and later (December 9, 2004), architectures which support it have non-executable stack and heap.[6]
Architectures that have per-page granularity consist of: alpha, amd64, hppa, i386 (with PAE), powerpc (ibm4xx), sh5, sparc (sun4m, sun4d), sparc64.
Architectures that can only support these with region granularity are: i386 (without PAE), other powerpc (such as macppc).
Other architectures do not benefit from non-executable stack or heap; NetBSD does not by default use any software emulation to offer these features on those architectures.
OpenBSD
[edit]A technology in the OpenBSD operating system, known as W^X, marks writable pages by default as non-executable on processors that support that. On 32-bit x86 processors, the code segment is set to include only part of the address space, to provide some level of executable space protection.
OpenBSD 3.3 shipped May 1, 2003, and was the first to include W^X.
- Hardware Supported Processors: Alpha, AMD64, HPPA, SPARC
- Emulation: IA-32 (x86)
- Other Supported: None
- Standard Distribution: Yes
- Release Date: May 1, 2003
Solaris
[edit]Solaris has supported globally disabling stack execution on SPARC processors since Solaris 2.6 (1997); in Solaris 9 (2002), support for disabling stack execution on a per-executable basis was added.
Windows
[edit]The first implementation of a non-executable stack for Windows (NT 4.0, 2000 and XP) was published by SecureWave via their SecureStack product in 2001, based on the work of PaX.[7][8]
Starting with Windows XP Service Pack 2 (2004) and Windows Server 2003 Service Pack 1 (2005), the NX features were implemented for the first time on the x86 architecture. Executable space protection on Windows is called "Data Execution Prevention" (DEP).
Under Windows XP or Server 2003 NX protection was used on critical Windows services exclusively by default. If the x86 processor supported this feature in hardware, then the NX features were turned on automatically in Windows XP/Server 2003 by default. If the feature was not supported by the x86 processor, then no protection was given.
Early implementations of DEP provided no address space layout randomization (ASLR), which allowed potential return-to-libc attacks that could have been feasibly used to disable DEP during an attack.[9] The PaX documentation elaborates on why ASLR is necessary;[10] a proof-of-concept was produced detailing a method by which DEP could be circumvented in the absence of ASLR.[11] It may be possible to develop a successful attack if the address of prepared data such as corrupted images or MP3s can be known by the attacker.
Microsoft added ASLR functionality in Windows Vista and Windows Server 2008. On this platform, DEP is implemented through the automatic use of PAE kernel in 32-bit Windows and the native support on 64-bit kernels. Windows Vista DEP works by marking certain parts of memory as being intended to hold only data, which the NX or XD bit enabled processor then understands as non-executable.[12] In Windows, from version Vista, whether DEP is enabled or disabled for a particular process can be viewed on the Processes/Details tab in the Windows Task Manager.
Windows implements software DEP (without the use of the NX bit) through Microsoft's "Safe Structured Exception Handling" (SafeSEH). For properly compiled applications, SafeSEH checks that, when an exception is raised during program execution, the exception's handler is one defined by the application as it was originally compiled. The effect of this protection is that an attacker is not able to add his own exception handler which he has stored in a data page through unchecked program input.[12][13]
When NX is supported, it is enabled by default. Windows allows programs to control which pages disallow execution through its API as well as through the section headers in a PE file. In the API, runtime access to the NX bit is exposed through the Win32 API calls VirtualAlloc[Ex] and VirtualProtect[Ex]. Each page may be individually flagged as executable or non-executable. Despite the lack of previous x86 hardware support, both executable and non-executable page settings have been provided since the beginning. On pre-NX CPUs, the presence of the 'executable' attribute has no effect. It was documented as if it did function, and, as a result, most programmers used it properly. In the PE file format, each section can specify its executability. The execution flag has existed since the beginning of the format and standard linkers have always used this flag correctly, even long before the NX bit. Because of this, Windows is able to enforce the NX bit on old programs. Assuming the programmer complied with "best practices", applications should work correctly now that NX is actually enforced. Only in a few cases have there been problems; Microsoft's own .NET Runtime had problems with the NX bit and was updated.
- Hardware Supported Processors: x86-64 (AMD64 and Intel 64), IA-64, Efficeon, Pentium M (later revisions), AMD Sempron (later revisions)
- Emulation: Yes
- Other Supported: None
- Standard Distribution: Post Windows XP
- Release Date: August 6, 2004
Xbox
[edit]In Microsoft's Xbox, although the CPU does not have the NX bit, newer versions of the XDK set the code segment limit to the beginning of the kernel's .data section (no code should be after this point in normal circumstances). Starting with version 51xx, this change was also implemented into the kernel of new Xboxes. This broke the techniques old exploits used to become a terminate-and-stay-resident program. However, new exploits were quickly released supporting this new kernel version because the fundamental vulnerability in the Xbox kernel was unaffected.
Limitations
[edit]Where code is written and executed at runtime—a JIT compiler is a prominent example—the compiler can potentially be used to produce exploit code (e.g. using JIT Spray) that has been flagged for execution and therefore would not be trapped.[14][15]
Return-oriented programming can allow an attacker to execute arbitrary code even when executable space protection is enforced.
See also
[edit]References
[edit]- ^ "Memory Management Security Enhancements", Android Security Overview, retrieved 2012/07/29.
- ^ "Android code change enabling NX by default". Android Source Repository Change. Retrieved 2019-08-27.
- ^ "Android Compatibility Requirement for NX". Android Code Review. Retrieved 2019-08-27.
- ^ "Linux kernel 2.6.8". kernelnewbies.org. 2004-08-14. Retrieved 2015-08-01.
- ^ "PaX SEGMEXEC documentation" (TXT). pax.grsecurity.net. September 10, 2004. Retrieved January 25, 2015.
- ^ NetBSD, Non-executable stack and heap, retrieved 2011/07/14.
- ^ "SecureWave | SecureNT". 2001-03-31. Archived from the original on 2001-03-31. Retrieved 2023-12-27.
- ^ "Homepage of PaX - the PAGE_EXEC flag implementation for IA-32". 2001-03-31. Archived from the original on 2001-03-31. Retrieved 2023-12-27.
- ^ "Blog on Cyberterror". Archived from the original on 2012-02-09. Retrieved 2008-01-08.
- ^ "address space layout randomization". PaX project.
- ^ "Uninformed - vol 2 article 4". Archived from the original on 2016-03-12. Retrieved 2010-03-19.
- ^ a b "A detailed description of the Data Execution Prevention (DEP) feature in Windows XP Service Pack 2, Windows XP Tablet PC Edition 2005, and Windows Server 2003". Microsoft. 2006-09-26. Archived from the original on 2014-09-11. Retrieved 2008-07-11.
- ^ Johnson, Peter. "Yasm User Manual, win32: Safe Structured Exception Handling". Tortall Networks: Open Source and Free Software. Archived from the original on January 2, 2015. Retrieved 27 September 2015.
- ^ Dion Blazakis. "Interpreter Exploitation: Pointer Inference And JIT Spraying" (PDF).
- ^ Alexey Sintsov (March 5, 2010). "Writing JIT-Spray Shellcode for fun and profit" (PDF). Archived from the original (PDF) on 2016-03-04.
Executable-space protection
View on GrokipediaOverview
Definition and Purpose
Executable-space protection (ESP), also known as W^X or write XOR execute, is a memory management security mechanism that designates specific regions of a process's virtual address space as non-executable, thereby triggering a hardware or software exception upon any attempt to execute machine code from those areas.[4] This policy ensures that memory pages cannot simultaneously possess both writable and executable permissions, enforcing a strict separation to prevent unauthorized code execution in data-only zones.[4] The primary purpose of ESP is to mitigate common exploitation techniques, such as buffer overflows, where attackers inject malicious code—often called shellcode—into writable data structures like the stack or heap and then redirect control flow to execute it.[1] By rendering these data regions non-executable, ESP blocks the injected code from running, thereby disrupting the exploit chain and enhancing overall memory safety without altering application behavior in normal operation.[1] This approach contributes to broader defenses against code injection attacks by maintaining a clear distinction: data areas remain writable but non-executable, while legitimate code segments are executable but protected from modification.[4] For instance, in a classic stack-based buffer overflow, an attacker might overflow a function's buffer to overwrite the return address and insert shellcode; however, under ESP, the processor detects the attempt to fetch instructions from the non-executable stack page and raises an exception, typically terminating the process before harm occurs.[1] Hardware support, such as the NX (No eXecute) bit in AMD64 processors, facilitates this by allowing the setting of a flag in page-table entries to enforce non-execution at the CPU level.[5]Security Benefits
Executable-space protection (ESP) substantially mitigates the risk of successful exploitation in memory corruption vulnerabilities by enforcing a strict separation between writable data regions and executable code segments, thereby preventing attackers from executing injected shellcode in areas like the stack or heap. This mechanism directly counters traditional buffer overflow attacks that depend on code injection, rendering a large majority of such exploits ineffective without requiring modifications to existing software. For instance, hardware-supported ESP implementations, such as the NX bit, have been shown to block execution attempts in non-executable memory, significantly hindering the deployment of malicious payloads in data-only attack scenarios.[1] As part of a layered defense strategy, ESP complements other mitigations like Address Space Layout Randomization (ASLR) and stack canaries by addressing the execution phase of attacks that survive initial randomization or integrity checks. While ASLR disrupts address predictability to complicate control-flow hijacking and stack canaries detect buffer overruns through value validation, ESP closes the gap by ensuring that even if corrupted data redirects execution to injected code, it cannot run, forcing attackers toward more complex techniques like return-oriented programming (ROP). This synergy enhances overall resilience against memory corruption, as no single mitigation is foolproof alone.[6] Empirical data from security analyses demonstrates the real-world impact of ESP adoption, with a notable decline in shellcode-based exploits following its integration into major operating systems around the mid-2000s. Microsoft reported a 70% reduction in exploited remote code execution vulnerabilities in its products from 2010 to 2013, largely attributable to widespread deployment of DEP (a hardware-enforced ESP variant) alongside ASLR, which curtailed the viability of injection-style attacks that dominated earlier exploit landscapes.[7] Beyond direct exploit prevention, ESP contributes to a healthier software ecosystem by incentivizing secure development practices, such as avoiding executable stacks in new code and auditing legacy applications for compatibility. This reduction in attack surface extends to older software bases prone to buffer overflows, where retrofitting ESP via emulation or hardware support minimizes risks without full rewrites, ultimately fostering a defensive posture that prioritizes memory safety across diverse environments.[6]Technical Mechanism
Software Emulation Techniques
Software emulation techniques provide a means to enforce executable-space protection (ESP) on systems lacking hardware support for non-executable memory, such as pre-2004 x86 processors without the NX bit. These methods simulate the desired security properties through kernel-level modifications, primarily using page table adjustments or processor segmentation features available in architectures like IA-32. By manipulating memory mappings, software emulation ensures that writable regions cannot be executed, preventing exploits like buffer overflows that inject and run malicious code.[8][9] One seminal approach is PaX's SEGMEXEC, which leverages the x86 segmentation unit to divide the 3 GB user-space address range into two 1.5 GB segments: a lower data segment for writable memory and an upper code segment for executable memory. Executable pages are mirrored across both segments during ELF loading, allowing legitimate code access while triggering segmentation faults for attempts to execute data pages; this is achieved by modifying context switches and loading routines in the kernel. SEGMEXEC restricts user-defined code segments to further mitigate attacks involving segment descriptor manipulation. The technique maintains compatibility with existing binaries but requires kernel patches for implementation.[8] Another key technique is Exec Shield, developed by Red Hat, which modifies the ELF binary loading process to place code segments below a configurable segment limit (making them executable) and data segments (including stack and heap) above it (non-executable). This separation exploits x86 segment limits to enforce a coarse-grained W^X policy, where attempts to execute upper-address data trigger segmentation faults. Exec Shield complements this with address space layout randomization (ASLR) for broader protection, though it applies primarily to static binaries and may require recompilation for optimal separation.[9][10] These emulation methods introduce performance overhead primarily from additional kernel operations, such as segment management or mirroring, but measurements indicate low impact—around 0.7% for SEGMEXEC in benchmarked scenarios. However, more dynamic software approaches relying on frequent permission switches via system calls like mprotect() to toggle between writable and executable states can incur higher costs, up to 10-20% slowdown in execution-intensive workloads due to repeated page table updates and fault handling.[11] Such trade-offs make software emulation essential for legacy hardware but less efficient than hardware alternatives like the NX bit.[12]Hardware-Based Protection
Hardware-based executable-space protection (ESP) relies on dedicated features in modern CPU architectures that allow pages of memory to be marked as non-executable directly within page table entries (PTEs), with enforcement handled natively by the memory management unit (MMU). These mechanisms prevent the execution of code from data regions, such as stack or heap, thereby mitigating buffer overflow exploits and other code injection attacks at the hardware level. Unlike software-emulated approaches, hardware enforcement incurs negligible overhead, as the CPU raises an exception—typically a general protection fault—upon any attempt to fetch instructions from a non-executable page.[13] In the AMD64 architecture, the No-eXecute (NX) bit serves as the primary hardware feature for ESP, implemented as bit 63 in 64-bit PTEs for x86-64 and later processors. When set to 1, this bit marks the associated page as non-executable, prohibiting instruction fetches while still allowing read and write access if those permissions are granted. The NX bit is supported in long mode and requires the extended feature enable (EFER) register's no-execute enable (NXE) bit to be set by the operating system before use; once enabled, the MMU checks the NX bit during address translation and generates a fault on execution attempts from marked pages. AMD introduced the NX bit as part of its x86-64 extension in the early 2000s, providing a low-latency alternative to software-based protections. Intel's equivalent feature, the Execute Disable (XD) bit, was first introduced in the Pentium 4 processor in 2004 and functions identically to the AMD NX bit, using bit 63 in 64-bit PTEs under physical address extension (PAE) or long mode.[14] Like NX, the XD bit requires activation via the EFER.NXE bit (bit 11) in the extended feature enable register, after which the processor's MMU enforces non-execution by triggering a #GP(0) general protection exception on fetch attempts from XD-marked pages. This hardware enforcement integrates seamlessly with the existing x86 paging hierarchy, where the CPU examines the bit during page walks without additional software intervention. Intel's XD bit was designed to align with AMD's NX while ensuring backward compatibility for 32-bit PAE paging. Beyond x86, other architectures provide analogous hardware support for ESP. In ARM architectures (from ARMv6 onward), the Execute Never (XN) bit in page table descriptors—such as bit 0 in short-descriptor level 2 entries or bit 54 in long-descriptor entries—prevents instruction execution from the mapped region, with the MMU raising a permission fault on violation; a privileged variant (PXN) further restricts execution at elevated privilege levels.[15] Similarly, PowerPC architectures include a No-Execute (N) bit in page table entries (bit 61 in 64-bit PTEs for Book III implementations), which, when set, blocks code execution from the page while permitting data access, enforced via storage protection exceptions during instruction fetch. (Note: PowerPC Book III spec mirrored; original from IBM/Motorola) Operating systems integrate these hardware features by setting the appropriate bits during memory allocation and mapping: executable regions like code segments receive the execute permission (NX/XD/XN cleared to 0), while data areas such as stacks and heaps have it set to 1. For x86-64, a typical 64-bit PTE structure includes bit 0 (present), bits 1-2 (read/write permissions), bit 3 (user/supervisor), and bit 63 (NX/XD), alongside the 52-bit physical page frame number and other attributes like caching controls; this granular bit-field design allows fine-tuned protection without altering the core paging mechanics.| Bit Position | Field | Description |
|---|---|---|
| 0 | Present (P) | Indicates if the page mapping is valid. |
| 1 | Read/Write (R/W) | Allows write access if set (otherwise read-only). |
| 2 | User/Supervisor (U/S) | Permits access from user mode if set. |
| 63 | No-Execute (NX/XD) | Marks page as non-executable if set to 1. |
| 12-51 | Physical Page Number | Base address of the 4 KiB physical page. |
Historical Development
Early Concepts and Innovations
The concept of executable-space protection originated in the mid-20th century with hardware innovations aimed at isolating executable code from modifiable data to enhance system security. In 1961, the Burroughs B5000 introduced one of the earliest implementations through its tagged architecture, where each word in memory carried a tag bit that distinguished executable instructions from data operands and control words, thereby preventing unauthorized execution of data as code.[16] This design enforced memory protection at the hardware level, ensuring that only properly tagged regions could be executed, which laid foundational principles for separating execution privileges from data storage.[16] Building on such tagged memory systems, research in the 1980s and 1990s explored advanced memory isolation techniques to safeguard against unauthorized access and execution. A notable example is the IBM System/38, released in 1980, which employed a tagging scheme integrated with its object-based addressing to protect data integrity and prevent code execution in non-designated areas.[17] The system's architecture used tags to maintain capability integrity within segments, allowing secure storage of both data and capabilities while isolating executable spaces from potential tampering.[17] These academic and industrial efforts emphasized hardware-enforced boundaries, influencing later software-based emulations of similar protections. By the early 2000s, software prototypes began emulating executable-space protection on commodity hardware lacking native support. In 2001, SecureWave released SecureStack, a kernel-mode driver for Windows NT/2000 and XP that marked the stack as non-executable, specifically targeting buffer overflow exploits by preventing shellcode execution in stack memory.[18] This tool represented a pioneering commercial effort to enforce write-XOR-execute (W^X) policies without hardware assistance, demonstrating practical defenses against common attack vectors.[18] Shortly thereafter, in October 2002, the PaX project introduced SEGMEXEC as part of its Linux kernel patch, providing software emulation of non-executable memory via x86 segmentation.[19] SEGMEXEC leveraged the processor's segmentation features to simulate per-page execution controls, predating widespread hardware NX bit support and enabling W^X enforcement on older systems.[8] This innovation allowed Linux users to deploy robust protection against code injection attacks through purely software means.[8]Widespread Adoption in the 2000s
The widespread adoption of executable-space protection (ESP) in the early 2000s was propelled by the escalating prevalence of buffer overflow exploits, exemplified by high-profile worms such as Code Red in July 2001 and Nimda in September 2001, which exploited vulnerabilities in Microsoft IIS to inject and execute malicious code on vulnerable systems.[20] These incidents highlighted the need for mechanisms to prevent code execution in data regions like the stack and heap, prompting operating system developers to integrate ESP features into production releases. By marking memory pages as non-executable, ESP significantly mitigated similar worm propagation tactics, reducing the success rate of code-injection attacks in subsequent years.[21] A pivotal milestone occurred in May 2003 with the release of OpenBSD 3.3, which introduced the first full W^X (write XOR execute) implementation in a production operating system, enforcing that memory pages could be either writable or executable but never both.[22] This software-emulated policy was enabled systemwide by default and utilized the hardware NX (no-execute) bit where available on supported architectures like SPARC, SPARC64, Alpha, and HPPA, thereby enhancing performance on compatible hardware while providing robust protection against buffer overflows.[23] In 2004, Linux kernel 2.6.8, released on August 14, further accelerated mainstream adoption by integrating support for non-executable stack and heap regions through options derived from Exec Shield and PaX, including updates to make the heap non-executable for binaries with PT_GNU_STACK markings.[24] Concurrently, Microsoft rolled out Windows XP Service Pack 2 on August 6, introducing Data Execution Prevention (DEP), a feature that leveraged the NX bit (also known as Execute Disable on Intel and Enhanced Virus Protection on AMD) to mark data pages as non-executable, thereby blocking common exploit techniques.[25] The launch of AMD's Opteron processor in April 2003, the first to implement the AMD64 architecture, played a crucial role in popularizing the NX bit by making hardware-accelerated ESP accessible in affordable 64-bit systems, influencing subsequent OS integrations and contributing to a broader decline in successful code-injection worms akin to Code Red and Nimda.[26][27]Operating System Implementations
Linux
The Linux kernel has supported executable-space protection through the NX (No eXecute) bit since version 2.6.8, released in August 2004, which enables non-executable memory mappings for the stack, heap, and libraries on compatible x86 architectures.[28] This integration allows administrators to configure default non-executable regions using the noexec mount flag, preventing execution of code in data areas and mitigating buffer overflow exploits without requiring additional patches.[28] By leveraging hardware NX support where available, the kernel enforces the W^X (write XOR execute) policy at the page level, marking writable regions like the stack and heap as non-executable by default during process creation.[29] For enhanced security in hardened environments, the PaX and grsecurity patches provide stricter enforcement of W^X policies beyond mainline capabilities. PaX, a kernel patch developed for architectures lacking native NX support, implements non-executable virtual memory pages through techniques like page execution control and segmentation, while grsecurity bundles these with additional access controls.[30] A key feature, MPROTECT, restricts runtime modifications to memory permissions, blocking calls to mprotect() or mmap() that would create executable writable pages or alter non-executable regions to executable, thereby preventing attackers from dynamically enabling code execution in data areas.[30] These patches, maintained separately from the mainline kernel, are widely used in security-focused distributions like Hardened Gentoo and offer configurable flags (e.g., -M for MPROTECT enforcement) on a per-binary basis via tools like paxctl.[30] Red Hat introduced Exec Shield in 2003 as part of Red Hat Enterprise Linux 3, utilizing CPU segmentation to separate read/write and execute permissions, limiting executable memory to the lower virtual address space and randomizing stack, heap, and library locations for added protection.[9] This software-based approach complemented early hardware NX adoption and influenced broader Linux security practices, but it was deprecated around 2005 in subsequent releases as hardware NX bits became standard, shifting reliance to native kernel mechanisms.[9] In Android, a Linux derivative, executable-space protection was enhanced starting with version 2.3 (Gingerbread) in 2010, enabling default non-executable stack and heap mappings on supported architectures to block code injection attacks.[31] This is further strengthened by SELinux, introduced in permissive mode in Android 4.3 (2013) and fully enforcing mandatory access control by Android 5.0 (Lollipop) in 2014, which confines processes and limits interactions that could bypass NX protections.[32] Hardened memory allocation, beginning with secure variants of dlmalloc in early versions and evolving to the Scudo allocator by Android 11 (2020), mitigates heap exploitation alongside NX; as of 2025, Android enforces NX on a per-app basis within isolated processes, ensuring app-specific memory regions remain non-executable unless explicitly required.[33][32]Windows
Data Execution Prevention (DEP), Microsoft's implementation of executable-space protection, was introduced in Windows XP Service Pack 2 in 2004 as a system-level memory protection feature designed to prevent code execution from data-only memory regions, such as heaps and stacks.[1] This feature marks memory pages as non-executable, triggering an access violation exception if malicious code attempts to run from protected areas, thereby mitigating exploits like buffer overflows.[1] DEP leverages hardware support for the No-eXecute (NX) bit—also known as Execute Disable (XD) on Intel processors—available on compatible CPUs to enforce these protections efficiently at the hardware level.[1] For systems with legacy CPUs lacking NX support, DEP employs software emulation to simulate the non-executable marking, ensuring broader compatibility while maintaining core security benefits, though with potential performance overhead due to additional runtime checks.[1] DEP operates through configurable system policies that balance security and application compatibility. The OptIn mode, the default for client editions like Windows XP and later, enables DEP exclusively for essential operating system components, including the Windows kernel and critical drivers, while allowing developers to opt in additional applications via APIs like SetProcessDEPPolicy.[34] In contrast, OptOut mode—default for server editions—applies DEP to the entire system and all processes, permitting administrators to exclude specific incompatible programs through the System Properties interface or boot configuration.[34] The AlwaysOn mode enforces DEP universally across all processes without exceptions, providing maximum protection; this mode, along with comprehensive kernel enforcement, became fully supported starting with Windows Vista Service Pack 1 in 2008, where it ensures the kernel runs with permanent DEP activation regardless of hardware variations.[34] In Microsoft's Xbox ecosystem, executable-space protection predates desktop implementations. The Xbox 360, launched in 2005, incorporated full DEP support as part of its PowerPC-based architecture, extending these protections to game execution environments. As of 2025, DEP is mandatory and deeply integrated into Windows 11 and Windows Server 2025, where it works in tandem with Virtualization-based Security (VBS) for enhanced enforcement.[35] VBS utilizes hardware virtualization to isolate critical components, with features like Hypervisor-protected Code Integrity (HVCI)—also known as memory integrity—building on DEP by verifying kernel-mode code signatures before allowing execution and preventing runtime modifications to executable pages.[35] This integration requires compatible hardware, including 64-bit CPUs with Second Level Address Translation (SLAT), Secure Boot, and TPM 2.0, and is enabled by default on qualifying Windows 11 systems to provide layered defenses against advanced threats.[35]BSD Derivatives
OpenBSD introduced W^X executable space protection in its 3.3 release on May 1, 2003, enforcing a policy where memory pages cannot be simultaneously writable and executable on architectures with MMU support for an execute bit, such as SPARC, SPARC64, Alpha, and HPPA.[22] This marked an early milestone in system-wide adoption of the feature, preventing code injection attacks by design.[23] Strict enforcement was achieved through integration with ProPolice, a GCC extension for stack-smashing protection that reorders variables and inserts canaries, enabled by default in the system compiler to complement W^X by detecting overflows before execution attempts.[22] FreeBSD implemented executable space protection starting with version 5.3 in November 2004, leveraging Physical Address Extension (PAE) and the NX bit on x86 processors to designate memory regions as non-executable where hardware permits.[36] By default, memory mappings created via mmap(2) without the PROT_EXEC flag are treated as non-executable, aligning with the system's security model to block unintended code execution in data areas like the stack and heap. NetBSD incorporated support for no-execute pages in version 2.0, released in December 2004, via enhancements to the pmap layer that manage physical-to-virtual address translations and enable non-executable attributes across diverse architectures.[37] This implementation maps the process stack and heap as non-executable by default while allowing explicit PROT_EXEC requests through mmap(2) on supported hardware, ensuring portability and hardware-agnostic enforcement where possible.[38] BSD derivatives share a commitment to security-by-default principles, activating executable space protection without user intervention to proactively counter exploitation vectors like buffer overflows.[39] Recent updates as of 2025, including OpenBSD 7.8's (October 2025) expanded ARM64 hardware compatibility and FreeBSD 14.3's (June 2025) refined ARMv8 support, have bolstered ESP robustness on embedded and mobile platforms.[40][41]macOS
Apple's implementation of executable-space protection in macOS began with partial NX stack protection in version 10.4 (2005), with full W^X enforcement in macOS 10.5 Leopard (2007), leveraging the NX (No eXecute) bit—also known as the XD (Execute Disable) bit—available on supported Intel processors to mark memory pages as non-executable, thereby preventing code execution in data regions like stack and heap.[42] This hardware-assisted mechanism enforces a write-XOR-execute (W^X) policy at the page level, raising exceptions on attempts to execute from protected areas.[42] In macOS, Library Validation, introduced as part of the Hardened Runtime in macOS 10.13 High Sierra (2017) but building on earlier code-signing policies from macOS 10.10 Yosemite (2014), enforces W^X specifically for system libraries and dynamically loaded modules by restricting processes to only load code-signed frameworks, plug-ins, or libraries from trusted developers or Apple itself.[43] This feature prevents the injection or modification of executable code in library space, complementing the NX bit by adding a software layer of validation that denies writable executable mappings for unauthorized content.[44] Hardened Runtime is enabled by default for notarized applications, ensuring that system-wide libraries maintain strict separation between writable data and executable regions.[45] Executable-space protection in iOS, derived from the same Darwin kernel as macOS, has been mandatory since iPhone OS 2.0 in 2008, utilizing the ARM processor's Execute Never (XN) bit to designate memory pages as non-executable by default and enforcing W^X across the system.[46] In iOS, third-party applications face additional restrictions on just-in-time (JIT) compilation, with no-execute policies applied to heap and stack regions unless the app holds a rare Apple-granted dynamic code-signing entitlement, which is typically reserved for first-party or specially sandboxed processes like Safari's JavaScript engine.[47] This entitlement allows limited writable-executable mappings within the app's sandbox, isolating potential risks from other system components.[47] Code signing is deeply integrated with ESP across macOS and iOS, requiring all executable pages—such as Mach-O binaries and dynamic libraries—to be digitally signed by a valid developer identity before they can be mapped as executable in memory, effectively blocking the execution of unsigned or tampered code.[48] In macOS 15 Sequoia (2024), this integration was strengthened by mandating signatures for all launched applications, removing previous workarounds for unsigned code and tying ESP enforcement directly to signature verification during process loading.[49] As of 2025, macOS 15 continues to enhance ESP through Pointer Authentication Codes (PACs), a hardware feature in Apple Silicon that complements NX/XN by cryptographically signing function pointers and return addresses to prevent their manipulation, even if an attacker bypasses basic page-level protections.[50] PACs are enforced system-wide in Sequoia, adding a layer of return-oriented programming resistance without altering core W^X policies.[50]Other Implementations
Oracle Solaris has implemented executable-space protection features since its early versions. Introduced in Solaris 2.6 in 1997, the noexec_user_stack parameter enables administrators to mark user-mode stacks as non-executable, thereby complicating buffer overflow exploits that attempt to inject and execute malicious code on the stack.[51] Solaris 10, released in 2005, extended this protection with the nxstack and nxheap security extensions, which systematically enforce non-executable stacks and heaps for processes running tagged binaries, achieving a full W^X (write XOR execute) policy to prevent code execution in writable memory regions.[52] In embedded and real-time operating systems (RTOS), executable-space protection often leverages hardware memory protection units (MPUs) for efficient, low-overhead enforcement. QNX Neutrino RTOS utilizes the underlying processor's MMU or MPU to implement NX-like features, allowing processes to mark memory regions as non-executable via the POSIX mprotect() interface with PROT_NONE or absent PROT_EXEC flags, thereby isolating executable code from data areas in resource-constrained environments.[53] Android derivatives build on Linux kernel NX support with additional restrictions, such as Android 10's enforcement of noexec on apps' private data directories (e.g., /data/data/<package>), preventing execution of binaries written to these areas to mitigate exploits where attackers inject code into app storage. (Note: Official Android blog reference approximated from developer announcements; direct link to archived policy change.) Gaming consoles employ custom executable-space protection tailored to their architectures, extending beyond standard OS mechanisms. The Xbox 360 implements a software-based "soft DEP" in game titles, marking non-code memory regions as non-executable at runtime despite lacking full hardware NX support, to defend against buffer overflows in user-mode code without relying solely on Windows-style DEP.[54] Similarly, PlayStation systems like the PS Vita use the ARM Cortex-A9 processor's hardware no-execute bit in conjunction with its MIPS-based userland emulation, enforcing isolated executable spaces in the kernel to prevent unauthorized code execution across the hybrid MIPS/ARM environment.[55] As of 2025, Internet of Things (IoT) systems increasingly adopt ARM TrustZone for advanced executable-space isolation, partitioning the processor into secure and non-secure worlds where executable code in the secure world remains protected from non-secure access attempts.[56] This hardware-enforced separation ensures that sensitive executables, such as cryptographic routines, operate in isolated memory regions, enhancing resilience against firmware attacks in resource-limited IoT devices.[57]Limitations and Bypasses
Inherent Limitations
Executable-space protection (ESP) implementations incur performance costs that vary by approach. Hardware-based mechanisms, such as the NX or XD bit on x86 processors, impose near-zero overhead since they rely on CPU-level page table attributes to enforce non-executability without additional runtime checks.[1] In contrast, software emulation of ESP, used in environments lacking hardware support, introduces some overhead through trap handling and permission validations.[1] Additionally, dynamic just-in-time (JIT) compilation necessitates temporary grants of execute permissions to generated code regions, complicating strict enforcement and potentially increasing vulnerability exposure during these intervals.[58] Compatibility challenges arise from ESP's rigid separation of executable and writable memory, impacting legitimate software behaviors. Self-modifying code, common in certain legacy applications or performance-critical routines, fails under strict ESP as modifications to executable regions trigger violations, often requiring exemptions or redesigns for compliance.[1] Similarly, older binaries relying on writable code segments, such as those using outdated Active Template Library (ATL) versions, may terminate unexpectedly due to non-executable data page faults, necessitating compatibility shims or opt-outs.[59] ESP provides only partial coverage across system memory, leaving certain regions unprotected by design. In the Linux kernel, for instance, loadable kernel modules and JIT-allocated areas can remain read-write-executable (RWX) unless explicitly configured with options like CONFIG_STRICT_KERNEL_RWX and CONFIG_STRICT_MODULE_RWX, which enforce stricter segmentation but still allow temporary RWX states during updates such as instruction patching.[60] User-mode protections dominate, but kernel-space enforcement remains incomplete without these enhancements, exposing potential exploitation vectors in privileged code. Fundamentally, ESP's scope is limited to preventing execution from non-executable regions and does not address code injection or memory corruption directly. It halts attempts to run injected payloads from data areas like stacks or heaps but offers no defense against the initial overwrite or leakage that enables such injections, serving as a partial rather than comprehensive safeguard.[1][61]Common Bypass Methods
One prominent technique to bypass executable-space protection (ESP) is the return-to-libc attack, which redirects program control flow to existing executable code in the C standard library (libc) without injecting new instructions. This method exploits buffer overflows to overwrite the return address on the stack, pointing it to the address of a library function like system(), followed by arguments such as a command string to execute a shell. Return-to-libc predates widespread ESP adoption but remains effective against non-executable memory regions, as it leverages pre-mapped executable library code that attackers can locate via information leaks or predictable addresses.[62] Return-Oriented Programming (ROP) represents a more sophisticated evolution, chaining short sequences of existing instructions—known as "gadgets"—ending in return statements from the program's or libraries' code segments to perform arbitrary computations. By constructing a chain of these gadgets and placing addresses on the stack, attackers achieve Turing-complete execution without writing to non-executable memory, effectively bypassing ESP mechanisms like Data Execution Prevention (DEP).[63] ROP emerged as a response to DEP's enforcement around 2007, with seminal demonstrations showing its viability against real-world binaries.[64] Despite mitigations like Address Space Layout Randomization (ASLR), ROP persists through gadgets in large codebases, enabling attackers to pivot control flow after initial exploits like buffer overflows. JIT spraying complements these approaches by exploiting just-in-time (JIT) compilers in environments like web browsers or JavaScript engines to generate large regions of predictable, executable memory. Attackers craft input that forces the JIT to compile code resembling shellcode or ROP gadgets into executable pages, which can then be jumped to despite ESP restrictions on data areas.[65] This technique simultaneously evades both ESP and ASLR by controlling the placement and content of JIT-output memory, as demonstrated in browser exploits where JavaScript arrays are sprayed with NOP-like instructions followed by payloads.[66] In contemporary threats as of 2025, advanced persistent threats increasingly employ hybrid JIT-ROP attacks, combining JIT spraying to create gadget-rich executable regions with ROP chains for precise control, often in conjunction with memory disclosure to defeat ASLR and control-flow integrity (CFI). These hybrids target JIT-heavy applications like modern web engines, where attackers first leak addresses and then chain JIT-generated gadgets for persistence or escalation. Recent defenses, such as hardware-assisted booby-trapping of memory to detect disclosure attempts in JIT-ROP scenarios, highlight the ongoing efficacy of these methods against layered mitigations in real-world scenarios.[67]References
- https://wiki.gentoo.org/wiki/Hardened/PaX_Quickstart
