1*bbb1b6f9SApple OSS Distributions# XNU Allocators best practices 2*bbb1b6f9SApple OSS Distributions 3*bbb1b6f9SApple OSS DistributionsThe right way to allocate memory in the kernel. 4*bbb1b6f9SApple OSS Distributions 5*bbb1b6f9SApple OSS Distributions## Introduction 6*bbb1b6f9SApple OSS Distributions 7*bbb1b6f9SApple OSS DistributionsXNU proposes two ways to allocate memory: 8*bbb1b6f9SApple OSS Distributions 9*bbb1b6f9SApple OSS Distributions- the VM subsystem that provides allocations at the granularity of pages (with 10*bbb1b6f9SApple OSS Distributions `kmem_alloc` and similar interfaces); 11*bbb1b6f9SApple OSS Distributions- the zone allocator subsystem (`<kern/zalloc.h>`) which is a slab-allocator of 12*bbb1b6f9SApple OSS Distributions objects of fixed size. 13*bbb1b6f9SApple OSS Distributions 14*bbb1b6f9SApple OSS DistributionsIn addition to that, `<kern/kalloc.h>` provides a variable-size general purpose 15*bbb1b6f9SApple OSS Distributionsallocator implemented as a collection of zones of fixed size, and overflowing to 16*bbb1b6f9SApple OSS Distributions`kmem_alloc` for allocations larger than a few pages (32KB when this 17*bbb1b6f9SApple OSS Distributionsdocument was being written but this is subject to change/tuning in the future). 18*bbb1b6f9SApple OSS Distributions 19*bbb1b6f9SApple OSS Distributions 20*bbb1b6f9SApple OSS DistributionsThe Core Kernel allocators rely on the following headers: 21*bbb1b6f9SApple OSS Distributions 22*bbb1b6f9SApple OSS Distributions- `<kern/zalloc.h>` and `<kern/kalloc.h>` for its API surface, which most 23*bbb1b6f9SApple OSS Distributions clients should find sufficient, 24*bbb1b6f9SApple OSS Distributions- `<kern/zalloc_internal.h>` for interfaces that need to be exported 25*bbb1b6f9SApple OSS Distributions for introspection and implementation purposes, and is not meant 26*bbb1b6f9SApple OSS Distributions for general consumption. 27*bbb1b6f9SApple OSS Distributions 28*bbb1b6f9SApple OSS DistributionsThis document will present the best practices to allocate memory 29*bbb1b6f9SApple OSS Distributionsin the kernel, from a security perspective. 30*bbb1b6f9SApple OSS Distributions 31*bbb1b6f9SApple OSS Distributions## Permanent allocations 32*bbb1b6f9SApple OSS Distributions 33*bbb1b6f9SApple OSS DistributionsThe kernel sometimes needs to provide persistent allocations that depend on 34*bbb1b6f9SApple OSS Distributionsparameters that aren't compile time constants, but will not vary over time (NCPU 35*bbb1b6f9SApple OSS Distributionsis an obvious example here). 36*bbb1b6f9SApple OSS Distributions 37*bbb1b6f9SApple OSS DistributionsThe zone subsystem provides a `zalloc_permanent*` family of functions that help 38*bbb1b6f9SApple OSS Distributionsallocating memory in such a fashion in a very compact way. 39*bbb1b6f9SApple OSS Distributions 40*bbb1b6f9SApple OSS DistributionsUnlike the typical zone allocators, this allows for arbitrary sizes, in a 41*bbb1b6f9SApple OSS Distributionssimilar fashion to `kalloc`. These functions will never fail (if the allocation 42*bbb1b6f9SApple OSS Distributionsfails, the kernel will panic), and always return zeroed memory. Trying to free 43*bbb1b6f9SApple OSS Distributionsthese allocations results in a kernel panic. 44*bbb1b6f9SApple OSS Distributions 45*bbb1b6f9SApple OSS Distributions## Allocation flags 46*bbb1b6f9SApple OSS Distributions 47*bbb1b6f9SApple OSS DistributionsMost `zalloc` or `kalloc` functions take `zalloc_flags_t` typed flags. 48*bbb1b6f9SApple OSS DistributionsWhen flags are expected, exactly one of `Z_WAITOK`, `Z_NOWAIT` or `Z_NOPAGEWAIT` 49*bbb1b6f9SApple OSS Distributionsis to be passed: 50*bbb1b6f9SApple OSS Distributions 51*bbb1b6f9SApple OSS Distributions- `Z_WAITOK` means that the zone allocator can wait and block, 52*bbb1b6f9SApple OSS Distributions- `Z_NOWAIT` can be used to require a fully non blocking behavior, which can be 53*bbb1b6f9SApple OSS Distributions used for allocations under spinlock and other preemption disabled contexts; 54*bbb1b6f9SApple OSS Distributions- `Z_NOPAGEWAIT` allows for the allocator to block (typically on mutexes), 55*bbb1b6f9SApple OSS Distributions but not to wait for available pages if there are none, this is only useful 56*bbb1b6f9SApple OSS Distributions for the buffer cache, and most client should either use `Z_NOWAIT` or `Z_WAITOK`. 57*bbb1b6f9SApple OSS Distributions 58*bbb1b6f9SApple OSS DistributionsOther important flags: 59*bbb1b6f9SApple OSS Distributions 60*bbb1b6f9SApple OSS Distributions- `Z_ZERO` if zeroed memory is expected (nowadays most of the allocations will 61*bbb1b6f9SApple OSS Distributions be zeroed regardless, but it's always clearer to specify it), note that it is 62*bbb1b6f9SApple OSS Distributions often more efficient than calling bzero as the allocator tends to maintain 63*bbb1b6f9SApple OSS Distributions freed memory as zeroed in the first place, 64*bbb1b6f9SApple OSS Distributions- `Z_NOFAIL` if the caller knows the allocation can't fail: allocations that are 65*bbb1b6f9SApple OSS Distributions made with `Z_WAITOK` from regular (non exhaustible) zones, or from `kalloc*` 66*bbb1b6f9SApple OSS Distributions interfaces with a size smaller than `KALLOC_SAFE_ALLOC_SIZE`, 67*bbb1b6f9SApple OSS Distributions will never fail (the kernel will instead panic if no memory can be found). 68*bbb1b6f9SApple OSS Distributions `Z_NOFAIL` can be used to denote that the caller knows about this. 69*bbb1b6f9SApple OSS Distributions If `Z_NOFAIL` is incorrectly used, then the zone allocator will panic at runtime. 70*bbb1b6f9SApple OSS Distributions 71*bbb1b6f9SApple OSS Distributions## Zones (`zalloc`) 72*bbb1b6f9SApple OSS Distributions 73*bbb1b6f9SApple OSS DistributionsThe first blessed way to allocate memory in the kernel is by using zones. 74*bbb1b6f9SApple OSS DistributionsZones are mostly meant to be used in Core XNU and some "BSD" kexts. 75*bbb1b6f9SApple OSS Distributions 76*bbb1b6f9SApple OSS DistributionsIt is generally recommended to create zones early and to store the `zone_t` 77*bbb1b6f9SApple OSS Distributionspointer in read-only memory (using `SECURITY_READ_ONLY_LATE` storage). 78*bbb1b6f9SApple OSS Distributions 79*bbb1b6f9SApple OSS DistributionsZones are more feature-rich than `kalloc`, and some features can only be 80*bbb1b6f9SApple OSS Distributionsused when making a zone: 81*bbb1b6f9SApple OSS Distributions 82*bbb1b6f9SApple OSS Distributions- the object type being allocated requires extremely strong segregation 83*bbb1b6f9SApple OSS Distributions from other types (typically `zone_require` will be used with this zone), 84*bbb1b6f9SApple OSS Distributions- the object type implements some form of security boundary and wants to adopt 85*bbb1b6f9SApple OSS Distributions the read-only allocator (See `ZC_READONLY`), 86*bbb1b6f9SApple OSS Distributions- the allocation must be per-cpu, 87*bbb1b6f9SApple OSS Distributions- ... 88*bbb1b6f9SApple OSS Distributions 89*bbb1b6f9SApple OSS DistributionsIn the vast majority of cases however, using `kalloc_type` (or `IOMallocType`) 90*bbb1b6f9SApple OSS Distributionsis preferred. 91*bbb1b6f9SApple OSS Distributions 92*bbb1b6f9SApple OSS Distributions 93*bbb1b6f9SApple OSS Distributions## The Typed allocator 94*bbb1b6f9SApple OSS Distributions 95*bbb1b6f9SApple OSS DistributionsIgnoring VM allocations (or wrappers like `IOMemoryDescriptor`), the only 96*bbb1b6f9SApple OSS Distributionsblessed way to allocate typed memory in XNU is using the typed allocator 97*bbb1b6f9SApple OSS Distributions`kalloc_type` or one of its variants (like IOKit's `IOMallocType`) and untyped 98*bbb1b6f9SApple OSS Distributionsmemory that doesn't contain pointers is using the data API `kalloc_data` or 99*bbb1b6f9SApple OSS Distributionsone of its variants (like IOKit's `IOMallocData`). However, this comes with 100*bbb1b6f9SApple OSS Distributionsadditional requirements. 101*bbb1b6f9SApple OSS Distributions 102*bbb1b6f9SApple OSS DistributionsNote that at this time, those interfaces aren't exported to third parties, 103*bbb1b6f9SApple OSS Distributionsas its ABI has not yet converged. 104*bbb1b6f9SApple OSS Distributions 105*bbb1b6f9SApple OSS Distributions### A word about types 106*bbb1b6f9SApple OSS Distributions 107*bbb1b6f9SApple OSS DistributionsThe typed allocators assume that allocated types fit a very precise model. 108*bbb1b6f9SApple OSS DistributionsIf the allocations you perform do not fit the model, then your types 109*bbb1b6f9SApple OSS Distributionsmust be restructured to fit, for security reasons. 110*bbb1b6f9SApple OSS Distributions 111*bbb1b6f9SApple OSS DistributionsA general theme will be the separation of data/primitive types from pointers, 112*bbb1b6f9SApple OSS Distributionsas attackers tend to use data/pointer overlaps to carry out their exploitations. 113*bbb1b6f9SApple OSS Distributions 114*bbb1b6f9SApple OSS DistributionsThe typed allocators use compiler support to infer signatures 115*bbb1b6f9SApple OSS Distributionsof the types being allocated. Because some scalars actually represent 116*bbb1b6f9SApple OSS Distributionskernel pointers (like `vm_offset_t`,`vm_address_t`, `uintptr_t`, ...), 117*bbb1b6f9SApple OSS Distributionstypes or structure members can be decorated with `__kernel_ptr_semantics` 118*bbb1b6f9SApple OSS Distributionsto denote when a data-looking type is actually a pointer. 119*bbb1b6f9SApple OSS Distributions 120*bbb1b6f9SApple OSS DistributionsDo note that `__kernel_data_semantics` and `__kernel_dual_semantics` 121*bbb1b6f9SApple OSS Distributionsare also provided but should typically rarely be used. 122*bbb1b6f9SApple OSS Distributions 123*bbb1b6f9SApple OSS Distributions#### fixed-sized types 124*bbb1b6f9SApple OSS Distributions 125*bbb1b6f9SApple OSS DistributionsThe first case is fixed size types, this is typically a `struct`, `union` 126*bbb1b6f9SApple OSS Distributionsor C++ `class`. Fixed-size types must follow certain rules: 127*bbb1b6f9SApple OSS Distributions 128*bbb1b6f9SApple OSS Distributions- types should be small enough to fit in the zone allocator: 129*bbb1b6f9SApple OSS Distributions smaller than `KALLOC_SAFE_ALLOC_SIZE`. When this is not the case, 130*bbb1b6f9SApple OSS Distributions we have typically found that there is a large array of data, 131*bbb1b6f9SApple OSS Distributions or some buffer in that type, the solution is to outline this allocation. 132*bbb1b6f9SApple OSS Distributions kernel extensions must define `KALLOC_TYPE_STRICT_SIZE_CHECK` to turn 133*bbb1b6f9SApple OSS Distributions misuse of `kalloc_type()` relative to size at compile time, it's default in XNU. 134*bbb1b6f9SApple OSS Distributions- for union types, data/pointer overlaps should be avoided if possible. 135*bbb1b6f9SApple OSS Distributions when this isn't possible, a zone should be considered. 136*bbb1b6f9SApple OSS Distributions 137*bbb1b6f9SApple OSS Distributions#### Variable-sized types 138*bbb1b6f9SApple OSS Distributions 139*bbb1b6f9SApple OSS DistributionsThese come in two variants: arrays, and arrays prefixed with a header. 140*bbb1b6f9SApple OSS DistributionsAny other case must be reduced to those, by possibly making more allocations. 141*bbb1b6f9SApple OSS Distributions 142*bbb1b6f9SApple OSS DistributionsAn array is simply an allocation of several fixed-size types, 143*bbb1b6f9SApple OSS Distributionsand the rules of "fixed-sized types" above apply to them. 144*bbb1b6f9SApple OSS Distributions 145*bbb1b6f9SApple OSS DistributionsThe following rules are expected when dealing with variable sized allocations: 146*bbb1b6f9SApple OSS Distributions 147*bbb1b6f9SApple OSS Distributions- variable sized allocations should have a single owner and not be refcounted; 148*bbb1b6f9SApple OSS Distributions- under the header-prefixed form, if the header contains pointers, 149*bbb1b6f9SApple OSS Distributions then the array element type **must not** be only data. 150*bbb1b6f9SApple OSS Distributions 151*bbb1b6f9SApple OSS DistributionsIf those rules can't be followed, then the allocation must be split with 152*bbb1b6f9SApple OSS Distributionsthe header becoming a fixed-sized type becoming the single owner 153*bbb1b6f9SApple OSS Distributionsof an array. 154*bbb1b6f9SApple OSS Distributions 155*bbb1b6f9SApple OSS Distributions#### Untyped memory 156*bbb1b6f9SApple OSS Distributions 157*bbb1b6f9SApple OSS DistributionsWhen allocating untyped memory with the data APIs ensure that it doesn't 158*bbb1b6f9SApple OSS Distributionscontain kernel pointers. If your untyped allocation contains kernel pointers 159*bbb1b6f9SApple OSS Distributionsconsider splitting the allocation into two: one part that is typed and contains 160*bbb1b6f9SApple OSS Distributionsthe kernel pointers and the second that is untyped and data-only. 161*bbb1b6f9SApple OSS Distributions 162*bbb1b6f9SApple OSS Distributions### API surface 163*bbb1b6f9SApple OSS Distributions 164*bbb1b6f9SApple OSS Distributions<table> 165*bbb1b6f9SApple OSS Distributions <tr> 166*bbb1b6f9SApple OSS Distributions <th>Interface</th> 167*bbb1b6f9SApple OSS Distributions <th>API</th> 168*bbb1b6f9SApple OSS Distributions <th>Notes</th> 169*bbb1b6f9SApple OSS Distributions </tr> 170*bbb1b6f9SApple OSS Distributions <tr> 171*bbb1b6f9SApple OSS Distributions <td>Data/Primitive types</td> 172*bbb1b6f9SApple OSS Distributions <td> 173*bbb1b6f9SApple OSS Distributions <p> 174*bbb1b6f9SApple OSS Distributions <b>Core Kernel</b>:<br/> 175*bbb1b6f9SApple OSS Distributions <tt>kalloc_data(size, flags)</tt><br/> 176*bbb1b6f9SApple OSS Distributions <tt>krealloc_data(ptr, old_size, new_size, flags)</tt><br/> 177*bbb1b6f9SApple OSS Distributions <tt>kfree_data(ptr, size)</tt><br/> 178*bbb1b6f9SApple OSS Distributions <tt>kfree_data_counted_by(ptr_var, count_var)</tt><br/> 179*bbb1b6f9SApple OSS Distributions <tt>kfree_data_sized_by(ptr_var, byte_count_var)</tt><br/> 180*bbb1b6f9SApple OSS Distributions <tt>kfree_data_addr(ptr)</tt> 181*bbb1b6f9SApple OSS Distributions </p> 182*bbb1b6f9SApple OSS Distributions <p> 183*bbb1b6f9SApple OSS Distributions <b>IOKit untyped variant (returns <tt>void *</tt>)</b>:<br/> 184*bbb1b6f9SApple OSS Distributions <tt>IOMallocData(size)</tt><br/> 185*bbb1b6f9SApple OSS Distributions <tt>IOMallocZeroData(size)</tt><br/> 186*bbb1b6f9SApple OSS Distributions <tt>IOFreeData(ptr, size)</tt> 187*bbb1b6f9SApple OSS Distributions </p> 188*bbb1b6f9SApple OSS Distributions <p> 189*bbb1b6f9SApple OSS Distributions <b>IOKit typed variant (returns <tt>type_t *</tt>)</b>:<br/> 190*bbb1b6f9SApple OSS Distributions <tt>IONewData(type_t, count)</tt><br/> 191*bbb1b6f9SApple OSS Distributions <tt>IONewZeroData(type_t, count)</tt><br/> 192*bbb1b6f9SApple OSS Distributions <tt>IODeleteData(ptr, type_t, count)</tt> 193*bbb1b6f9SApple OSS Distributions </p> 194*bbb1b6f9SApple OSS Distributions </td> 195*bbb1b6f9SApple OSS Distributions <td>This should be used when the allocated type contains no kernel pointer only</td> 196*bbb1b6f9SApple OSS Distributions </tr> 197*bbb1b6f9SApple OSS Distributions <tr> 198*bbb1b6f9SApple OSS Distributions <td>Fixed-sized type</td> 199*bbb1b6f9SApple OSS Distributions <td> 200*bbb1b6f9SApple OSS Distributions <p> 201*bbb1b6f9SApple OSS Distributions <b>Core Kernel</b>:<br/> 202*bbb1b6f9SApple OSS Distributions <tt>kalloc_type(type_t, flags)</tt><br/> 203*bbb1b6f9SApple OSS Distributions <tt>kfree_type(type_t, ptr)</tt> 204*bbb1b6f9SApple OSS Distributions </p> 205*bbb1b6f9SApple OSS Distributions <p> 206*bbb1b6f9SApple OSS Distributions <b>IOKit:</b><br/> 207*bbb1b6f9SApple OSS Distributions <tt>IOMallocType(type_t)</tt><br/> 208*bbb1b6f9SApple OSS Distributions <tt>IOFreeType(ptr, type_t)</tt> 209*bbb1b6f9SApple OSS Distributions </p> 210*bbb1b6f9SApple OSS Distributions </td> 211*bbb1b6f9SApple OSS Distributions <td> 212*bbb1b6f9SApple OSS Distributions <p> 213*bbb1b6f9SApple OSS Distributions Note that this is absolutely OK to use this variant 214*bbb1b6f9SApple OSS Distributions for data/primitive types, it will be redirected to <tt>kalloc_data</tt> 215*bbb1b6f9SApple OSS Distributions (or <tt>IOMallocData</tt>). 216*bbb1b6f9SApple OSS Distributions </p> 217*bbb1b6f9SApple OSS Distributions </td> 218*bbb1b6f9SApple OSS Distributions </tr> 219*bbb1b6f9SApple OSS Distributions <tr> 220*bbb1b6f9SApple OSS Distributions <td>Arrays of fixed-sized type</td> 221*bbb1b6f9SApple OSS Distributions <td> 222*bbb1b6f9SApple OSS Distributions <p> 223*bbb1b6f9SApple OSS Distributions <b>Core Kernel</b>:<br/> 224*bbb1b6f9SApple OSS Distributions <tt>kalloc_type(type_t, count, flags)</tt><br/> 225*bbb1b6f9SApple OSS Distributions <tt>kfree_type(type_t, count, ptr)</tt> 226*bbb1b6f9SApple OSS Distributions </p> 227*bbb1b6f9SApple OSS Distributions <p> 228*bbb1b6f9SApple OSS Distributions <b>IOKit:</b><br/> 229*bbb1b6f9SApple OSS Distributions <tt>IONew(type_t, count)</tt><br/> 230*bbb1b6f9SApple OSS Distributions <tt>IONewZero(type_t, count)</tt><br/> 231*bbb1b6f9SApple OSS Distributions <tt>IODelete(ptr, type_t, count)</tt> 232*bbb1b6f9SApple OSS Distributions </p> 233*bbb1b6f9SApple OSS Distributions </td> 234*bbb1b6f9SApple OSS Distributions <td> 235*bbb1b6f9SApple OSS Distributions <p> 236*bbb1b6f9SApple OSS Distributions <tt>kalloc_type(type_t, ...)</tt> (resp. <tt>IONew(type_t, 1)</tt>) 237*bbb1b6f9SApple OSS Distributions <b>isn't</b> equivalent to <tt>kalloc_type(type_t, 1, ...)</tt> 238*bbb1b6f9SApple OSS Distributions (resp. <tt>IOMallocType(type_t)</tt>). Mix-and-matching interfaces 239*bbb1b6f9SApple OSS Distributions will result in panics. 240*bbb1b6f9SApple OSS Distributions </p> 241*bbb1b6f9SApple OSS Distributions <p> 242*bbb1b6f9SApple OSS Distributions Note that this is absolutely OK to use this variant 243*bbb1b6f9SApple OSS Distributions for data/primitive types, it will be redirected to <tt>kalloc_data</tt>. 244*bbb1b6f9SApple OSS Distributions </p> 245*bbb1b6f9SApple OSS Distributions </td> 246*bbb1b6f9SApple OSS Distributions </tr> 247*bbb1b6f9SApple OSS Distributions <tr> 248*bbb1b6f9SApple OSS Distributions <td>Header-prefixed arrays of fixed-sized type</td> 249*bbb1b6f9SApple OSS Distributions <td> 250*bbb1b6f9SApple OSS Distributions <p> 251*bbb1b6f9SApple OSS Distributions <b>Core Kernel</b>:<br/> 252*bbb1b6f9SApple OSS Distributions <tt>kalloc_type(hdr_type_t, type_t, count, flags)</tt><br/> 253*bbb1b6f9SApple OSS Distributions <tt>kfree_type(hdr_type_t, type_t, count, ptr)</tt> 254*bbb1b6f9SApple OSS Distributions </p> 255*bbb1b6f9SApple OSS Distributions <p> 256*bbb1b6f9SApple OSS Distributions <b>IOKit:</b><br/> 257*bbb1b6f9SApple OSS Distributions <tt>IONew(hdr_type_t, type_t, count)</tt><br/> 258*bbb1b6f9SApple OSS Distributions <tt>IONewZero(hdr_type_t, type_t, count)</tt><br/> 259*bbb1b6f9SApple OSS Distributions <tt>IODelete(ptr, hdr_type_t, type_t, count)</tt> 260*bbb1b6f9SApple OSS Distributions </p> 261*bbb1b6f9SApple OSS Distributions </td> 262*bbb1b6f9SApple OSS Distributions <td> 263*bbb1b6f9SApple OSS Distributions <p> 264*bbb1b6f9SApple OSS Distributions <tt>hdr_type_t</tt> can't contain a refcount, 265*bbb1b6f9SApple OSS Distributions and <tt>type_t</tt> can't be a primitive type. 266*bbb1b6f9SApple OSS Distributions </p> 267*bbb1b6f9SApple OSS Distributions </td> 268*bbb1b6f9SApple OSS Distributions </tr> 269*bbb1b6f9SApple OSS Distributions</table> 270*bbb1b6f9SApple OSS Distributions 271*bbb1b6f9SApple OSS Distributions`kfree_data_counted_by` and `kfree_data_sized_by` are used when working with 272*bbb1b6f9SApple OSS Distributions-fbounds-safety and pointers with __counted_by and __sized_by modifiers, 273*bbb1b6f9SApple OSS Distributionsrespectively. They expect both their pointer and size arguments to be 274*bbb1b6f9SApple OSS Distributionsmodifiable, and the pointer and size will be set to 0 together, in accordance 275*bbb1b6f9SApple OSS Distributionswith -fbounds-safety semantics. Please note that arguments are evaluated 276*bbb1b6f9SApple OSS Distributionsmultiple times. When -fbounds-safety is enabled, the compiler can help ensuring 277*bbb1b6f9SApple OSS Distributionscorrect usage of these macros; with -fbounds-safety disabled, engineers are on 278*bbb1b6f9SApple OSS Distributionstheir own to ensure proper usage. 279*bbb1b6f9SApple OSS Distributions 280*bbb1b6f9SApple OSS Distributions## C++ classes and operator new. 281*bbb1b6f9SApple OSS Distributions 282*bbb1b6f9SApple OSS DistributionsThis section covers how typed allocators should be adopted to use 283*bbb1b6f9SApple OSS Distributions`operator new/delete` in C++. For C++ classes, the approach required 284*bbb1b6f9SApple OSS Distributionsdiffers based on whether the class inherits from `OSObject` or not. 285*bbb1b6f9SApple OSS Distributions 286*bbb1b6f9SApple OSS DistributionsMost, if not all, C++ objects used in conjuction with IOKit APIs 287*bbb1b6f9SApple OSS Distributionsshould probably use OSObject as a base class. C++ operators 288*bbb1b6f9SApple OSS Distributionsand non-POD types should be used seldomly. 289*bbb1b6f9SApple OSS Distributions 290*bbb1b6f9SApple OSS Distributions### `OSObject` subclasses 291*bbb1b6f9SApple OSS Distributions 292*bbb1b6f9SApple OSS DistributionsAll subclasses of `OSObject` must declare and define one of IOKit's 293*bbb1b6f9SApple OSS Distributions`OSDeclare*` and `OSDefine*` macros. As part of those, an `operator new` and 294*bbb1b6f9SApple OSS Distributions`operator delete` are injected that force objects to enroll into `kalloc_type`. 295*bbb1b6f9SApple OSS Distributions 296*bbb1b6f9SApple OSS DistributionsNote that idiomatic IOKit is supposed to use `OSTypeAlloc(Class)`. 297*bbb1b6f9SApple OSS Distributions 298*bbb1b6f9SApple OSS Distributions### Other classes 299*bbb1b6f9SApple OSS Distributions 300*bbb1b6f9SApple OSS DistributionsUnlike `OSObject` subclasses, regular C++ classes must adopt typed allocators 301*bbb1b6f9SApple OSS Distributionsmanually. If your struct or class is POD (Plain Old Data), then replacing usage of 302*bbb1b6f9SApple OSS Distributions`new/delete` (resp. `new[]/delete[]`) with `IOMallocType/IOFreeType` (resp. 303*bbb1b6f9SApple OSS Distributions`IONew/IODelete`) is safe. 304*bbb1b6f9SApple OSS Distributions 305*bbb1b6f9SApple OSS DistributionsHowever, if you have non default structors, or members of your class/struct 306*bbb1b6f9SApple OSS Distributionshave non default structors, you will need to manually enroll it into `kalloc_type`. 307*bbb1b6f9SApple OSS DistributionsThis can be accomplished through one of the following approaches, and it lets you 308*bbb1b6f9SApple OSS Distributionsto continue to use C++'s new and delete keywords to allocate/deallocate instances. 309*bbb1b6f9SApple OSS Distributions 310*bbb1b6f9SApple OSS DistributionsThe first approach is to subclass the IOTypedOperatorsMixin struct. This will 311*bbb1b6f9SApple OSS Distributionsadopt typed allocators for your class/struct by providing the appropriate 312*bbb1b6f9SApple OSS Distributionsimplementations for `operator new/delete`: 313*bbb1b6f9SApple OSS Distributions 314*bbb1b6f9SApple OSS Distributions```cpp 315*bbb1b6f9SApple OSS Distributionsstruct Type : public IOTypedOperatorsMixin<Type> { 316*bbb1b6f9SApple OSS Distributions ... 317*bbb1b6f9SApple OSS Distributions}; 318*bbb1b6f9SApple OSS Distributions``` 319*bbb1b6f9SApple OSS Distributions 320*bbb1b6f9SApple OSS DistributionsAlternatively, if you cannot use the mixin approach, you can use the 321*bbb1b6f9SApple OSS Distributions`IOOverrideTypedOperators` macro to override `operator new/delete` 322*bbb1b6f9SApple OSS Distributionswithin your class/struct declaration: 323*bbb1b6f9SApple OSS Distributions 324*bbb1b6f9SApple OSS Distributions```cpp 325*bbb1b6f9SApple OSS Distributionsstruct Type { 326*bbb1b6f9SApple OSS Distributions IOOverrideTypedOperators(Type); 327*bbb1b6f9SApple OSS Distributions ... 328*bbb1b6f9SApple OSS Distributions}; 329*bbb1b6f9SApple OSS Distributions``` 330*bbb1b6f9SApple OSS Distributions 331*bbb1b6f9SApple OSS DistributionsFinally, if you need to decouple the declaration of the operators from 332*bbb1b6f9SApple OSS Distributionstheir implementation, you can use `IODeclareTypedOperators` paired with 333*bbb1b6f9SApple OSS Distributions`IODefineTypedOperators`, to declare the operators within your class/struct 334*bbb1b6f9SApple OSS Distributionsdeclaration and then provide their definition out of line: 335*bbb1b6f9SApple OSS Distributions 336*bbb1b6f9SApple OSS Distributions```cpp 337*bbb1b6f9SApple OSS Distributions// declaration 338*bbb1b6f9SApple OSS Distributionsstruct Type { 339*bbb1b6f9SApple OSS Distributions IODeclareTypedOperators(Type); 340*bbb1b6f9SApple OSS Distributions ... 341*bbb1b6f9SApple OSS Distributions}; 342*bbb1b6f9SApple OSS Distributions 343*bbb1b6f9SApple OSS Distributions// definition 344*bbb1b6f9SApple OSS DistributionsIODefineTypedOperators(Type) 345*bbb1b6f9SApple OSS Distributions``` 346*bbb1b6f9SApple OSS Distributions 347*bbb1b6f9SApple OSS DistributionsWhen a class/struct adopts typed allocators through one of those approaches, 348*bbb1b6f9SApple OSS Distributionsall its subclasses must also explicitly adopt typed allocators. It is not 349*bbb1b6f9SApple OSS Distributionssufficient for a common parent within the class hierarchy to enroll, in order to 350*bbb1b6f9SApple OSS Distributionsautomatically provide the implementation of the operators for all of its children: 351*bbb1b6f9SApple OSS Distributionseach and every subclass in the class hierarchy must also explicitly do the same. 352*bbb1b6f9SApple OSS Distributions 353*bbb1b6f9SApple OSS Distributions### The case of `operator new[]` 354*bbb1b6f9SApple OSS Distributions 355*bbb1b6f9SApple OSS DistributionsThe ABI of `operator new[]` is unfortunate, as it denormalizes 356*bbb1b6f9SApple OSS Distributionsdata that we prefer to be known by the owning object 357*bbb1b6f9SApple OSS Distributions(the element sizes and array element count). 358*bbb1b6f9SApple OSS Distributions 359*bbb1b6f9SApple OSS DistributionsIt also makes those allocations ripe for abuse in an adversarial 360*bbb1b6f9SApple OSS Distributionscontext as this denormalized information is at the begining 361*bbb1b6f9SApple OSS Distributionsof the structure, making it relatively easy to attack with 362*bbb1b6f9SApple OSS Distributionsout-of-bounds bugs. 363*bbb1b6f9SApple OSS Distributions 364*bbb1b6f9SApple OSS DistributionsFor this reason, the default variants of the mixin and the macros 365*bbb1b6f9SApple OSS Distributionspresented above will delete the implementation of `operator new[]` 366*bbb1b6f9SApple OSS Distributionsfrom the class they are applied to. 367*bbb1b6f9SApple OSS Distributions 368*bbb1b6f9SApple OSS DistributionsHowever, if those must be used, you can add adopt the typed 369*bbb1b6f9SApple OSS Distributionsallocators on your class by using the appropriate variant 370*bbb1b6f9SApple OSS Distributionswhich explicitly implements the support for array operators: 371*bbb1b6f9SApple OSS Distributions- `IOTypedOperatorsMixinSupportingArrayOperators` 372*bbb1b6f9SApple OSS Distributions- `IOOverrideTypedOperatorsSupportingArrayOperators` 373*bbb1b6f9SApple OSS Distributions- `IO{Declare, Define}TypedOperatorsSupportingArrayOperators` 374*bbb1b6f9SApple OSS Distributions 375*bbb1b6f9SApple OSS Distributions### Scalar types 376*bbb1b6f9SApple OSS Distributions 377*bbb1b6f9SApple OSS DistributionsThe only accepted ways of using `operator new/delete` and their variants are the ones 378*bbb1b6f9SApple OSS Distributionsdescribed above. You should never use the operators on scalar types. Instead, you 379*bbb1b6f9SApple OSS Distributionsshould use the appropriate typed allocator API based on the semantics of the memory 380*bbb1b6f9SApple OSS Distributionsbeing allocated (i.e. `IOMallocData` for data only buffers, and `IOMallocType`/`IONew` 381*bbb1b6f9SApple OSS Distributionsfor any other type). 382*bbb1b6f9SApple OSS Distributions 383*bbb1b6f9SApple OSS Distributions### Wrapping C++ type allocation in container OSObjects 384*bbb1b6f9SApple OSS Distributions 385*bbb1b6f9SApple OSS DistributionsThe blessed way of wrapping and passing a C++ type allocation for use in the 386*bbb1b6f9SApple OSS Distributionslibkern collection is using `OSValueObject`. Please do not use `OSData` for this 387*bbb1b6f9SApple OSS Distributionspurpose as its backing store should not contain kernel pointers. 388*bbb1b6f9SApple OSS Distributions 389*bbb1b6f9SApple OSS Distributions`OSValueObject<T>` allows you to safely use an `OSData` like API surface 390*bbb1b6f9SApple OSS Distributionswrapping a structure of type `T`. For each unique `T` being used, the 391*bbb1b6f9SApple OSS Distributions`OSValueObject<T>` must be instantiated in a module of your kernel extension, 392*bbb1b6f9SApple OSS Distributionsusing `OSDefineValueObjectForDependentType(T);`. 393*bbb1b6f9SApple OSS Distributions 394