Kernel ASLR on amd64


October 12, 2017 posted by Maxime Villard

Recently, I completed a Kernel ASLR implementation for NetBSD-amd64, making NetBSD the first BSD system to support such a feature. Simply said, KASLR is a feature that randomizes the location of the kernel in memory, making it harder to exploit several classes of vulnerabilities, both locally (privilege escalations) and remotely (remote code executions).

Current design

The current design is based on a specialized kernel called the "prekern", which operates between the bootloader and the kernel itself. The kernel is compiled as a raw library with the GENERIC_KASLR configuration file, while the prekern is compiled as a static binary. When the machine boots, the bootloader jumps into the prekern. The prekern relocates the kernel at a random virtual address (VA), and jumps into it. Finally, the kernel performs some cleanup, and executes normally.

Currently, the kernel is randomized as a single block. That is to say, a random VA is chosen, and the kernel text->rodata->data sections are mapped contiguously starting from there. It has several drawbacks, but it's a first shot.

To complete this implementation, work had to be done at three levels: the bootloader, the prekern and the kernel. I committed several of the kernel and bootloader patches discreetly a few months ago, to pave some way for real changes. In the past few weeks, I changed the low-level x86 layer of the kernel and replaced several hard-coded (and sometimes magic) values by variables, in such a way that the kernel can run with a non-static memory layout. Finally, the last step was committing the prekern itself to the source tree.

Future work

  • Randomize the kernel sections independently, and intertwine them.
  • Modify several kernel entry points not to leak kernel addresses to userland.
  • Randomize the kernel heap too (which is still static for now).
  • Fix a few other things that need some more work.

How to use

All of the patches are now in NetBSD-current. Instructions on how to install and use this implementation can be found here; they are inlined below, and probably won't change in the future.

Make sure you have a v5.11 bootloader installed. If you don't, build and install a new bootloader:

    $ cd /usr/src/sys/arch/i386/stand/boot
    $ make
    # cp biosboot/boot /
Build and install a KASLR kernel:
    $ cd /usr/src
    $ ./build.sh -u kernel=GENERIC_KASLR
    # cp /usr/obj/sys/arch/amd64/compile/GENERIC_KASLR/netbsd /netbsd_kaslr
Finally, build and install a prekern:
    $ cd /usr/src/sys/arch/amd64/stand/prekern
    $ make
    # cp prekern /prekern
Reboot your machine. In the boot prompt, enter:
    > pkboot netbsd_kaslr
The system will boot with no further user interaction. Should you encounter any regression or unexpected behavior, please report it immediately to tech-kern.

Note that you can still boot a static kernel, by typing as usual:

    > boot netbsd

Availability

This KASLR implementation will be available starting from NetBSD 9. Once it is stabilized, it may be backported to NetBSD 8. Until then, feel free to test it!

[2 comments]

 



Comments:

Well, that's good news, thanks, good work!!! Just noting that while writing we are the FIRST to implement KASLR it would be fair to mention, that OpenBSD got a similar technology KARL already in their release....

Posted by Petr Topiarz on October 17, 2017 at 11:25 AM UTC #

Interesting strategy!

Posted by Wellington Torrejais da Silva on October 25, 2017 at 01:10 AM UTC #

Post a Comment:
  • HTML Syntax: NOT allowed