2.6. Position Independent Executables

Position-Independent-Executable is a feature of Binutils, Libc, and GCC that creates an executable which is something between a shared library and a normal executable. Programs compiled with these features appear as “shared object” with the file(1) command. This allows the executable to behave like a shared library so base addresses can be relocatable. The PIE program must be linked to Scrt1.o. Scrt1.o is available from the newer versions of Libc. Furthermore these programs must be linked with the -pie ld(1) command from a Binutils version 2.15 or later. GCC supports this natively with the -fPIE switch in version 3.4 or later.

When all of the object code is position independent the kernel can disallow text relocation. This dramatically increases the security of the system with little performance loss. PaX and Grsec kernels have this option available though very few systems have been able to take advantage of it. The entire base system can be built position independent with the exception of the Grub boot loader, and Glibc's utilities due to non-pic assembly code. These programs will still function if they are dynamically linked. Other exceptions are X11 windowing system, Mplayer, and a few other graphical programs which were not programed with PIE in mind, this should come in time. Gzip uses assembly code which is not position independent, but this can be omitted at compile time and Gzip will use only C code.

PaX can also randomize the return addresses of PIE programs with Address Space Layout Randomization (ASLR). This can prevent security bugs from being taken advantage of by attackers.

You can search for text relocation in programs with the following command:

readelf -d /path/to/object | grep TEXTREL

It is possible for TEXTREL to be present in both executable programs and libraries. Further debugging is needed to find the specific code that is not position independent, it is most often assembly. If a program errors at compile time with 'ASM' and 'BREG' in the message, this is non-pic assembly.

The coreutils uname patch from LFS also uses assembly code which is not position independent.

The man page for ld has a description for -pie. See man 1 ld.

Use the NOELFRELOCS in PaX or Grsec kernel options to disable text relocation.

The fPIE flag can only be passed to executables, not libraries. The fPIE flag gives some advantages over fPIC in that the compiler can assume the code will stay local to the program. This translates into optimizations having a greater effect; non-static functions can be inlined at -O3, etc. The hardened-specs used in the book adds filters to the GCC link_command spec to distinguish executables from libraries, so the ld -pie switch is only passed when linking executables. The same filters can not be used for cc1, so the cc1 spec passes -fPIC instead of -fPIE to everything unless the -static or -no-pie flags are used. Using gcc -fPIC with ld -pie works fairly well, all the PaX/Grsec kernel features will be able to have full advantages. fPIE is known to cause text relocation in some programs, so it must be used with care. In this book we patch some programs, and use sed(1) commands on others, to add gcc -pie -fpie on program executables. fPIE must be added surgically, and not to environment cflags. The hardened-specs preserves the vanilla gcc -pie behaviour, meaning if you use gcc -pie neither -fpic nor -fpie will be automatically added, so both -pie -fpie must be used together (as per the gcc man page). gcc -pie affects which startfiles are used (Scrt.o), so it must be used in conjuction with ld -pie. Almost all packages use GCC to do linking, so setting environment ldflags is almost never needed.

Beyond the packages in this book the hardened-specs will work perfectly fine with -fPIC. If you wish to use -fPIE to have greater optimization be sure to use readelf -d to check for TEXTREL. If -fPIE is passed to one object in a library it will cause a TEXTREL section in that library, and it will not work correctly. Libraries, private or otherwise, need to be compiled with -fPIC.

On x86 systems -fPIC and -fpic are exactly the same. Ditto with -fPIE and -fpie.

See also: