Contributed by ray on from the secure-pie-operating-system dept.
PIE support changes were committed recently to gcc, csu and gdb.
These changes build on top of prior work that enhanced ld.so to grok PIE, kernel changes to recognize and load PIE binaries, converting csu asm to be pic compatible and ld.so bug fixes for some relocations.
- gcc: to add -fpie/-fPIE and -pie arguments
- csu: to compile the C Start Up objects position independent
- gdb: to add PIE debugging support
PIE stands for Position Independent Executable. It is another address space randomization technique that compiles & links executables to be position independent. When combined with a kernel that can recognize it is loading a PIE binary, the kernel can load it into a random address instead of the traditional fixed addresses programs use. By using at random load addresses it stops return-to-libc type attacks against functions in the main program.
What was recently committed are the parts needed to use PIE when the proper gcc arguments are given. It is not on by default (yet) and nothing in the tree is being linked with PIE. Work is continuing to round out the missing parts so that it can be turned on by default in the future. However, things are working for dynamically linked programs; to use it, just add the appropriate gcc arguments (more details below).
If you are interested in knowing all the gory details of how PIE was implemented on OpenBSD, take a look at my presentation or go to DCBSDCon in February where I hope to do the talk again. Instead of going over that stuff again here, let's take a look at how to use PIE.
New arguments were added to gcc to support PIE (-fpie/-fPIE and -pie). -fpie/-fPIE are similar to the gcc arguments -fpic/-fPIC in that they both create position independent objects files. However the PIE versions have one additional optimization that makes the resulting objects not suitable for shared libraries. The optimization is explained in detail in my presentation.
The -pie argument tells gcc to pass along the pie argument to the linker which understands how to build a PIE binary. When you execute the PIE binary, the kernel recognizes it and loads it at a random address. You can see the random load address by using ldd(1) or for long running processes procmap(1). For example on i386:$ cc -c -fpie hello.c -o hello.o $ cc -pie hello.o -o hello $ ldd hello hello: Start End Type Open Ref GrpRef Name 142cc000 342d0000 exe 1 0 0 hello 04774000 247a9000 rlib 0 1 0 /usr/lib/libc.so.49.0 097e8000 097e8000 rtld 0 1 0 /usr/libexec/ld.so $ ldd hello hello: Start End Type Open Ref GrpRef Name 1aecb000 3aecf000 exe 1 0 0 hello 0a0c4000 2a0f9000 rlib 0 1 0 /usr/lib/libc.so.49.0 06c3d000 06c3d000 rtld 0 1 0 /usr/libexec/ld.so $ ldd hello hello: Start End Type Open Ref GrpRef Name 1a561000 3a565000 exe 1 0 0 hello 0b8e3000 2b918000 rlib 0 1 0 /usr/lib/libc.so.49.0 06e61000 06e61000 rtld 0 1 0 /usr/libexec/ld.so
Note that you can't just put -fpie -pie into CFLAGS since these arguments are only for the objects that get linked into a program. If you use them on a shared lib you will end up with broken shared libraries.
gdb works with PIE programs, but not with core files generated from a PIE program. So you can use gdb to attach to a running PIE program or run a PIE program in gdb, but postmortem debugging of cores isn't working yet. This is one of the things that needs to be worked on for better supporting PIE.
Another area that needs work is static PIE programs. Currently -pie -static is disabled because the resulting binary is not quite a static program. It still needs ld.so to run which means it can't be run in single user mode too.
While I've been the primary developer moving this along, I couldn't have accomplished it without the help, guidance and reviews of drahn@, kettenis@, miod@, weingart@ and other developers who gave me access to hardware or tested my diffs. Thank them for putting up with my silly PIE diff names too.
Thanks Kurt for all the hard work baking the PIE diffs, and also for this write up!
(Comments are closed)