Hardened/PaX flag migration from PT PAX to XATTR PAX

A quick guide on migrating PaX flags from PT_PAX to XATTR_PAX.

Before you start reading!
This page is a quick howto on migrating from PT_PAX to XATTR_PAX flags. It presupposes the reader knows what PaX is all about. See our Pax Quickstart for a broad coverage. For an in-depth explanation of how PaX works, see the Homepage of The PaX Team.

The three ways of marking PaX flags: EI_PAX, PT_PAX and XATTR_PAX
PaX provides various protections against abuses of memory. Some of these protections can only be enabled or disabled by (re)configuring the kernel and recompiling/rebooting. However a few important ones (PAGEEXEC, EMUTRAMP, MPROTECT, RANDMMAP and SEGMEXEC) can be tweaked when the system is up and running by marking the PaX flags on the ELF objects of the program you want to run. Since some programs need to use memory in a way normally forbidden by PaX, we may have to relax some restrictions on a per program basis.

Historically, the PaX flags have been stored in one of three different locations. At first, they were housed in the ELF header of the objects (EI_PAX), but this broke with updates to glibc. They were next moved to an ELF program header (PT_PAX) and this was mostly satisfactory, except for those occassion programs where adding such a header was problematic for one reason or another. The next generation places the flags in the extended attributes of the filesystem(s). As long as all the filesystems and the utilities working with those files/filesystems respects the extended attributes, this is the best solution because it essentially does not touch the ELF binaries themselves.

Migrating from PT_PAX to XATTR_PAX
Marking the ELF header (EI_PAX) has been completely deprecated in Gentoo. If you have an ancient system which still uses EI_PAX, then its probably so broken by this point that no migration is possible anyhow. Start over.

Marking the ELF program header (PT_PAX) is still supported, but that support will slowly disappear. As of glibc-2.16, the elf.h header file will no longer contain the definitions of the PT_PAX_FLAGS program header, nor of the values of the PaX flags that live there. At some point in the future, the patch against binutils which includes the PT_PAX_FLAGS program header will also go. At that point only XATTR_FLAGS will remain. You might want to get ahead of the game and migrate now.

The process of migration is safe because at no point will we actually dump the PT_PAX flags, so we can always revert if something goes wrong. The essential caveat to remember is that the kernel ultimately decides whether to use PT_PAX or XATTR_PAX (or both). So you can have both markings on an ELF object and have the kernel read one and ignore the other. Note that if you enable both PT_PAX and XATTR_PAX in the kernel, and you create an XATTR_PAX field, then the kernel expects both fields to be identical, otherwise neither is respected. It is okay to enable both fields provided you don't create XATTR_PAX; then, the PT_PAX field is fully respected. We can use this as part of the migration; but in general, we do not recommend setting both unless there is a good reason. Just switch from one to the other, i.e. PT_PAX xor XATTR_PAX.

So, starting from a stock PT_PAX system, you can migrate to XATTR_PAX as follows:

1. Userland preliminaries:

First, let's make sure that your userland utilities can handle extended attributes in general and XATTR_PAX in particular. If they cannot, then either the XATTR_PAX markings will fail or they'll get lost as we pack/unpack our ELF objects, for example, when using tar. So,
 * a. make sure you set USE=xattr in your global USE flags, and
 * b. emerge >=sys-apps/elfix-0.8.1 without disabling either ptpax or xtpax USE flags.
 * c. add PAX_MARKINGS="XT" in the file.

2. Kernel preliminaries:

As you do the migration, you must make sure your filesystem can accomodate extended attributes, including tmpfs! If your kernel hasn't been already so configured, do so now and reboot into it. Choosing PAX_XATTR_PAX_FLAGS under the PaX kernel menu will automatically set extended attributes on as many filesystems as can support them. Remember, you can enable both PT_PAX and XATTR_PAX in the kernel at this point, and PT_PAX will be respected until you create XATTR_PAX fields on the target binaries. We'll tolerate this as a transition, but we recommend using only XATTR_PAX afterward.

3. Migrate the flags:

The elfix package comes with migrate-pax. Running it with the -m flag will copy the PT_PAX flags to XATTR_PAX for every ELF object that portage knows about, except for those object which have the default flags. Since a kernel configured to use only XATTR_PAX will fall back on the default flags when no XATTR_PAX field is found, there is no reason to create such a field when the default flags are desired. Running  is very safe and you can easily undo it by running.

4. Boot into an XATTR_PAX only kernel:

You can now boot into a pure XATTR_PAX kernel. Make sure PT_PAX is off. Even though the flags should be the same in both fields, or XATTR_PAX absent in the case of default flags, we will be on the side of caution and keep control over the effective flags by using only XATTR_PAX.

5. Profit!

If you really want to make sure it worked, the elfix package comes with some test suites. These are tricky to use correctly because if you have the wrong combination of PT_PAX versus XATTR_PAX userland/kernel configurations, you'll get a lot of false failures. The next section shows you how to test.

Testing whether the migration worked and XATTR_PAX flags are respected
So did the migration work? And is the kernel recognizing XATTR_PAX markings? You can verify that the migration worked by spot checking with paxctl-ng. Try something like the following:

To check if the kernel is recognizing XATTR_PAX markings, we'll use a test suite from the package. We'll have to checkout the git repo since the ebuild doesn't run tests. They are tricky and can give lots of false negatives if you don't have the right combination of PT_PAX versus XATTR_PAX in both userland and kernel. You can proceed as follows:

{{RootCmd|git clone git://git.overlays.gentoo.org/proj/elfix.git
 * cd elfix
 * ./autogen.sh
 * ./configure --disable-ptpax --enable-xtpax --enable-tests
 * make
 * cd tests/pxtpax/
 * ./daemontest.sh|output=

=
=================================================================== RUNNING DAEMON TEST NOTE: 1) This test is only for amd64 and i686  2) This test will fail on amd64 unless the following are enabled in the kernel: CONFIG_PAX_PAGEEXEC CONFIG_PAX_EMUTRAMP CONFIG_PAX_MPROTECT CONFIG_PAX_RANDMMAP 3) This test will fail on i686 unless the following are enabled in the kernel:       CONFIG_PAX_EMUTRAMP        CONFIG_PAX_MPROTECT        CONFIG_PAX_RANDMMAP        CONFIG_PAX_SEGMEXEC ................................................................................ ................................................................................ ................................................................................ ... Mismatches = 0

=
=================================================================== }}

No mismatches! It worked. What the test is doing is marking a daemon with every possible combination of PaX flags, starting it, checking if its running with the expected flags, and reporting. If you want to have fun with this, try enabling PT_PAX and disabling XATTR_PAX when you configure elfix, but keep only XATTR_PAX support in the kernel. It will fail miserably as no PaX flags are respected.