PaX
Related articles
PaX is developed as a subset of the grsecurity patches, and is included in the linux-grsec package in the official repositories. It is also available in the standalone linux-paxAUR package in the AUR.
PaX contains most of the grsecurity mitigations against memory corruption exploits. It hardens the kernel and userspace processes in many ways, including improved address space layout randomization, strengthening the separation between kernel and userspace code / data and wiping out various classes of information leaks. The kernel hardening features have no user-facing impact, but the MPROTECT / RANDMMAP mitigations require making exceptions for some applications.
Using PaX alone is not recommended as the synergies with other grsecurity features are important. For example, defeating even the improved PaX ASLR is trivial without the GRKERNSEC_PROC_MEMMAP feature if the attacker has filesystem access.
Contents
Installation
The Pax subset is installed with the linux-grsec package; however, it is set to soft mode by default, meaning it is opt-in rather than opt-out.
The recommended way to switch to opt-in is to install the paxd package.
It is also possible to temporarily disable soft mode:
# kernel.pax.softmode=0
Note that this will only work until the next reboot.
Performance
Tunable parameters
The pax_sanitize_slab=0
option can be set on the kernel line to disable slab object sanitization. This will increase the risk of information leaks from the kernel, while reducing the performance hit from CONFIG_PAX_MEMORY_SANITIZE
(~3% for a kernel compile by default).
The pax_nouderef
option can be set on the kernel line to disable UDEREF. It is cheap on i686 since it takes advantage of memory segmentation but can cause serious performance issues with some virtualization environments. On x86_64, there are 3 implementations of UDEREF:
- slow / weak legacy implementation (~10% slower kernel compile)
- strong implementation on Sandy Bridge and later (default when supported, use
nopcid
to use the legacy implementation) - fast / weak implementation on Sandy Bridge and later (pass
pax_weakuderef
to use it)
Custom kernel
Building a custom kernel allows full control over the compromise between performance and security. The pre-built linux-grsec package prioritizes security over performance. On i686, disabling CONFIG_PAX_MEMORY_SANITIZE
and CONFIG_PAX_MEMORY_STACKLEAK
will make the performance hit negligible. On x86_64, disabling those options along with CONFIG_PAX_MEMORY_UDEREF
will do the same, although pax_nouderef
also exists at runtime as documented above.
PaX exceptions
Some of the PaX exploit mitigations prevent certain applications from running and require the executables to be marked with exceptions. The MPROTECT feature is by far the most common source of issues, and linux-grsec defaults to logging violations to the kernel log. It is more difficult to identify these issues with PaX installed on a vanilla kernel.
Extended attributes can be used to exclude executables from one or more of the features. This can be done in multiple ways.
Using the paxd daemon
The paxd package provided in the official repositories includes a daemon that automatically applies PaX exceptions from /etc/paxd.conf
whenever an executable is updated or the configuration file is modified. This is the officially supported way of applying these exceptions for binaries provided by packages. To start / enable the daemon:
# systemctl start paxd # systemctl enable paxd
User exceptions
paxd also provides a user service so that individual users can apply exceptions, primarily to files in their home directory. It can be started / enabled with systemctl --user
and will apply exceptions from $XDG_CONFIG_HOME/paxd.conf
(falling back to ~/.config/paxd.conf
).
Manually
The setfattr command can be used to manually set exclusions for a problematic binary. For example, to disable the MPROTECT and RANDMMAP features:
$ setfattr -n user.pax.flags -v "emr" /usr/bin/problematic_binary
The pax-utils package includes some useful tools. For example, the pspax
utility can display PaX permissions from the kernel's perspective along with capabilities. The scanelf
tool can be used to query attributes of binaries.
One might also use getfattr to retrieve extended attributes set above (or set by paxd described above) if they choose not to run pax-utils or if they want to check the attributes of a process not running:
$ getfattr -n user.pax.flags /usr/bin/problematic_binary
Soft mode
Setting kernel.pax.softmode=1
with sysctl will result in the mitigations being opt-in rather than opt-out. This could be used to apply the mitigations only to certain high-risk binaries such as web services on a server without causing any issues. However, opting out of the mitigations results in a significantly more secure system and paxd takes care of nearly all the work automatically.
Testing the userspace features
The paxtest tool can be used to test the userspace exploit mitigation features. Note that the UDEREF self-protection feature shrinks the address space on x86_64, reducing the entropy available for randomization. It's an extremely important feature and outweighs the minimal gain from the additional entropy.
Vanilla kernel (x86_64)
Executable anonymous mapping : Killed Executable bss : Killed Executable data : Killed Executable heap : Killed Executable stack : Killed Executable shared library bss : Killed Executable shared library data : Killed Executable anonymous mapping (mprotect) : Vulnerable Executable bss (mprotect) : Vulnerable Executable data (mprotect) : Vulnerable Executable heap (mprotect) : Vulnerable Executable stack (mprotect) : Vulnerable Executable shared library bss (mprotect) : Vulnerable Executable shared library data (mprotect): Vulnerable Writable text segments : Vulnerable Anonymous mapping randomisation test : 28 quality bits (guessed) Heap randomisation test (ET_EXEC) : 13 quality bits (guessed) Heap randomisation test (PIE) : 28 quality bits (guessed) Main executable randomisation (ET_EXEC) : 28 quality bits (guessed) Main executable randomisation (PIE) : 28 quality bits (guessed) Shared library randomisation test : 28 quality bits (guessed) VDSO randomisation test : 20 quality bits (guessed) Stack randomisation test (SEGMEXEC) : 30 quality bits (guessed) Stack randomisation test (PAGEEXEC) : 30 quality bits (guessed) Arg/env randomisation test (SEGMEXEC) : 22 quality bits (guessed) Arg/env randomisation test (PAGEEXEC) : 22 quality bits (guessed) Randomization under memory exhaustion @~0: 28 bits (guessed) Randomization under memory exhaustion @0 : 28 bits (guessed) Return to function (strcpy) : paxtest: return address contains a NULL byte. Return to function (memcpy) : Killed Return to function (strcpy, PIE) : paxtest: return address contains a NULL byte. Return to function (memcpy, PIE) : Killed
PaX kernel (x86_64 without UDEREF)
Executable anonymous mapping : Killed Executable bss : Killed Executable data : Killed Executable heap : Killed Executable stack : Killed Executable shared library bss : Killed Executable shared library data : Killed Executable anonymous mapping (mprotect) : Killed Executable bss (mprotect) : Killed Executable data (mprotect) : Killed Executable heap (mprotect) : Killed Executable stack (mprotect) : Killed Executable shared library bss (mprotect) : Killed Executable shared library data (mprotect): Killed Writable text segments : Killed Anonymous mapping randomisation test : 33 quality bits (guessed) Heap randomisation test (ET_EXEC) : 22 quality bits (guessed) Heap randomisation test (PIE) : 40 quality bits (guessed) Main executable randomisation (ET_EXEC) : 33 quality bits (guessed) Main executable randomisation (PIE) : 33 quality bits (guessed) Shared library randomisation test : 33 quality bits (guessed) VDSO randomisation test : 33 quality bits (guessed) Stack randomisation test (SEGMEXEC) : 40 quality bits (guessed) Stack randomisation test (PAGEEXEC) : 40 quality bits (guessed) Arg/env randomisation test (SEGMEXEC) : 44 quality bits (guessed) Arg/env randomisation test (PAGEEXEC) : 44 quality bits (guessed) Randomization under memory exhaustion @~0: 33 bits (guessed) Randomization under memory exhaustion @0 : 33 bits (guessed) Return to function (strcpy) : paxtest: return address contains a NULL byte. Return to function (memcpy) : Killed Return to function (strcpy, PIE) : paxtest: return address contains a NULL byte. Return to function (memcpy, PIE) : Killed
PaX kernel (x86_64 with UDEREF)
Executable anonymous mapping : Killed Executable bss : Killed Executable data : Killed Executable heap : Killed Executable stack : Killed Executable shared library bss : Killed Executable shared library data : Killed Executable anonymous mapping (mprotect) : Killed Executable bss (mprotect) : Killed Executable data (mprotect) : Killed Executable heap (mprotect) : Killed Executable stack (mprotect) : Killed Executable shared library bss (mprotect) : Killed Executable shared library data (mprotect): Killed Writable text segments : Killed Anonymous mapping randomisation test : 29 quality bits (guessed) Heap randomisation test (ET_EXEC) : 22 quality bits (guessed) Heap randomisation test (PIE) : 35 quality bits (guessed) Main executable randomisation (ET_EXEC) : 29 quality bits (guessed) Main executable randomisation (PIE) : 29 quality bits (guessed) Shared library randomisation test : 29 quality bits (guessed) VDSO randomisation test : 29 quality bits (guessed) Stack randomisation test (SEGMEXEC) : 35 quality bits (guessed) Stack randomisation test (PAGEEXEC) : 35 quality bits (guessed) Arg/env randomisation test (SEGMEXEC) : 39 quality bits (guessed) Arg/env randomisation test (PAGEEXEC) : 39 quality bits (guessed) Randomization under memory exhaustion @~0: 29 bits (guessed) Randomization under memory exhaustion @0 : 29 bits (guessed) Return to function (strcpy) : paxtest: return address contains a NULL byte. Return to function (memcpy) : Killed Return to function (strcpy, PIE) : paxtest: return address contains a NULL byte. Return to function (memcpy, PIE) : Killed