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_mapin some sense
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:
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.
The kernel map is used for kernel allocations of all types (
kernel_memory_allocate(), etc.) and spans all of kernel space (
0xFFFEFFFF). The kernel based maps are submaps of the
kernel_map, for example
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.
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.