This short article describes how I improved the SLUB allocator in the Linux kernel.

On the 7-th of August I gave a talk at SHA2017. SHA stands for Still Hacking Anyway, it is a big outdoor hacker camp in Netherlands. The slides and recording of the talk:

In this talk I showed that the general method of exploiting a double-free error is based on turning it into a use-after-free bug. That is usually achieved by allocating a memory region of the same size between double free() calls (see the diagram below). That technique is called heap spraying.


diagram


However, in case of CVE-2017-2636, which I exploited, there are 13 buffers freed straightaway. Moreover, the double freeing happens at the beginning. So the usual heap spraying described above doesn't work for that vulnerability. Nevertheless, I've managed to turn that state of the system into a use-after-free error. I abused the naive behaviour of SLUB, which is currently the main Linux kernel allocator.

It turned out that SLUB allows consecutive double freeing of the same memory region. In contrast, GNU C library allocator has a fasttop check against it, which introduces a relatively small performance penalty. The idea is simple: report an error on freeing a memory region if its address is similar to the last one on the allocator's freelist.

A similar check in SLUB would block some double-free exploits in Linux kernel (including my PoC exploit for CVE-2017-2636). So I modified set_freepointer() function in mm/slub.c and sent the patch to the Linux Kernel Mailing List (LKML). It provoked a lively discussion there.

The SLUB maintainers didn't like that this check:

  1. introduces some performance penalty for the default SLUB functionality;
  2. duplicates some part of already existing slub_debug feature;
  3. causes a kernel oops in case of a double-free error.

I replied with these arguments:

  1. slub_debug is not enabled in Linux distributions by default (due to the noticeable performance impact);
  2. when the allocator detects a double-free, some severe kernel error has already occurred on behalf of some process. So it might not be worth trusting that process (which might be an exploit).

Finally Kees Cook helped to negotiate adding this check behind CONFIG_SLAB_FREELIST_HARDENED kernel option. So currently the second version of the patch is accepted and applied to the linux-next branch. It should get to the Linux kernel mainline in the nearest future.

I hope that in future some popular Linux distribution will provide the kernel with the security hardening options (including CONFIG_SLAB_FREELIST_HARDENED) enabled by default.

Update

This naive double-free detection finally got to Linux kernel v4.14 as a part of CONFIG_SLAB_FREELIST_HARDENED. See Kees' post for more details.