1*043036a2SApple OSS Distributions# Guard-object allocation policy 2*043036a2SApple OSS Distributions 3*043036a2SApple OSS DistributionsThe contemporary techniques we use to group and protect smaller allocations, 4*043036a2SApple OSS Distributionssuch as zalloc and kalloc_type, are premised around type-isolation and VA 5*043036a2SApple OSS Distributionssequestering. These techniques are impractical for larger allocations because 6*043036a2SApple OSS Distributionsthey consume outsized chunks of virtual address space, and could lead to 7*043036a2SApple OSS Distributionsexhaustion. We therefore use a different strategy for larger allocations, which 8*043036a2SApple OSS Distributionswe call guard objects. 9*043036a2SApple OSS Distributions 10*043036a2SApple OSS Distributions 11*043036a2SApple OSS Distributions## Algorithm 12*043036a2SApple OSS Distributions 13*043036a2SApple OSS DistributionsAllocation policies are assigned to particular regions of kernel address space. 14*043036a2SApple OSS DistributionsThe strategy specified by this document is used by regions such as the various 15*043036a2SApple OSS Distributionspointer ranges of `kmem_alloc()`, which previously used a first-fit allocator. 16*043036a2SApple OSS DistributionsUnder the guard-objects policy, the virtual address space is divided in 17*043036a2SApple OSS Distributions*chunks*. A chunk has a size class of the form $2^k \times \mathtt{PAGE\_SIZE}$, 18*043036a2SApple OSS Distributionsand is made of $\mathcal{S}$ *slots* of that size. $\mathcal{S}$ varies with the 19*043036a2SApple OSS Distributionssize class: smaller size-classes will have more slots, and larger size classes 20*043036a2SApple OSS Distributionswill have fewer. Chunks are also configured to have $\mathcal{G}$ _guards_ and 21*043036a2SApple OSS Distributionsup to $\mathcal{Q}$ _quarantines_. 22*043036a2SApple OSS Distributions 23*043036a2SApple OSS DistributionsChunks maintain several other important pieces of information, such as: 24*043036a2SApple OSS Distributions 25*043036a2SApple OSS Distributions* which slots are allocated and which slots are free; 26*043036a2SApple OSS Distributions* a dynamic count of quarantined slots within $[0, \mathcal{Q})$; 27*043036a2SApple OSS Distributions* a count of *available* slots, which are the number of free slots in excess 28*043036a2SApple OSS Distributions of guards $\mathcal{G}$ and the number of currently quarantined slots. 29*043036a2SApple OSS Distributions 30*043036a2SApple OSS DistributionsA chunk can be in three states: *empty* if all its slots are free, *partial* if 31*043036a2SApple OSS Distributionsit has at least one available slot, *full* if it has no available slots. Chunks 32*043036a2SApple OSS Distributionsare maintained in lists segregated by size class and state. 33*043036a2SApple OSS Distributions 34*043036a2SApple OSS Distributions### Allocating memory 35*043036a2SApple OSS Distributions 36*043036a2SApple OSS DistributionsMemory requests for a given size are rounded up to the next size class of the 37*043036a2SApple OSS Distributionsform $2^k$. The allocator must first select an appropriate chunk. Partial chunks 38*043036a2SApple OSS Distributionsare preferred, and if no partial chunk exists, an empty chunk is allocated from 39*043036a2SApple OSS Distributionsunused virtual address space. 40*043036a2SApple OSS Distributions 41*043036a2SApple OSS DistributionsA random slot is then chosen from any of the free slots in that chunk, and the 42*043036a2SApple OSS Distributionsavailable count of the chunk is decremented. If the chunk has now exhausted its 43*043036a2SApple OSS Distributionsavailable slots — only quarantined slots and guards are left — it's placed on 44*043036a2SApple OSS Distributionsits corresponding size class's full list. 45*043036a2SApple OSS Distributions 46*043036a2SApple OSS DistributionsVisually, let’s consider an example with two partial chunks A and B, with 8 47*043036a2SApple OSS Distributionsslots each, for $\mathcal{G} = \mathcal{Q} = 2$: 48*043036a2SApple OSS Distributions 49*043036a2SApple OSS Distributions``` 50*043036a2SApple OSS Distributions A───────────────┬─┬─┬─┬─┐ B───────────────┬─┬─┬─┬─┐ 51*043036a2SApple OSS Distributions │ Available: 1 │X│ │ │X│ │ Available: 4 │ │ │X│ │ 52*043036a2SApple OSS Distributions ┌─▶│ Quarantine: 0 ├─┼─┼─┼─┤────▶│ Quarantine: 0 ├─┼─┼─┼─┤ 53*043036a2SApple OSS Distributions┌─────────┐ │ │ Guards: 2 │X│X│X│ │ │ Guards: 2 │ │X│ │ │ 54*043036a2SApple OSS Distributions│ partial │──┘ └───────────────┴─┴─┴─┴─┘ └───────────────┴─┴─┴─┴─┘ 55*043036a2SApple OSS Distributions├─────────┤ 56*043036a2SApple OSS Distributions│ full │ 57*043036a2SApple OSS Distributions└─────────┘ 58*043036a2SApple OSS Distributions 59*043036a2SApple OSS DistributionsLegend: 60*043036a2SApple OSS Distributions┌─┐ ┌─┐ 61*043036a2SApple OSS Distributions│ │ free slot │X│ allocated slot 62*043036a2SApple OSS Distributions└─┘ └─┘ 63*043036a2SApple OSS Distributions``` 64*043036a2SApple OSS Distributions 65*043036a2SApple OSS DistributionsThe first allocation will be performed from chunk A, using its last available 66*043036a2SApple OSS Distributionsslot and moving it to the full list: 67*043036a2SApple OSS Distributions 68*043036a2SApple OSS Distributions``` 69*043036a2SApple OSS Distributions B───────────────┬─┬─┬─┬─┐ 70*043036a2SApple OSS Distributions │ Available: 4 │ │ │X│ │ 71*043036a2SApple OSS Distributions ┌─▶│ Quarantine: 0 ├─┼─┼─┼─┤ 72*043036a2SApple OSS Distributions┌─────────┐ │ │ Guards: 2 │ │X│ │ │ 73*043036a2SApple OSS Distributions│ partial │──┘ └───────────────┴─┴─┴─┴─┘ 74*043036a2SApple OSS Distributions├─────────┤ 75*043036a2SApple OSS Distributions│ full │──┐ A───────────────┬─┬─┬─┬─┐ 76*043036a2SApple OSS Distributions└─────────┘ │ │ Available: 0 │X│ │X│X│ 77*043036a2SApple OSS Distributions └─▶│ Quarantine: 0 ├─┼─┼─┼─┤ 78*043036a2SApple OSS Distributions │ Guards: 2 │X│X│X│ │ 79*043036a2SApple OSS Distributions └───────────────┴─┴─┴─┴─┘ 80*043036a2SApple OSS Distributions``` 81*043036a2SApple OSS Distributions 82*043036a2SApple OSS DistributionsWhen the next allocation request in this size class arrives, the allocator will 83*043036a2SApple OSS Distributionsselect B because A is now full: 84*043036a2SApple OSS Distributions 85*043036a2SApple OSS Distributions``` 86*043036a2SApple OSS Distributions B───────────────┬─┬─┬─┬─┐ 87*043036a2SApple OSS Distributions │ Available: 3 │ │ │X│ │ 88*043036a2SApple OSS Distributions ┌─▶│ Quarantine: 0 ├─┼─┼─┼─┤ 89*043036a2SApple OSS Distributions┌─────────┐ │ │ Guards: 2 │ │X│X│ │ 90*043036a2SApple OSS Distributions│ partial │──┘ └───────────────┴─┴─┴─┴─┘ 91*043036a2SApple OSS Distributions├─────────┤ 92*043036a2SApple OSS Distributions│ full │──┐ A───────────────┬─┬─┬─┬─┐ 93*043036a2SApple OSS Distributions└─────────┘ │ │ Available: 0 │X│ │X│X│ 94*043036a2SApple OSS Distributions └─▶│ Quarantine: 0 ├─┼─┼─┼─┤ 95*043036a2SApple OSS Distributions │ Guards: 2 │X│X│X│ │ 96*043036a2SApple OSS Distributions └───────────────┴─┴─┴─┴─┘ 97*043036a2SApple OSS Distributions``` 98*043036a2SApple OSS Distributions 99*043036a2SApple OSS Distributions### Deallocating memory 100*043036a2SApple OSS Distributions 101*043036a2SApple OSS DistributionsDeallocating a virtual memory range works in reverse. First, we evaluate which 102*043036a2SApple OSS Distributionschunk and slot correspond to the range being freed. Since the semantics of the 103*043036a2SApple OSS Distributionsvirtual memory subsystem mandate that we must support partial deallocations, we 104*043036a2SApple OSS Distributionsnext consider whether the slot has become only partially free. If so, we have 105*043036a2SApple OSS Distributionsnothing more to do for now; the slot remains in use. 106*043036a2SApple OSS Distributions 107*043036a2SApple OSS DistributionsIf however the slot is now entirely free, then the quarantine count of the chunk 108*043036a2SApple OSS Distributionsis incremented. If at least $\mathcal{G} + \mathcal{Q}$ are free, then the 109*043036a2SApple OSS Distributionsquarantine is cleared. The idea behind this policy is that maintaining a good 110*043036a2SApple OSS Distributionsentropy requires enough free slots to choose from. As a result, once the free 111*043036a2SApple OSS Distributionsslot count dips below $\mathcal{G} + \mathcal{Q}$, freed slots are quarantined 112*043036a2SApple OSS Distributionsrather than made immediately available. 113*043036a2SApple OSS Distributions 114*043036a2SApple OSS DistributionsFinally, we evaluate whether the chunk needs to be moved: 115*043036a2SApple OSS Distributions 116*043036a2SApple OSS Distributions* if a chunk's slots are all fully free, the chunk is marked as empty, and is 117*043036a2SApple OSS Distributions typically returned to the system as free space; 118*043036a2SApple OSS Distributions* if the chunk previously had no slots available, but has any available now, 119*043036a2SApple OSS Distributions the chunk is moved to the partially-free chunks list. 120*043036a2SApple OSS Distributions 121*043036a2SApple OSS DistributionsVisually, let’s consider an example with a chunk using 16 slots, 122*043036a2SApple OSS Distributionsunder a configuration in which $\mathcal{G} = \mathcal{Q} = 4$: 123*043036a2SApple OSS Distributions 124*043036a2SApple OSS Distributions``` 125*043036a2SApple OSS Distributions A───────────────┬─┬─┬─┬─┬─┬─┬─┬─┐ 126*043036a2SApple OSS Distributions┌─────────┐ │ Available: 1 │ │X│X│X│ │ │X│ │ 127*043036a2SApple OSS Distributions│ partial │─────▶│ Quarantine: 1 ├─┼─┼─┼─┼─┼─┼─┼─┤ 128*043036a2SApple OSS Distributions├─────────┤ │ Guards: 4 │ │X│X│X│X│X│ │X│ 129*043036a2SApple OSS Distributions│ full │ └───────────────┴─┴─┴─┴─┴─┴─┴─┴─┘ 130*043036a2SApple OSS Distributions└─────────┘ 131*043036a2SApple OSS Distributions 132*043036a2SApple OSS DistributionsLegend: 133*043036a2SApple OSS Distributions┌─┐ ┌─┐ 134*043036a2SApple OSS Distributions│ │ free slot │X│ allocated slot 135*043036a2SApple OSS Distributions└─┘ └─┘ 136*043036a2SApple OSS Distributions``` 137*043036a2SApple OSS Distributions 138*043036a2SApple OSS DistributionsIf we now free an element, its slot is marked free, and the quarantine count 139*043036a2SApple OSS Distributionsis increased: 140*043036a2SApple OSS Distributions 141*043036a2SApple OSS Distributions``` 142*043036a2SApple OSS Distributions A───────────────┬─┬─┬─┬─┬─┬─┬─┬─┐ 143*043036a2SApple OSS Distributions┌─────────┐ │ Available: 1 │ │X│X│X│ │ │X│ │ 144*043036a2SApple OSS Distributions│ partial │─────▶│ Quarantine: 2 ├─┼─┼─┼─┼─┼─┼─┼─┤ 145*043036a2SApple OSS Distributions├─────────┤ │ Guards: 4 │ │X│X│ │X│X│ │X│ 146*043036a2SApple OSS Distributions│ full │ └───────────────┴─┴─┴─┴─┴─┴─┴─┴─┘ 147*043036a2SApple OSS Distributions└─────────┘ 148*043036a2SApple OSS Distributions``` 149*043036a2SApple OSS Distributions 150*043036a2SApple OSS DistributionsIf we allocate the last available element, a slot is now marked used, 151*043036a2SApple OSS Distributionsthe available count drops to 0, and causes the chunk to now be full, 152*043036a2SApple OSS Distributionsand the quarantine stays untouched: 153*043036a2SApple OSS Distributions 154*043036a2SApple OSS Distributions``` 155*043036a2SApple OSS Distributions┌─────────┐ 156*043036a2SApple OSS Distributions│ partial │ A───────────────┬─┬─┬─┬─┬─┬─┬─┬─┐ 157*043036a2SApple OSS Distributions├─────────┤ │ Available: 0 │X│X│X│X│ │ │X│ │ 158*043036a2SApple OSS Distributions│ full │─────▶│ Quarantine: 2 ├─┼─┼─┼─┼─┼─┼─┼─┤ 159*043036a2SApple OSS Distributions└─────────┘ │ Guards: 4 │ │X│X│ │X│X│ │X│ 160*043036a2SApple OSS Distributions └───────────────┴─┴─┴─┴─┴─┴─┴─┴─┘ 161*043036a2SApple OSS Distributions``` 162*043036a2SApple OSS Distributions 163*043036a2SApple OSS DistributionsFreeing just one element would return just one slot, and bump the quarantine 164*043036a2SApple OSS Distributionscount to 3. It takes freeing two elements for more than $\mathcal{G} + 165*043036a2SApple OSS Distributions\mathcal{Q}$ slots to be free, leading to clearing the quarantine: 166*043036a2SApple OSS Distributions 167*043036a2SApple OSS Distributions``` 168*043036a2SApple OSS Distributions A───────────────┬─┬─┬─┬─┬─┬─┬─┬─┐ 169*043036a2SApple OSS Distributions┌─────────┐ │ Available: 4 │X│X│X│X│ │ │X│ │ 170*043036a2SApple OSS Distributions│ partial │─────▶│ Quarantine: 0 ├─┼─┼─┼─┼─┼─┼─┼─┤ 171*043036a2SApple OSS Distributions├─────────┤ │ Guards: 4 │ │X│X│ │ │ │ │X│ 172*043036a2SApple OSS Distributions│ full │ └───────────────┴─┴─┴─┴─┴─┴─┴─┴─┘ 173*043036a2SApple OSS Distributions└─────────┘ 174*043036a2SApple OSS Distributions``` 175*043036a2SApple OSS Distributions 176*043036a2SApple OSS Distributions### Operation clamping to a slot 177*043036a2SApple OSS Distributions 178*043036a2SApple OSS DistributionsAs long as a VM operation does not exceed slot bounds, any VM call is permitted, 179*043036a2SApple OSS Distributionswhether it is configuration altering calls such as `vm_protect()` or 180*043036a2SApple OSS Distributions`vm_inherit()`, taking copies of the range with `mach_make_memory_entry()`, or 181*043036a2SApple OSS Distributionsreplacing part of the mapping with `vm_allocate(..., VM_FLAGS_FIXED | 182*043036a2SApple OSS DistributionsVM_FLAGS_OVERWRITE)`. 183*043036a2SApple OSS Distributions 184*043036a2SApple OSS DistributionsHowever, operations that cross a slot boundary are not permitted, and lead to 185*043036a2SApple OSS Distributionstermination. When guard object policies are in effect, allocations are 186*043036a2SApple OSS Distributionsrandomized, and even in a single threaded context, clients can't assume that 187*043036a2SApple OSS Distributionsconsecutive allocations will be served in address order, and as a result, 188*043036a2SApple OSS Distributionsoperations crossing slot boundaries are always bugs. 189*043036a2SApple OSS Distributions 190*043036a2SApple OSS Distributions 191*043036a2SApple OSS Distributions## Security motivation 192*043036a2SApple OSS Distributions 193*043036a2SApple OSS DistributionsWith the algorithm explanation, the “guard object” moniker should start to make 194*043036a2SApple OSS Distributionssense: the goal is that unused free slots are object-sized guards — in the 195*043036a2SApple OSS Distributionsguard-page sense. Unlike usage of traditional guard pages, which only protect 196*043036a2SApple OSS Distributionsagainst linear buffer overflows, this scheme also adds a probabilistic 197*043036a2SApple OSS Distributionsmitigation against use-after-free or non-linear buffer overflows, forcing 198*043036a2SApple OSS Distributionsattackers to contend with a high probability of hitting these guards. 199*043036a2SApple OSS Distributions 200*043036a2SApple OSS DistributionsDue to visible timing differences, it is assumed that an attacker can observe 201*043036a2SApple OSS Distributionswhen a chunk is being allocated or freed. However, this doesn't give them an 202*043036a2SApple OSS Distributionsedge because the system maintains a guarantee that at least 203*043036a2SApple OSS Distributions$\mathcal{G}/\mathcal{S}$ of the address space causes a crash when accessed at 204*043036a2SApple OSS Distributionsany given time. This is why we can let go of any form of sequestering of the 205*043036a2SApple OSS Distributionsaddress space for ranges managed with the guard-object allocation policy. 206*043036a2SApple OSS Distributions 207*043036a2SApple OSS Distributions### Use-after-Free exploitation strategies and failure rates 208*043036a2SApple OSS Distributions 209*043036a2SApple OSS DistributionsAttackers attempting to exploit a use-after-free will be able to cause an 210*043036a2SApple OSS Distributionselement to be freed, knowing that a dangling pointer to it remains. They will 211*043036a2SApple OSS Distributionsthen try to replace this freed element with another one of a different type 212*043036a2SApple OSS Distributionsthat they control, creating a type confusion. 213*043036a2SApple OSS Distributions 214*043036a2SApple OSS DistributionsBecause allocating new chunks causes visible timing differences, we can assume 215*043036a2SApple OSS Distributionsthat attackers are able to fill chunks with all slots corresponding to elements 216*043036a2SApple OSS Distributionsthat they control. They also know which elements are in the same chunk, but 217*043036a2SApple OSS Distributionsdon't know which element corresponds to which slot. 218*043036a2SApple OSS Distributions 219*043036a2SApple OSS Distributions**In the absence of the quarantine**, the best strategy for attackers trying to 220*043036a2SApple OSS Distributionsexploit a use-after free is to perform $\mathcal{S} − \mathcal{G}$ rounds 221*043036a2SApple OSS Distributionsof freeing then reallocating each element in the chunk, where the first free is 222*043036a2SApple OSS Distributionsto the element they are trying to use-after-free, so that they retain a dangling 223*043036a2SApple OSS Distributionspointer to the original slot. Each round, the allocator will choose one slot 224*043036a2SApple OSS Distributionsamong $\mathcal{G} + 1$, when only one corresponds to the slot that was freed by 225*043036a2SApple OSS Distributionstriggering the bug. The failure rate the attackers face with this strategy is 226*043036a2SApple OSS Distributions 227*043036a2SApple OSS Distributions$$failure\_rate = \left( 228*043036a2SApple OSS Distributions\frac{\mathcal{G}}{\mathcal{G+1}}\right)^{\mathcal{S} - \mathcal{G}}$$ 229*043036a2SApple OSS Distributions 230*043036a2SApple OSS Distributions* $\mathcal{S} = 8, \mathcal{G} = 2$ yields a 8.8% failure rate; 231*043036a2SApple OSS Distributions* $\mathcal{S} = 16, \mathcal{G} = 4$ yields a 6.9 failure rate. 232*043036a2SApple OSS Distributions 233*043036a2SApple OSS Distributions**Using the quarantine** further reduces an attacker's odds of success. Unlike 234*043036a2SApple OSS Distributionsbefore, they need to free at least $\mathcal{Q}$ elements before elements are 235*043036a2SApple OSS Distributionsmade available for allocations again. As a result, a round now needs to be 236*043036a2SApple OSS Distributions$\mathcal{Q}$ deallocations followed by $\mathcal{Q}$ allocations. As before, 237*043036a2SApple OSS Distributionsthe very first deallocation is to the element the attacker tries to 238*043036a2SApple OSS Distributionsuse-after-free. A round gives attackers $\frac{\mathcal{G}}{ 239*043036a2SApple OSS Distributions\mathcal{G}+\mathcal{Q}}$ chances of failure. The aggregate failure rate for 240*043036a2SApple OSS Distributionsthis strategy is 241*043036a2SApple OSS Distributions 242*043036a2SApple OSS Distributions$$failure\_rate =\left( 1 - \frac{(\mathcal{S} - \mathcal{G)} \bmod \mathcal{Q} 243*043036a2SApple OSS Distributions}{\mathcal{G} + \mathcal{Q}} \right) 244*043036a2SApple OSS Distributions\left(\frac{\mathcal{G}}{\mathcal{G} + \mathcal{Q}}\right)^{ 245*043036a2SApple OSS Distributions\left\lfloor \frac{\mathcal{S} -\mathcal{G}}{\mathcal{Q}} \right\rfloor}$$ 246*043036a2SApple OSS Distributions 247*043036a2SApple OSS Distributions* $\mathcal{S}=8, \mathcal{G}=1, \mathcal{Q}=4$ yields a 8% failure rate; 248*043036a2SApple OSS Distributions* $\mathcal{S}=8, \mathcal{G}=2, \mathcal{Q}=2$ yields a 12.5% failure rate; 249*043036a2SApple OSS Distributions* $\mathcal{S}=16, \mathcal{G}=4, \mathcal{Q}=3$ yields a 10.7% failure rate; 250*043036a2SApple OSS Distributions* $\mathcal{S}=16, \mathcal{G}=4, \mathcal{Q}=4$ yields a 12.5% failure rate. 251*043036a2SApple OSS Distributions 252*043036a2SApple OSS Distributions### Out-of-bound exploitation strategies 253*043036a2SApple OSS Distributions 254*043036a2SApple OSS DistributionsExploiting out-of-bound bugs requires knowing the distance between allocated 255*043036a2SApple OSS Distributionsobjects, which an attacker a priori doesn’t know without some information leak. 256*043036a2SApple OSS DistributionsThe regions protected by guard objects are coarsely randomized in the address 257*043036a2SApple OSS Distributionsspace, so that attackers can’t predict how far an allocation is from other juicy 258*043036a2SApple OSS Distributionsexploitation targets in the address space such as the `__DATA` segment. Lastly, 259*043036a2SApple OSS Distributionsguard objects are combined in XNU with type isolation and allocation fronts. It 260*043036a2SApple OSS Distributionsmakes cross-type attacks unreliable and unpredictable — as the various buckets 261*043036a2SApple OSS Distributionsof types are randomized per boot. 262*043036a2SApple OSS Distributions 263*043036a2SApple OSS DistributionsThe last remaining avenue of attack targets types that fall in the same 264*043036a2SApple OSS Distributionsallocation front. However, attackers still have to contend with the uniform 265*043036a2SApple OSS Distributions$\mathcal{G}/\mathcal{S}$ density of holes, making out-of-bound unreliable with 266*043036a2SApple OSS Distributionsa probability of failure close to $\mathcal{G}/\mathcal{S}$. This probability of 267*043036a2SApple OSS Distributionsfailure is typically worse than use-after-free for attackers, and intuitively, 268*043036a2SApple OSS Distributionsthis is precisely because they need to know more information — the distance 269*043036a2SApple OSS Distributionsbetween objects — unlike use-after-free where that distance is obviously known 270*043036a2SApple OSS Distributionsto be zero. 271*043036a2SApple OSS Distributions 272*043036a2SApple OSS Distributions### Choice of parameters 273*043036a2SApple OSS Distributions 274*043036a2SApple OSS DistributionsIn the actual implementation, $\mathcal{S}$ scales up with the size of the 275*043036a2SApple OSS Distributionsallocations going up — as a way to limit the amount of metadata needed. 276*043036a2SApple OSS DistributionsMaintaining the $\mathcal{G}/\mathcal{S}$ and $\mathcal{Q}/\mathcal{S}$ ratios 277*043036a2SApple OSS Distributionsconstant for any $\mathcal{S}$ allows for all probabilities to become 278*043036a2SApple OSS Distributionsindependent of $\mathcal{S}$. 279*043036a2SApple OSS Distributions 280*043036a2SApple OSS DistributionsOur goal is to make attackers face at least 10% chance of failure — in the 281*043036a2SApple OSS Distributionsabsence of information disclosure — which is why we chose numbers where 282*043036a2SApple OSS Distributions$\mathcal{G} = \mathcal{Q} = \mathcal{S}/4$, yielding: 283*043036a2SApple OSS Distributions 284*043036a2SApple OSS Distributions* 25% failure rates for out-of-bound exploitation; 285*043036a2SApple OSS Distributions* 12.5% failure rates for use-after-free exploitation. 286*043036a2SApple OSS Distributions 287