I figure I should break in my first post, that I'm now a Kubuntu member, and through that, also an Ubuntu member, and thus can post to Ubuntu Planet now :-).
For all of those out there who helped make this possible, thank you. Next stop, MOTU.
Friday, September 12, 2008
Saturday, September 6, 2008
PIE GCC stage two bootstrapping notes ...
I figure I haven't explained what I'm doing at this point. I'm currently compiling GCC with a patch to have both it be PIC/PIE, and generate PIE binaries, a rather fun task requiring multiple compiler bootstraps, but should allow me to properly test the ability to compile the system PIE enabled. I suspect I can convince kees to see if all this bootstrapping isn't necessary and can generate comparable results to my test builds.
Roughly speaking, the sequence of events that I'm following goes something like this.
1. Build a compiler that generates PIC code by default from a non-PIC system (embyro compiler)
2. Use the PIC compiler to compile glibc, gcc/binutils depends (zlib, gmp, mpfr)
3. Build a compiler with the previous compiler to build a compiler that can generate PIE binaries. This will be used to build the equivelent of a Gentoo stage1 system. <- We are here
4. Build a temporary base system.
5. Using the PIE compiler, rebuild the base system with the proper paths (butterfly compiler).
6. Build Ubuntu specific tools (dpkg, apt, etc.)
7. Build Ubuntu base system with GCC patchs, generating debs
8. Using those debs, rebuild the base system again
Roughly speaking, the sequence of events that I'm following goes something like this.
1. Build a compiler that generates PIC code by default from a non-PIC system (embyro compiler)
2. Use the PIC compiler to compile glibc, gcc/binutils depends (zlib, gmp, mpfr)
3. Build a compiler with the previous compiler to build a compiler that can generate PIE binaries. This will be used to build the equivelent of a Gentoo stage1 system. <- We are here
4. Build a temporary base system.
5. Using the PIE compiler, rebuild the base system with the proper paths (butterfly compiler).
6. Build Ubuntu specific tools (dpkg, apt, etc.)
7. Build Ubuntu base system with GCC patchs, generating debs
8. Using those debs, rebuild the base system again
Thursday, September 4, 2008
A Look At the Specs ...
(warning: GCC internals ahead. For ye who wishes to stay sane, stay away, stay very far away)
Part of the major changes hardy->intrepid was the inclusion of hardening configurations in GCC. This was originally handled via a script called hardening-wrapper, which using the alternates system to replace GCC with a wrapper script, which passed a variety of options (see the wiki for the full list) and was controllable via environmental variables.
After intrepid, all of these options (aside from PIE) was moved into GCC specifically via the spec mechanism. For those unaware, GCC (and binutils) is essentially several smaller programs, such as the C preprocessor, cc1, assembler, linker, etc. The specs strings is essentially a rules system that controls the arguements to each of these mini programs. Lets take a more specific look at these strings. You can view the gcc specs can be viewed with gcc -dumpspecs
(Ubuntu GCC 4.3.1 Intrepid Alpha, for beverity sake, here's just a small section)
*cpp_unique_options:
%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}} %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{fmudflap:-D_MUDFLAP -include mf-runtime.h} %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h} %{!D_FORTIFY_SOURCE:%{!D_FORTIFY_SOURCE=*:%{!U_FORTIFY_SOURCE:-D_FORTIFY_SOURCE=2}}} %{E|M|MM:%W{o*}}
While this appears to a load of messy strings, it defines the command line arguements GCC accepts, and what it does. The last section for instance was added in Ubuntu to add the FORTIFY_SOURCE defines, as well as include the offswitch for it. Adding the PIE switch would be done under the cc1 section which is what handles the PIE processing, in a similar mechanism. This way, we can apply PIE to every package, and then manually add -fno-PIE on any package that requires it to be disabled.
This is a quick overview of specs, and I hope you learned something by reading it, and understanding how this will be done.
Part of the major changes hardy->intrepid was the inclusion of hardening configurations in GCC. This was originally handled via a script called hardening-wrapper, which using the alternates system to replace GCC with a wrapper script, which passed a variety of options (see the wiki for the full list) and was controllable via environmental variables.
After intrepid, all of these options (aside from PIE) was moved into GCC specifically via the spec mechanism. For those unaware, GCC (and binutils) is essentially several smaller programs, such as the C preprocessor, cc1, assembler, linker, etc. The specs strings is essentially a rules system that controls the arguements to each of these mini programs. Lets take a more specific look at these strings. You can view the gcc specs can be viewed with gcc -dumpspecs
(Ubuntu GCC 4.3.1 Intrepid Alpha, for beverity sake, here's just a small section)
*cpp_unique_options:
%{C|CC:%{!E:%eGCC does not support -C or -CC without -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*&F*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}} %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{fmudflap:-D_MUDFLAP -include mf-runtime.h} %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h} %{!D_FORTIFY_SOURCE:%{!D_FORTIFY_SOURCE=*:%{!U_FORTIFY_SOURCE:-D_FORTIFY_SOURCE=2}}} %{E|M|MM:%W{o*}}
While this appears to a load of messy strings, it defines the command line arguements GCC accepts, and what it does. The last section for instance was added in Ubuntu to add the FORTIFY_SOURCE defines, as well as include the offswitch for it. Adding the PIE switch would be done under the cc1 section which is what handles the PIE processing, in a similar mechanism. This way, we can apply PIE to every package, and then manually add -fno-PIE on any package that requires it to be disabled.
This is a quick overview of specs, and I hope you learned something by reading it, and understanding how this will be done.
More progress ...
After further research, I attempted to use Linux from Scratch as a base for my attempts to compile the base system. This lead me to High Security LFS, which is the base chroot built with PIE, which is what I want. I can't find anyone who's done HLFS on amd64, so it will be rather interesting to see how well this works.
GCC sucks.
On my quest to build the archive with PIE, I discovered the first major headache, is that there is a rather interesting circular dependency in the compiler toolchain.
Roughly speaking, libgcc is linked to to glibc, which is linked to libgmp, which the compiler is dependent on, making it not possible to directly build the compiler built with PIE (and as an additional fun fact, the three stage bootstrap makes hardened wrapper non-effective. CFLAGS can be passed to the second and third stage bootstrap so this isn't a huge limitation, but it will regular beating gcc's debain/rules2 into passing the flags correctly. I'm now at the point roughly where I can try to build perl from source, then dpkg and aptitude.
Roughly speaking, libgcc is linked to to glibc, which is linked to libgmp, which the compiler is dependent on, making it not possible to directly build the compiler built with PIE (and as an additional fun fact, the three stage bootstrap makes hardened wrapper non-effective. CFLAGS can be passed to the second and third stage bootstrap so this isn't a huge limitation, but it will regular beating gcc's debain/rules2 into passing the flags correctly. I'm now at the point roughly where I can try to build perl from source, then dpkg and aptitude.
The -fPIE is a lie. Part 1
For those playing along at home, I've been working with Kees Cook (from Canonical), on investigating the possibility of generating Position Independent Executables for the AMD64 architecture which would greatly help increase security for Ubuntu.
Position independent code roughly means that there are no hard coded addresses in the binary, making a return-to-libc attack near impossible when combined with address space randomization, a technique that causes binaries and libraries to be loaded in random locations in memory. The upshot is that on 64-bit systems, even if a buffer overflow or other programming bug makes it possible to override the stack, a return-to-libc attack can't be done due to the randomized address space. Stack smashs and buffer overflows are of course properly avoided alrady in Ubuntu due to the stack protector.
Now some people may be wondering why we're not doing this for x86. The reason is that there is a price to be paid by PIE code and that is that a register must be used to handle the locations and relative jumps in the executable. x86 has very few general purpose registers that could be used for this, and thus has a rather large cost. Architectures such as ia64, amd64, powerpc, and sparc have more than enough general registers to make the change fessiable without aversily affecting performance.
Currently, I'm working on building a base chroot completely PIE enabled, and then rebootstrapping Ubuntu from scratch, a laborous, but hopefully successful attempt at rebuilding the archive with PIE.
Position independent code roughly means that there are no hard coded addresses in the binary, making a return-to-libc attack near impossible when combined with address space randomization, a technique that causes binaries and libraries to be loaded in random locations in memory. The upshot is that on 64-bit systems, even if a buffer overflow or other programming bug makes it possible to override the stack, a return-to-libc attack can't be done due to the randomized address space. Stack smashs and buffer overflows are of course properly avoided alrady in Ubuntu due to the stack protector.
Now some people may be wondering why we're not doing this for x86. The reason is that there is a price to be paid by PIE code and that is that a register must be used to handle the locations and relative jumps in the executable. x86 has very few general purpose registers that could be used for this, and thus has a rather large cost. Architectures such as ia64, amd64, powerpc, and sparc have more than enough general registers to make the change fessiable without aversily affecting performance.
Currently, I'm working on building a base chroot completely PIE enabled, and then rebootstrapping Ubuntu from scratch, a laborous, but hopefully successful attempt at rebuilding the archive with PIE.
Well, here I am. Blogging.
I was rather shocked to discover I had a blog on blogger (empty, of course). I figured with my recent work with Ubuntu and Debian, it might be worth having a blog so people can follow a long with home. Well, I guess this is it for now.
Subscribe to:
Posts (Atom)