Home / Blog / Kernel and exploits

A history of PaX: the hardening project that predicted modern exploit mitigations

PaX 的技术考古之旅

First published Jun 2014•Rewritten Nov 2026•Kernel and exploits Papers

PaX is a hardening patch for the Linux kernel, first designed around 2000, built around enforcing the principle that a given memory page should not be both writable and executable at once. It predates the mainstream adoption of the mitigations it inspired by several years.

Origins in a hardware quirk

The earliest work behind PaX grew out of an observation about how certain x86 processors cached page-table permission information separately for instruction fetches and for data accesses. Because those two caches could, under the right conditions, be made to disagree about whether a given page was executable, it was possible to construct a software technique that enforced a strict separation between writable and executable memory, years before processors added native hardware support for that distinction. That software technique became the ancestor of what is now called NX, non-executable memory, which eventually arrived as a hardware feature and was adopted across every major operating system.

Looking ahead from 2003

By 2003, with its core memory-protection approach already established, the project's own internal notes described a framework for categorising how a memory-corruption bug could be turned into exploitation: running attacker-supplied code outright, hijacking existing code to run out of its intended order, or running existing code in its intended order but feeding it attacker-controlled data. That framework mapped cleanly onto defences that didn't widely exist yet, address-space layout randomisation to make the second and third categories unreliable, and non-executable memory to block the first outright. Both ideas were already implemented inside the patch years before other major operating systems shipped equivalents.

A patch that stayed outside the mainline kernel

Despite its influence, PaX itself was never merged into the mainline Linux kernel; the kernel community instead built a more general module-based security framework that let other projects implement access-control policies as loadable modules. The PaX and Grsecurity developers maintained their work as a separate, out-of-tree patch set instead, continuing to add new protections over the following decade.

Why it matters

Reading through a hardening project's early design notes is a useful exercise even now: most of the exploit-mitigation landscape still in use today, from address randomisation to non-executable memory to stack protections, traces back to ideas this project worked out, and often shipped, before they became industry standard. Understanding why those mitigations exist, and what specific exploitation technique each one was built to block, is still directly useful when assessing whether a target's current hardening configuration is actually effective.

Key takeaways

  • PaX's core non-executable-memory idea grew out of a quirk in how early x86 CPUs cached instruction versus data page permissions
  • PaX implemented software equivalents of NX and ASLR years before those became standard hardware or OS features
  • A 2003 internal framework classified exploitation into three categories: attacker code execution, reordered existing code, and existing code fed attacker-controlled data
  • PaX was never merged into the mainline Linux kernel; it has always been maintained as a separate patch set
  • Knowing which specific exploitation technique each mitigation was designed to block helps when judging whether a hardening configuration is actually effective

This note has been rewritten and checked for this edition; it is not a copy of the original post.