Kernel ASLR

From The Apple Wiki

The goal of Kernel ASLR is to prevent an attacker from modifying or utilizing (kernel) data at known (fixed) addresses. The strategy to implement this is two-fold:

  • Randomize the kernel image base
  • Randomize the base of the kernel_map in some sense

Kernel Image

The kernel image base is randomized by the boot loader (iBoot). This is done by creating random data, doing a SHA-1 hash of it and then using a byte from the SHA-1 hash for the kernel slide. The slide is calculated with this formula:

base=0x01000000+(slide_byte*0x00200000)

If the slide is 0, the static offset of 0x21000000 is used instead.

The adjusted base is passed to the kernel in the boot arguments structure at offset 0x04, which is equivalent to gBootArgs->virtBase.

Kernel Map

The kernel map is used for kernel allocations of all types (kalloc(), kernel_memory_allocate(), etc.) and spans all of kernel space (0x80000000-0xFFFEFFFF). The kernel based maps are submaps of the kernel_map, for example zone_map, ipc_kernel_map, etc.

The strategy is to randomize the base of the kernel_map. A random 9-bit value is generated right after kmem_init() which establishes kernel_map, is multiplied by the page size. The resulting value is used as the size for the initial kernel_map allocation. Future kernel_map (and submap) allocations are pushed forward by a random amount. The allocation is silently removed after the first garbage collection and reused. This behaviour can be overridden with the "kmapoff" boot parameter.

Attacks

Leaking the kernel base is really useful. Kext_request() allows applications to request information about kernel modules, divided into active and passive operations. Active operations (load, unload, start, stop, etc.) require root access. iOS removes the ability to load kernel extensions. Passive operations were originally (before iOS6) unrestricted and allowed unprivileged users to query kernel module base addresses. iOS6 inadvertently removed some limitations; only the load address requests are disallowed. So we can use kKextRequestPredicateGetLoaded to get load addresses and mach-o header dumps. The load address and mach-o segment headers are obscured to hide the ASLR slide, but mach-o section headers are not. This reveals the virtual addresses of loaded kernel sections.

This information leak has been closed with iOS 6.0.1.

See also ARM Exception Vector Info Leak from the evasi0n jailbreak.

References