On 19 December 2014 at 00:31, Daniel Micay <danielmicay@gmail.com> wrote:
Arch's single biggest security weakness is that it's not benefiting from address space layout randomization (ASLR). Fixing this issue would be a major step towards being a leader in this area. Many distributions enable ASLR, stack protector, etc. for a chosen set of "security critical" stuff but very few enable them across the board.
Executable permissions on memory (NX bit) prevent an attacker from directly injecting code via memory corruption vulnerabilities. It's only truly useful in combination with ASLR because if the existing code is in a known location it can be reused by the attacker.[1]
[1] https://en.wikipedia.org/wiki/Return-oriented_programming
The cost of ASLR is that it requires position independent (relocatable) code (PIC), as is already required for all code in dynamic libraries.
On i686, PIC has a significant cost (up to 30% or more). The vanilla kernel also lacks emulation of the NX bit and has no brute force protection to make up for the smaller 32-bit address space. Only the subset of users using grsecurity / PaX would truly benefit. I don't care about i686 anyway.
On x86_64, there's hardware support for position independent code so it's essentially free. It does currently cost ~1% due to linker and compiler limitations (indirection to access globals) but this has been fixed in the binutils/gcc master branches. It's much cheaper than the -fstack-protector-strong switch which we're already using, and the security value is higher.
The only real barrier to enabling it is the lack of support in GCC for simply flipping it on by default. Library code is already built with -fPIC and is then linked with -shared. Full ASLR requires building the executable code with -fPIE (or -fPIC, which isn't as cheap) and then linking with -pie. There are two approaches to this:
1) Patching the toolchain's spec files (Hardened Gentoo) 2) Wrapper scripts for clang/gcc/ld.bfd/ld.gold (Debian, Fedora, Ubuntu)
Upstream hasn't accepted various forms of the first option, so I don't think it's a suitable approach for us. The hardening-wrapper package implements the second option and also enforces our existing hardening flags for build systems ignoring CFLAGS/CXXFLAGS/LDFLAGS.
All it would take is either adding hardening-wrapper to the default devtools packages list or making it part of base-devel.
Here's an example with a small C program:
strcat@thinktank i ~ master % cat test.c #include <stdio.h>
static void foo() {} static int bar = 5;
int main(void) { int baz = 5; printf("function: %p, data: %p, stack: %p\n", foo, &bar, &baz); return 0; }
Without the hardening-wrapper package installed:
strcat@thinktank i ~ master % gcc test.c -o test strcat@thinktank i ~ master % checksec --file test RELRO STACK CANARY NX PIE RPATH RUNPATH FILE No RELRO No canary found NX enabled No PIE No RPATH No RUNPATH test strcat@thinktank i ~ master % ./test function: 0x400506, data: 0x600980, stack: 0x7fff12ba3a7c strcat@thinktank i ~ master % ./test function: 0x400506, data: 0x600980, stack: 0x7fffa47958fc
With the hardening-wrapper package installed:
strcat@thinktank i ~ master % gcc test.c -o test strcat@thinktank i ~ master % checksec --file test RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH test strcat@thinktank i ~ master % ./test function: 0x7f267e569800, data: 0x7f267e76a050, stack: 0x7fff3ee5ea14 strcat@thinktank i ~ master % ./test function: 0x7f6a06b3e790, data: 0x7f6a06d3f048, stack: 0x7fff76a891bc
The defaults in /etc/hardening-wrapper.conf can be overridden via env variables:
strcat@thinktank i ~ master % HARDENING_STACK_PROTECTOR=0 gcc test.c -o test strcat@thinktank i ~ master % checksec --file test RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH test
The need to use wrapper scripts is a bit ugly, but I think it's a nicer approach than tracking down and patching dozens of build systems to respect CFLAGS/LDFLAGS and it's the only realistic way to enable PIE. The only alternative short of patching GCC spec files is manually specifying the flags in thousands of executable-only packages, and patching any build system producing both binaries and libraries (yikes!).
No matter how much I like the idea of making Arch more secure, there is one thing that makes compiling the whole system with ASLR one big no-go for me (please correct me if I'm wrong). As far as I know, the ASLR makes core dumps completely useless, and also makes it impossible to make any sense from addresses in backtrace (assume that you get a backtrace from an application without debugging symbols). I guess the same thing would happen with valgrind, too. I would be OK with building things from core with ASLR, as they should very stable, but not whole Arch. Lukas