kalloc.h
1 /* 2 * Copyright (c) 2000-2020 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 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 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 /* 29 * @OSF_COPYRIGHT@ 30 */ 31 /* 32 * Mach Operating System 33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University 34 * All Rights Reserved. 35 * 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. 41 * 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. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56 57 #ifdef KERNEL_PRIVATE 58 59 #ifndef _KERN_KALLOC_H_ 60 #define _KERN_KALLOC_H_ 61 62 #include <mach/machine/vm_types.h> 63 #include <mach/boolean.h> 64 #include <mach/vm_types.h> 65 #include <kern/zalloc.h> 66 67 __BEGIN_DECLS 68 69 #if XNU_KERNEL_PRIVATE 70 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] 98 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) 114 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); 139 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); 151 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); 163 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); 179 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) 205 206 #define kalloc(size) \ 207 kheap_alloc(KHEAP_DEFAULT, size, Z_WAITOK) 208 209 #define kalloc_flags(size, flags) \ 210 kheap_alloc(KHEAP_DEFAULT, size, flags) 211 212 #define kalloc_tag(size, itag) \ 213 kheap_alloc_tag(KHEAP_DEFAULT, size, Z_WAITOK, itag) 214 215 #define kalloc_tag_bt(size, itag) \ 216 kheap_alloc_tag_bt(KHEAP_DEFAULT, size, Z_WAITOK, itag) 217 218 #define krealloc(elem, old_size, new_size, flags) \ 219 kheap_realloc(KHEAP_DEFAULT, elem, old_size, new_size, flags) 220 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; }) 228 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; }) 232 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; }) 236 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; }) 240 241 extern void 242 kfree( 243 void *data, 244 vm_size_t size); 245 246 extern void 247 kheap_free( 248 kalloc_heap_t heap, 249 void *data, 250 vm_size_t size); 251 252 __abortlike 253 extern void 254 kheap_temp_leak_panic(thread_t self); 255 256 #else /* XNU_KERNEL_PRIVATE */ 257 258 extern void *kalloc(vm_size_t size) __attribute__((alloc_size(1))); 259 260 extern void kfree(void *data, vm_size_t size); 261 262 #endif /* !XNU_KERNEL_PRIVATE */ 263 #pragma mark implementation details 264 #if XNU_KERNEL_PRIVATE 265 #pragma GCC visibility push(hidden) 266 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); 272 273 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); 307 308 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); 386 387 extern vm_size_t kalloc_max_prerounded; 388 extern vm_size_t kalloc_large_total; 389 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 405 406 #endif /* _KERN_KALLOC_H_ */ 407 408 #endif /* KERNEL_PRIVATE */