Regardless of the exact device and OS version, the top-level strategy of the heap groom can be seen as follows: First, we fill up the gaps to remove any unpredictable initially-free allocations in the kalloc.4096 zone. We don’t know how many holes there are, but overallocating here does no real harm. Eventually, all of the gaps in the kalloc.4096 zone are filled, and the allocations that follow then come from new pages brought in and carved up from kernel_memory_allocate, which are much more predictably clustered.
Once the gaps are full, the exploit developer sets about creating several what I’ll call “exploit zones”. Each “exploit zone” is a collection of victim candidate objects and a single “placeholder object”. The victim candidate is the recv_msg_elem array with the length chosen so that it gets allocated in the kalloc.4096 zone. The basic goal with these “exploit zones” is to create a group of allocations where the victim object follows a placeholder object with a good probability. Just before the exploit is triggered, the exploit developer releases all of the placeholder objects back to zalloc. This releases all of the blocking objects to the kalloc.4096 free list so that when the overflowing object is allocated, it finds itself immediately before a victim object with high likelihood.
The exact object used for the placeholder allocation is not important; it just matters that we can control the allocation’s size and have fine-grained control over when the object is released back to zalloc. It turns out that an out-of-line allocation associated with an iOS mach port is an ideal candidate for this, and this is what it is used in this exploit. By crafting the size of the message, we can exactly specify the size of kalloc allocation and when the corresponding mach port is destroyed, the corresponding allocation will be immediately released back to kfree.
For old devices, the exploit creates 17 “exploit zones”, each with 7 victim candidates and one placeholder. For newer devices, the exploit creates 20 “exploit zones”, each with 15 victim candidates and one placeholder. Having created these several exploit zones, the exploit developer “activates” them by freeing all of the corresponding placeholder objects very quickly. The exploit developer activates these arenas in allocation-order, which means that the kalloc.4096 zone’s free list fills up as “holes” in the exploitation arenas where the placeholder objects were. Since the kalloc.4096 free list releases elements in a last-in-first-out order, this means the next 4096-byte allocation will come from the last exploitation arena, the one after will come from the second-to-last arena, and so on. This has the effect of creating a sudden series of kalloc.4096 zone free entries, each of which is likely followed by a victim object candidate.
Now all the exploit developer needs to do is arrange for the vulnerable (overflowing) object to be allocated as quickly as possible while the kalloc.4096 heap is in this state. If all goes according to plan, the overflowing object will be allocated from one of these free entries and therefore lands inside an “exploit zone” immediately before one of these recv_msg_elem array victim candidate objects. Now when the overflow occurs, it will overflow onto one of the adjacent victim objects on the heap.