xref: /xnu-12377.41.6/doc/allocators/api-basics.md (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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