10

Write xor Execute (W^X) is a policy that a block (page) of memory cannot be marked as both writeable and executable at the same time.

What attacks does W^X prevent, with and without the following:

  • Address Space Layout Randomization (ASLR)
  • Data Execution Prevention (DEP)
  • Once-writeable, never executable - page can never be marked as executable after being marked as writeable.
Polynomial
  • 132,208
  • 43
  • 298
  • 379

1 Answers1

7

W^X and "Once-writable, never executable" are both sub-cases of DEP. DEP is about making read accesses, and execution accesses, distinct (a writable page is also a readable page). W^X is about using DEP to enforce a specific policy, which is that a given page can never be writable and executable at the same time.

Compliance to the W^X policy can be required from the programmer because writing "data" and then executing it reliably entails flushing some caches, which is an explicit and expensive operation. Going through the kernel (with a mprotect() call) is not a hard way to do that. On the other hand, forcing the programmer to do such things explicitly means that it will not happen in other situations, namely when an attacker tries to exploit a buffer overflow. This is a generalization of the "stack is not executable" feature. (The buffer overflow is still there, though; W^X just makes life harder for the attacker.)

The "once-writable, never executable" policy looks suspicious to me: it is incompatible with JIT compilers. Anyway, it would be a sub-case of W^X: like W^X, in which the transition W->X is forbidden.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • I've come across `W!->X` in a grsec hardened kernel build. They create a list of pages that have been marked as writeable, then prevent kernel-level memory protection modification functions from changing the flags to include executable. When an allocation is released, the page is removed from the list. – Polynomial Aug 20 '12 at 21:03
  • I suspect `W!->X` might be feasible for many applications, but not all of them: it's not something that could be applied across the board to every application. (But perhaps you could make it a default and allow applications that use a JIT to opt out.) It might also be feasible for the kernel, as Polynomial writes. I don't mean to disagree with anything ThomasPornin wrote, just elaborating a bit. – D.W. Aug 21 '12 at 06:45