Blocking double-free in Linux kernel

On the 7-th of August the Positive Technologies expert Alexander Popov gave a
talk at SHA2017. SHA stands for Still Hacking Anyway, it is a big outdoor hacker camp in Netherlands.

The recording of Alexander's talk is available here:

This short article describes some new aspects of Alexander's talk, which haven't
been covered in our blog.

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.

However, in case of CVE-2017-2636, which Alexander 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, Alexander has managed to turn that state of the system into a use-after-free error. He 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 Alexander's PoC exploit for CVE-2017-2636). So Alexander modified set_freepointer() function in mm/slub.c and sent the patch to the Linux Kernel Mailing List (LKML). It provoked a lively discussion.

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.

Alexander replied with his 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 Alexander's check behind CONFIG_SLAB_FREELIST_HARDENED kernel option. So currently the second version of
Alexander's patch is accepted and applied to the linux-next branch. It should get to the Linux kernel mainline in the nearest future.

We 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.

Article Link: