Address space layout randomization helps to protect against buffer overflow attacks as it becomes harder for an attacker to turn a programming error into an exploitable security hole. The first implementation for Linux is 15 years old. Support in mainline kernel and toolchains have been available for a good while now. But to work, ASLR also needs executables to be built as position independent. And as Hanno Böck from the fuzzing project gently reminded me at 32C3, almost no executables in Debian are built as such, while it is now the default in Windows, Mac OS X, OpenBSD, and Fedora to name just a few other systems.

PIE has the reputation of having a performance hit. While true, especially for register constrained architectures like i386, it makes a difference only for the executable itself, not any shared library it uses as they are already built as position independent. Also, several optimizations have been made since the early days. GCC 5 will reuse the PIC hard register (which is also good for libraries). On amd64, GCC 5 and binutils 2.26 will do copy relocations. More improvements for i386 are being worked on.

I sincerly believe that users are way more likely to notice a compromised system than a slightly slower one.

Tracking progress

Since version 2.5.40, lintian will now issue a warning1 when it detects that a binary has not been compiled as a position independent executable. Kudos to Niels Thykier. Now that we can track our progress, I'm calling every Debian Developers: let's try to get as many ASLR-compatible executables in Stretch!

How to enable PIE

Thanks to all contributors over the past years who have improved our toolchain, we now have a fairly easy way to enable hardening flags with dpkg-buildflags. For packages using dh, it now boils down with adding on top of debian/rules:

export DEB_BUILD_MAINT_OPTIONS = hardening=+all

You can even test if a package supports all hardening flags without any changes running DEB_BUILD_OPTIONS=hardening=+all dpkg-buildpackage. Running lintian or hardening-check can then tell you if the protections have been successfully enabled.

Hardening by default?

But do we really need to change so many packages individually? The difference between the current default features and all hardening features are pie and bindnow. Could we turn them by default and do binNMUs instead of requiring actions from maintainers?

I guess the question boils down to: how many packages would require a (one-liner) change to turn off the pie or bindnow features if they were on by default?

To get the beginning of an answer, I took the top 502 (according to popcon installations) source packages shipping non-position independent executables. I've try to rebuild them enabling all hardening flags through DEB_BUILD_OPTIONS.

Out of 49 packages3:

  • 32 (65%) built fine and produced PIE binaries: acpi, bc, bind9, bsd-mailx, bsdmainutils, bzip2, cpio, cron, debianutils, diffutils, dpkg, file, fontconfig, gettext, glib2.0, glibc, gnupg, gzip, hostname, ifupdown, iputils, logrotate, m4, mutt, nano, net-tools, netcat, netkit-ftp, netkit-telnet, os-prober, pam, util-linux.
  • 4 (8%) built fine but did not compiled hardened binaries: discover, mawk, mlocate, patch.
  • 13 (27%) failed to build, with some of these expected failures, e.g. for *-static or GRUB: bash, busybox, coreutils, e2fsprogs, grub2, insserv, iptables, kbd, ncurses, newt, openssl, pciutils, perl.

The results are really encouraging. Especially taking in account that some of these packages are part of the “tricky and weird” set. To know for sure, we would need a mass-rebuild of the archive with DEB_BUILD_OPTIONS=hardening=+all in the environment. Any takers?

  1. Verification of the whole archive by the latest version of lintian is still in progress by the time I'm writing these lines. According to Niels it should take 3-4 more days to look at all available packages. ↩

  2. As always, UDD does wonders:

    SELECT packages.source, MAX(popcon.insts) AS insts
      FROM lintian, popcon, packages
     WHERE lintian.tag = 'hardening-no-pie'
       AND lintian.package_arch = 'amd64'
       AND popcon.package = lintian.package
       AND packages.package = popcon.package
       AND packages.distribution = 'debian'
       AND packages.release = 'sid'
     GROUP BY packages.source
     ORDER BY MAX(popcon.insts) DESC
     LIMIT 50;
  3. acpid currently fail to build from source in sid. ↩