Enable ASLR, PIE, RELRO, NX-Stack on FreeBSD (and hardening)

At now FreeBSD (9.0-RELEASE) does not have ASLR support by default, in this article we will teach you to patch the kernel to add ASLR support, recompile the kernel, install and configure the new sysct subset for ASLR random space tunning.

To start we need to have the system source (kernel) installed in: /usr/src/sys
If we do not have download sources, the most comfortable is using cvsup (or csup, a C clone)

To do this, you must first install cvsup if you do not have it:

  [root@reki ~]# cd /usr/ports/net/cvsup
  [root@reki /usr/ports/net/cvsup]# make install clean

Once installed, you must configure:

  cat > /root/RELENG_9-supfile
  *default host=cvsup11.FreeBSD.org
  *default base=/var/db
  *default prefix=/usr
  *default release=cvs tag=RELENG_9
  *default delete use-rel-suffix
  *default compress


The above configuration use the mirror cvsup11, we recommend check the best for your connection.
Furthermore, the tag used RELENG_9 is for FreeBSD 9. If you want to try the bleeding edge (at now 10.0-CURRENT) you must to put a "." as tag. This is enough.

This supfile will update all FreeBSD ports tree and userspace sources.
If you just want the kernel sources, you can comment the two lines and add the following: src-sys

Once we have our file it is time to run cvsup:

  [root@reki ~]# cvsup -g -L2 /root/RELENG_9-supfile

This process is quite slow, so I recommend to be patient and do something else :-)
Once finished, we will have to patch your kernel.

  [root@reki ~]# fetch http://lists.freebsd.org/pipermail/freebsd-current/attachments/20111116/b67a9b75/randomize-stack-and-mmap.bin
  [root@reki ~]# cd /usr/src 
  [root@reki /usr/src]# patch -p1 < /root/randomize-stack-and-mmap.bin 
  Hmm...  Looks like a unified diff to me...
  The text leading up to this was:
  |commit 779a962519e7ead63dda24348b98f6cde8156752
  |Author: Oliver Pinter 
  |Date:   Tue Oct 4 00:24:01 2011 +0200
  |    forwardport mmap-randomization patch from 7-STABLE-op
  |    Signed-off-by: Oliver Pinter 
  |diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
  |index fe01142..dc66db6 100644
  |--- a/sys/kern/kern_exec.c
  |+++ b/sys/kern/kern_exec.c
  Patching file sys/kern/kern_exec.c using Plan A...
  Hunk #1 succeeded at 107 (offset 1 line).
  Hunk #2 succeeded at 122 (offset 1 line).
  Hunk #3 succeeded at 182 (offset 1 line).
  Hunk #4 succeeded at 1274 (offset -2 lines).
  Hunk #5 succeeded at 1295 (offset 1 line).
  Hmm...  The next patch looks like a unified diff to me...
  The text leading up to this was:
  |diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c
  |index e85b681..991a37d 100644
  |--- a/sys/vm/vm_mmap.c
  |+++ b/sys/vm/vm_mmap.c
  Patching file sys/vm/vm_mmap.c using Plan A...
  Hunk #1 succeeded at 68.
  Hunk #2 succeeded at 101 (offset 1 line).
  Hunk #3 succeeded at 260 (offset -1 lines).
  Hunk #4 succeeded at 272 (offset 1 line).
  [root@reki /usr/src]#

  This is an optional step, but I recommend adding the flag "-fstack-protector", "-fomit-frame-pointer" and "-fPIE" in the file: /etc/make.conf
  It is also recommended to install and replace gcc by clang.

  [root@reki ~]# cat /etc/make.conf
  CPUTYPE?=               core2

  # Comment from -fomit-frame-pointer to kernel compiling
  CFLAGS=                 -O3 -pipe -fno-strict-aliasing -fstack-protector -fomit-frame-pointer # -Wl,-z,relro -Wl,-z,now -D_FORTIFY_SOURCE=2 -fPIE -pie
  COPTFLAGS=              -O3 -pipe -fno-strict-aliasing -fstack-protector -fomit-frame-pointer -funroll-loops -ffast-math # -Wl,-z,relro -Wl,-z,now -D_FORTIFY_SOURCE=2 -fPIE -pie
  CXXFLAGS+=              -O3 -pipe -fno-strict-aliasing -fstack-protector -fomit-frame-pointer -funroll-loops -ffast-math # -Wl,-z,relro -Wl,-z,now -D_FORTIFY_SOURCE=2 -fPIE -pie

  FORCE_MAKE_JOBS=        yes
  KERNCONF=               BSD GENERIC

  WITHOUT_X11=            YES
  BUILD_STATIC=           YES
  NO_PROFILE=             YES

  CC=                     clang
  CXX=                    clang++
  CPP=                    clang-cpp


  # added by use.perl 2012-06-08 14:22:50

Once the kernel are patched, you can configure it. If you do not understand this step, you can ignore it, is optional.

  [root@reki /usr/src]# vi sys/amd64/conf/GENERIC

Once configured (or has been left by default) must be compiled:

  [root@reki /usr/src]# make -j4 buildkernel KERNCONF=GENERIC

Once compiled, if all went well, it's time to install it (and also uncomment make.conf options):

  [root@reki /usr/src]# make installkernel

Now enable the NX support for the stack:

  cat >> /etc/sysctl.conf

The next step is to compile and install the userland.

  [root@reki /usr/src]# make -j4 buildworld
  [root@reki /usr/src]# make installworld

Now restart and if all goes well, we should have our shell again :-)

  [root@reki ~]# uname -a 
  FreeBSD reki 8.2-STABLE FreeBSD 9.0-STABLE #1: Thu Jul 19 19:01:37 CEST 2012     root@reki:/usr/obj/usr/src/sys/GENERIC  amd64

To check if we ASLR, you can do something like the following:

  [capi_x@reki ~]$ cat > kk.c
  #include <stdio.h>

  int main() {
      float pp;
      char  kk[256];

      printf("%p\n", &pp);
      printf("%p\n",  kk);

  [capi_x@reki ~]$ clang -fstack-protector -fPIE -pie kk.c -o kk
  [capi_x@reki ~]$ ./kk
  [capi_x@reki ~]$ ./kk
  [capi_x@reki ~]$ 

As can be seen, the addresses change, that's because now we have an implementation of ASLR.
If we want to increase the size of aletorización sysctl can be done by: kern.stackgap_random:

By default the value is 65536 (16 bits) does not recommend increasing its value, because some softwares can fail. Once finished the article I recommend reading the following slides which discusses an architecture based on FreeBSD and your full hardening: Deploying web servers

In truth, I recommend reading the presentation, is a delight with FreeBSD flavour ;-)

Disclaimer: This is an unofficial patch, you know if all bark, then rollback and passing this.
Update: The make.conf exposed and ASLR patch work perfectly on 10.0-CURRENT (at now)

P.S: Greetings to bryn1u if you read this :)