]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
f427ee49 | 2 | * Copyright (c) 2000-2020 Apple Computer, Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
0a7de745 | 31 | /* |
1c79356b A |
32 | * Mach Operating System |
33 | * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University | |
34 | * All Rights Reserved. | |
0a7de745 | 35 | * |
1c79356b A |
36 | * Permission to use, copy, modify and distribute this software and its |
37 | * documentation is hereby granted, provided that both the copyright | |
38 | * notice and this permission notice appear in all copies of the | |
39 | * software, derivative works or modified versions, and any portions | |
40 | * thereof, and that both notices appear in supporting documentation. | |
0a7de745 | 41 | * |
1c79356b A |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
0a7de745 | 45 | * |
1c79356b | 46 | * Carnegie Mellon requests users of this software to return to |
0a7de745 | 47 | * |
1c79356b A |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
49 | * School of Computer Science | |
50 | * Carnegie Mellon University | |
51 | * Pittsburgh PA 15213-3890 | |
0a7de745 | 52 | * |
1c79356b A |
53 | * any improvements or extensions that they make and grant Carnegie Mellon |
54 | * the rights to redistribute these changes. | |
55 | */ | |
1c79356b | 56 | |
0a7de745 | 57 | #ifdef KERNEL_PRIVATE |
91447636 | 58 | |
0a7de745 | 59 | #ifndef _KERN_KALLOC_H_ |
1c79356b A |
60 | #define _KERN_KALLOC_H_ |
61 | ||
1c79356b | 62 | #include <mach/machine/vm_types.h> |
3e170ce0 | 63 | #include <mach/boolean.h> |
3e170ce0 | 64 | #include <mach/vm_types.h> |
f427ee49 | 65 | #include <kern/zalloc.h> |
1c79356b | 66 | |
91447636 | 67 | __BEGIN_DECLS |
1c79356b | 68 | |
3e170ce0 A |
69 | #if XNU_KERNEL_PRIVATE |
70 | ||
f427ee49 A |
71 | /*! |
72 | * @typedef kalloc_heap_t | |
73 | * | |
74 | * @abstract | |
75 | * A kalloc heap view represents a sub-accounting context | |
76 | * for a given kalloc heap. | |
77 | */ | |
78 | typedef struct kalloc_heap { | |
79 | struct kheap_zones *kh_zones; | |
80 | zone_stats_t kh_stats; | |
81 | const char *kh_name; | |
82 | struct kalloc_heap *kh_next; | |
83 | zone_kheap_id_t kh_heap_id; | |
84 | } *kalloc_heap_t; | |
85 | ||
86 | /*! | |
87 | * @macro KALLOC_HEAP_DECLARE | |
88 | * | |
89 | * @abstract | |
90 | * (optionally) declare a kalloc heap view in a header. | |
91 | * | |
92 | * @discussion | |
93 | * Unlike kernel zones, new full blown heaps cannot be instantiated. | |
94 | * However new accounting views of the base heaps can be made. | |
95 | */ | |
96 | #define KALLOC_HEAP_DECLARE(var) \ | |
97 | extern struct kalloc_heap var[1] | |
3e170ce0 | 98 | |
f427ee49 A |
99 | /** |
100 | * @const KHEAP_ANY | |
101 | * | |
102 | * @brief | |
103 | * A value that represents either the default or kext heap for codepaths that | |
104 | * need to allow @c kheap_free() to either one. | |
105 | * | |
106 | * @discussion | |
107 | * When the memory provenance is not known, this value can be used to free | |
108 | * memory indiscriminately. | |
109 | * | |
110 | * Note: code using this constant can likely be used as a gadget to free | |
111 | * arbitrary memory and its use is strongly discouraged. | |
112 | */ | |
113 | #define KHEAP_ANY ((struct kalloc_heap *)NULL) | |
39037602 | 114 | |
f427ee49 A |
115 | /** |
116 | * @const KHEAP_DATA_BUFFERS | |
117 | * | |
118 | * @brief | |
119 | * The builtin heap for bags of pure bytes. | |
120 | * | |
121 | * @discussion | |
122 | * This set of kalloc zones should contain pure bags of bytes with no pointers | |
123 | * or length/offset fields. | |
124 | * | |
125 | * The zones forming the heap aren't sequestered from each other, however the | |
126 | * entire heap lives in a different submap from any other kernel allocation. | |
127 | * | |
128 | * The main motivation behind this separation is due to the fact that a lot of | |
129 | * these objects have been used by attackers to spray the heap to make it more | |
130 | * predictable while exploiting use-after-frees or overflows. | |
131 | * | |
132 | * Common attributes that make these objects useful for spraying includes | |
133 | * control of: | |
134 | * - Data in allocation | |
135 | * - Time of alloc and free (lifetime) | |
136 | * - Size of allocation | |
137 | */ | |
138 | KALLOC_HEAP_DECLARE(KHEAP_DATA_BUFFERS); | |
39037602 | 139 | |
f427ee49 A |
140 | /** |
141 | * @const KHEAP_KEXT | |
142 | * | |
143 | * @brief | |
144 | * The builtin heap for allocations made by kexts. | |
145 | * | |
146 | * @discussion | |
147 | * This set of kalloc zones should contain allocations from kexts and the | |
148 | * individual zones in this heap are sequestered. | |
149 | */ | |
150 | KALLOC_HEAP_DECLARE(KHEAP_KEXT); | |
39037602 | 151 | |
f427ee49 A |
152 | /** |
153 | * @const KHEAP_DEFAULT | |
154 | * | |
155 | * @brief | |
156 | * The builtin default core kernel kalloc heap. | |
157 | * | |
158 | * @discussion | |
159 | * This set of kalloc zones should contain other objects that don't have their | |
160 | * own security mitigations. The individual zones are themselves sequestered. | |
161 | */ | |
162 | KALLOC_HEAP_DECLARE(KHEAP_DEFAULT); | |
3e170ce0 | 163 | |
f427ee49 A |
164 | /** |
165 | * @const KHEAP_TEMP | |
166 | * | |
167 | * @brief | |
168 | * A heap that represents allocations that are always done in "scope" of | |
169 | * a thread. | |
170 | * | |
171 | * @discussion | |
172 | * Allocations in this heap must be allocated and freed "in scope", which means: | |
173 | * - the thread that did the allocation will be the one doing the free, | |
174 | * - allocations will be freed by the time the thread returns to userspace. | |
175 | * | |
176 | * This is an alias on the @c KHEAP_DEFAULT heap with added checks. | |
177 | */ | |
178 | KALLOC_HEAP_DECLARE(KHEAP_TEMP); | |
3e170ce0 | 179 | |
f427ee49 A |
180 | /*! |
181 | * @macro KALLOC_HEAP_DEFINE | |
182 | * | |
183 | * @abstract | |
184 | * Defines a given kalloc heap view and what it points to. | |
185 | * | |
186 | * @discussion | |
187 | * Kalloc heaps are views over one of the pre-defined builtin heaps | |
188 | * (such as @c KHEAP_DATA_BUFFERS or @c KHEAP_DEFAULT). Instantiating | |
189 | * a new one allows for accounting of allocations through this view. | |
190 | * | |
191 | * Kalloc heap views are initialized during the @c STARTUP_SUB_ZALLOC phase, | |
192 | * as the last rank. If views on zones are created, these must have been | |
193 | * created before this stage. | |
194 | * | |
195 | * @param var the name for the zone view. | |
196 | * @param name a string describing the zone view. | |
197 | * @param heap_id a @c KHEAP_ID_* constant. | |
198 | */ | |
199 | #define KALLOC_HEAP_DEFINE(var, name, heap_id) \ | |
200 | SECURITY_READ_ONLY_LATE(struct kalloc_heap) var[1] = { { \ | |
201 | .kh_name = name, \ | |
202 | .kh_heap_id = heap_id, \ | |
203 | } }; \ | |
204 | STARTUP_ARG(ZALLOC, STARTUP_RANK_LAST, kheap_startup_init, var) | |
3e170ce0 | 205 | |
f427ee49 A |
206 | #define kalloc(size) \ |
207 | kheap_alloc(KHEAP_DEFAULT, size, Z_WAITOK) | |
39037602 | 208 | |
f427ee49 A |
209 | #define kalloc_flags(size, flags) \ |
210 | kheap_alloc(KHEAP_DEFAULT, size, flags) | |
3e170ce0 | 211 | |
f427ee49 A |
212 | #define kalloc_tag(size, itag) \ |
213 | kheap_alloc_tag(KHEAP_DEFAULT, size, Z_WAITOK, itag) | |
39037602 | 214 | |
f427ee49 A |
215 | #define kalloc_tag_bt(size, itag) \ |
216 | kheap_alloc_tag_bt(KHEAP_DEFAULT, size, Z_WAITOK, itag) | |
39037602 | 217 | |
f427ee49 A |
218 | #define krealloc(elem, old_size, new_size, flags) \ |
219 | kheap_realloc(KHEAP_DEFAULT, elem, old_size, new_size, flags) | |
39037602 | 220 | |
f427ee49 A |
221 | /* |
222 | * These versions allow specifying the kalloc heap to allocate memory | |
223 | * from | |
224 | */ | |
225 | #define kheap_alloc(kalloc_heap, size, flags) \ | |
226 | ({ VM_ALLOC_SITE_STATIC(0, 0); \ | |
227 | kalloc_ext(kalloc_heap, size, flags, &site).addr; }) | |
39037602 | 228 | |
f427ee49 A |
229 | #define kheap_alloc_tag(kalloc_heap, size, flags, itag) \ |
230 | ({ VM_ALLOC_SITE_STATIC(0, (itag)); \ | |
231 | kalloc_ext(kalloc_heap, size, flags, &site).addr; }) | |
39037602 | 232 | |
f427ee49 A |
233 | #define kheap_alloc_tag_bt(kalloc_heap, size, flags, itag) \ |
234 | ({ VM_ALLOC_SITE_STATIC(VM_TAG_BT, (itag)); \ | |
235 | kalloc_ext(kalloc_heap, size, flags, &site).addr; }) | |
39037602 | 236 | |
f427ee49 A |
237 | #define kheap_realloc(kalloc_heap, elem, old_size, new_size, flags) \ |
238 | ({ VM_ALLOC_SITE_STATIC(0, 0); \ | |
239 | krealloc_ext(kalloc_heap, elem, old_size, new_size, flags, &site).addr; }) | |
39037602 | 240 | |
f427ee49 A |
241 | extern void |
242 | kfree( | |
243 | void *data, | |
244 | vm_size_t size); | |
3e170ce0 | 245 | |
f427ee49 A |
246 | extern void |
247 | kheap_free( | |
248 | kalloc_heap_t heap, | |
249 | void *data, | |
250 | vm_size_t size); | |
3e170ce0 | 251 | |
f427ee49 A |
252 | __abortlike |
253 | extern void | |
254 | kheap_temp_leak_panic(thread_t self); | |
1c79356b | 255 | |
f427ee49 A |
256 | #else /* XNU_KERNEL_PRIVATE */ |
257 | ||
258 | extern void *kalloc(vm_size_t size) __attribute__((alloc_size(1))); | |
1c79356b | 259 | |
f427ee49 | 260 | extern void kfree(void *data, vm_size_t size); |
9bccf70c | 261 | |
3e170ce0 | 262 | #endif /* !XNU_KERNEL_PRIVATE */ |
f427ee49 A |
263 | #pragma mark implementation details |
264 | #if XNU_KERNEL_PRIVATE | |
265 | #pragma GCC visibility push(hidden) | |
3e170ce0 | 266 | |
f427ee49 A |
267 | /* Used by kern_os_* and operator new */ |
268 | KALLOC_HEAP_DECLARE(KERN_OS_MALLOC); | |
269 | ||
270 | extern void kheap_startup_init( | |
271 | kalloc_heap_t heap); | |
9bccf70c | 272 | |
1c79356b | 273 | |
f427ee49 A |
274 | /* |
275 | * This type is used so that kalloc_internal has good calling conventions | |
276 | * for callers who want to cheaply both know the allocated address | |
277 | * and the actual size of the allocation. | |
278 | */ | |
279 | struct kalloc_result { | |
280 | void *addr; | |
281 | vm_size_t size; | |
282 | }; | |
283 | ||
284 | extern struct kalloc_result | |
285 | kalloc_ext( | |
286 | kalloc_heap_t kheap, | |
287 | vm_size_t size, | |
288 | zalloc_flags_t flags, | |
289 | vm_allocation_site_t *site); | |
290 | ||
291 | extern struct kalloc_result | |
292 | krealloc_ext( | |
293 | kalloc_heap_t kheap, | |
294 | void *addr, | |
295 | vm_size_t old_size, | |
296 | vm_size_t new_size, | |
297 | zalloc_flags_t flags, | |
298 | vm_allocation_site_t *site); | |
299 | ||
300 | extern struct kalloc_result | |
301 | kheap_realloc_addr( | |
302 | kalloc_heap_t kheap, | |
303 | void *addr, | |
304 | vm_size_t new_size, | |
305 | zalloc_flags_t flags, | |
306 | vm_allocation_site_t *site); | |
1c79356b | 307 | |
6d2010ae | 308 | |
f427ee49 A |
309 | /* these versions update the size reference with the actual size allocated */ |
310 | ||
311 | static inline void * | |
312 | kallocp_ext( | |
313 | kalloc_heap_t kheap, | |
314 | vm_size_t *size, | |
315 | zalloc_flags_t flags, | |
316 | vm_allocation_site_t *site) | |
317 | { | |
318 | struct kalloc_result kar = kalloc_ext(kheap, *size, flags, site); | |
319 | *size = kar.size; | |
320 | return kar.addr; | |
321 | } | |
322 | ||
323 | #define kallocp(sizep) \ | |
324 | ({ VM_ALLOC_SITE_STATIC(0, 0); \ | |
325 | kallocp_ext(KHEAP_DEFAULT, sizep, Z_WAITOK, &site); }) | |
326 | ||
327 | #define kallocp_tag(sizep, itag) \ | |
328 | ({ VM_ALLOC_SITE_STATIC(0, (itag)); \ | |
329 | kallocp_ext(KHEAP_DEFAULT, sizep, Z_WAITOK, &site); }) | |
330 | ||
331 | #define kallocp_tag_bt(sizep, itag) \ | |
332 | ({ VM_ALLOC_SITE_STATIC(VM_TAG_BT, (itag)); \ | |
333 | kallocp_ext(KHEAP_DEFAULT, sizep, Z_WAITOK, &site); }) | |
334 | ||
335 | extern vm_size_t | |
336 | kalloc_size( | |
337 | void *addr); | |
338 | ||
339 | extern void | |
340 | kheap_free_addr( | |
341 | kalloc_heap_t heap, | |
342 | void *addr); | |
343 | ||
344 | extern vm_size_t | |
345 | kalloc_bucket_size( | |
346 | vm_size_t size); | |
347 | ||
348 | /* | |
349 | * These macros set "elem" to NULL on free. | |
350 | * | |
351 | * Note: all values passed to k*free() might be in the element to be freed, | |
352 | * temporaries must be taken, and the resetting to be done prior to free. | |
353 | */ | |
354 | #define kfree(elem, size) ({ \ | |
355 | _Static_assert(sizeof(elem) == sizeof(void *), "elem isn't pointer sized"); \ | |
356 | __auto_type __kfree_eptr = &(elem); \ | |
357 | __auto_type __kfree_elem = *__kfree_eptr; \ | |
358 | __auto_type __kfree_size = (size); \ | |
359 | *__kfree_eptr = (__typeof__(__kfree_elem))NULL; \ | |
360 | (kfree)((void *)__kfree_elem, __kfree_size); \ | |
361 | }) | |
362 | ||
363 | #define kheap_free(heap, elem, size) ({ \ | |
364 | _Static_assert(sizeof(elem) == sizeof(void *), "elem isn't pointer sized"); \ | |
365 | __auto_type __kfree_heap = (heap); \ | |
366 | __auto_type __kfree_eptr = &(elem); \ | |
367 | __auto_type __kfree_elem = *__kfree_eptr; \ | |
368 | __auto_type __kfree_size = (size); \ | |
369 | *__kfree_eptr = (__typeof__(__kfree_elem))NULL; \ | |
370 | (kheap_free)(__kfree_heap, (void *)__kfree_elem, __kfree_size); \ | |
371 | }) | |
372 | ||
373 | #define kheap_free_addr(heap, elem) ({ \ | |
374 | _Static_assert(sizeof(elem) == sizeof(void *), "elem isn't pointer sized"); \ | |
375 | __auto_type __kfree_heap = (heap); \ | |
376 | __auto_type __kfree_eptr = &(elem); \ | |
377 | __auto_type __kfree_elem = *__kfree_eptr; \ | |
378 | *__kfree_eptr = (__typeof__(__kfree_elem))NULL; \ | |
379 | (kheap_free_addr)(__kfree_heap, (void *)__kfree_elem); \ | |
380 | }) | |
381 | ||
382 | extern zone_t | |
383 | kalloc_heap_zone_for_size( | |
384 | kalloc_heap_t heap, | |
385 | vm_size_t size); | |
1c79356b | 386 | |
91447636 | 387 | extern vm_size_t kalloc_max_prerounded; |
b0d623f7 | 388 | extern vm_size_t kalloc_large_total; |
1c79356b | 389 | |
f427ee49 A |
390 | extern void |
391 | kern_os_kfree( | |
392 | void *addr, | |
393 | vm_size_t size); | |
394 | ||
395 | #pragma GCC visibility pop | |
396 | #endif /* XNU_KERNEL_PRIVATE */ | |
397 | ||
398 | extern void | |
399 | kern_os_zfree( | |
400 | zone_t zone, | |
401 | void *addr, | |
402 | vm_size_t size); | |
403 | ||
404 | __END_DECLS | |
9bccf70c | 405 | |
0a7de745 | 406 | #endif /* _KERN_KALLOC_H_ */ |
91447636 | 407 | |
0a7de745 | 408 | #endif /* KERNEL_PRIVATE */ |