Difference between revisions of "Kernel ASLR"

From The iPhone Wiki
Jump to: navigation, search
(initial page with some infos from mdowd's presentation)
 
 
(3 intermediate revisions by one other user not shown)
Line 4: Line 4:
   
 
===Kernel Image===
 
===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:
+
The kernel image base is randomized by the boot loader ([[iBoot (Bootloader)|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)
 
base=0x01000000+(slide_byte*0x00200000)
Line 10: Line 10:
 
If the slide is 0, the static offset of 0x21000000 is used instead.
 
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 <code>0x04</code>.
+
The adjusted base is passed to the kernel in the boot arguments structure at offset <code>0x04</code>, which is equivalent to gBootArgs->virtBase.
   
 
===Kernel Map===
 
===Kernel Map===
Line 19: Line 19:
 
===Attacks===
 
===Attacks===
 
Leaking the kernel base is really useful. <code>Kext_request()</code> 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 <code>kKextRequestPredicateGetLoaded</code> 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.
 
Leaking the kernel base is really useful. <code>Kext_request()</code> 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 <code>kKextRequestPredicateGetLoaded</code> 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==
 
==References==

Latest revision as of 18:07, 13 August 2013

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