1 /*
2 * Copyright (c) 2024 Apple 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 #ifndef _VM_SANITIZE_INTERNAL_H_
30 #define _VM_SANITIZE_INTERNAL_H_
31
32 #include <mach/vm_types_unsafe.h>
33 #include <mach/error.h>
34 #include <stdbool.h>
35 #include <vm/vm_sanitize_telemetry.h>
36
37 __BEGIN_DECLS
38 #pragma GCC visibility push(hidden)
39
40 /*
41 * kern_return_t errors used internally by VM
42 */
43
44 /*!
45 * @define VM_ERR_RETURN_NOW
46 * @abstract Communicate to a caller that they should
47 * return @c KERN_SUCCESS immediately after completing sanitization checks.
48 */
49 #define VM_ERR_RETURN_NOW (err_vm | err_sub(0) | 1)
50
51 /*!
52 * @function vm_sanitize_get_kr
53 * @abstract When a VM sanitizer returns an error, use this to extract
54 * the real value that the sanitizers request that you return.
55 *
56 * @discussion errno-returning callers may need to transform this result further
57 *
58 * @param kr error code set by the sanitizers
59 * @returns a (possibly different) error code
60 */
61 static inline
62 kern_return_t
vm_sanitize_get_kr(kern_return_t kr)63 vm_sanitize_get_kr(kern_return_t kr)
64 {
65 if (kr == VM_ERR_RETURN_NOW) {
66 return KERN_SUCCESS;
67 }
68 return kr;
69 }
70
71 /*!
72 * @enum vm_sanitize_caller_id_t
73 *
74 * @brief
75 * IDs for callers of sanitization functions that have different
76 * set of return values.
77 */
78 __enum_closed_decl(vm_sanitize_caller_id_t, uint32_t, {
79 VM_SANITIZE_CALLER_ID_NONE,
80
81 /* memory entry */
82 VM_SANITIZE_CALLER_ID_MACH_MAKE_MEMORY_ENTRY,
83 VM_SANITIZE_CALLER_ID_MACH_MEMORY_ENTRY_PAGE_OP,
84 VM_SANITIZE_CALLER_ID_MACH_MEMORY_ENTRY_RANGE_OP,
85 VM_SANITIZE_CALLER_ID_MACH_MEMORY_ENTRY_MAP_SIZE,
86 VM_SANITIZE_CALLER_ID_MACH_MEMORY_OBJECT_MEMORY_ENTRY,
87
88 /* alloc/dealloc */
89 VM_SANITIZE_CALLER_ID_VM_ALLOCATE_FIXED,
90 VM_SANITIZE_CALLER_ID_VM_ALLOCATE_ANYWHERE,
91 VM_SANITIZE_CALLER_ID_VM_DEALLOCATE,
92 VM_SANITIZE_CALLER_ID_MUNMAP,
93
94 /* map/remap */
95 VM_SANITIZE_CALLER_ID_VM_MAP_REMAP,
96 VM_SANITIZE_CALLER_ID_MMAP,
97 VM_SANITIZE_CALLER_ID_MREMAP_ENCRYPTED,
98 VM_SANITIZE_CALLER_ID_MAP_WITH_LINKING_NP,
99 VM_SANITIZE_CALLER_ID_ENTER_MEM_OBJ,
100 VM_SANITIZE_CALLER_ID_ENTER_MEM_OBJ_CTL,
101
102 /* wire/unwire */
103 VM_SANITIZE_CALLER_ID_VM_WIRE_USER,
104 VM_SANITIZE_CALLER_ID_VM_UNWIRE_USER,
105 VM_SANITIZE_CALLER_ID_VM_MAP_WIRE,
106 VM_SANITIZE_CALLER_ID_VM_MAP_UNWIRE,
107 VM_SANITIZE_CALLER_ID_VSLOCK,
108 VM_SANITIZE_CALLER_ID_VSUNLOCK,
109
110 /* copyin/copyout */
111 VM_SANITIZE_CALLER_ID_VM_MAP_COPY_OVERWRITE,
112 VM_SANITIZE_CALLER_ID_VM_MAP_COPYIN,
113 VM_SANITIZE_CALLER_ID_VM_MAP_READ_USER,
114 VM_SANITIZE_CALLER_ID_VM_MAP_WRITE_USER,
115
116 /* inherit */
117 VM_SANITIZE_CALLER_ID_VM_MAP_INHERIT,
118 VM_SANITIZE_CALLER_ID_MINHERIT,
119
120 /* protect */
121 VM_SANITIZE_CALLER_ID_VM_MAP_PROTECT,
122 VM_SANITIZE_CALLER_ID_MPROTECT,
123 VM_SANITIZE_CALLER_ID_USERACC,
124
125 /* behavior */
126 VM_SANITIZE_CALLER_ID_VM_BEHAVIOR_SET,
127 VM_SANITIZE_CALLER_ID_MADVISE,
128
129 /* msync */
130 VM_SANITIZE_CALLER_ID_VM_MAP_MSYNC,
131 VM_SANITIZE_CALLER_ID_MSYNC,
132
133 /* machine attribute */
134 VM_SANITIZE_CALLER_ID_VM_MAP_MACHINE_ATTRIBUTE,
135
136 /* page info */
137 VM_SANITIZE_CALLER_ID_VM_MAP_PAGE_RANGE_INFO,
138 VM_SANITIZE_CALLER_ID_VM_MAP_PAGE_RANGE_QUERY,
139 VM_SANITIZE_CALLER_ID_MINCORE,
140
141 /* single */
142 VM_SANITIZE_CALLER_ID_MACH_VM_DEFERRED_RECLAMATION_BUFFER_INIT,
143 VM_SANITIZE_CALLER_ID_MACH_VM_RANGE_CREATE,
144 VM_SANITIZE_CALLER_ID_SHARED_REGION_MAP_AND_SLIDE_2_NP,
145
146 /* test */
147 VM_SANITIZE_CALLER_ID_TEST
148 });
149
150 /*!
151 * @enum vm_sanitize_flags_t
152 *
153 * @brief
154 * Flags that influence the sanitization being performed.
155 *
156 * @const VM_SANITIZE_FLAGS_NONE
157 * Default value.
158 *
159 * @const VM_SANITIZE_FLAGS_CHECK_ALIGNED_START
160 * Checks that the start address is aligned to map page size.
161 *
162 * @const VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS
163 * In sanitizers that have a @c size parameter, the sanitizer will ask
164 * the caller to return @c KERN_SUCCESS when @c size @c == @c 0.
165 *
166 * Exactly one of @c VM_SANITIZE_FLAGS_SIZE_ZERO_* must be passed to sanitizers
167 * that return a sanitized size.
168 *
169 * @const VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS
170 * In sanitizers that have a @c size parameter, the sanitizer will ask
171 * the caller to return @c KERN_INVALID_ARGUMENT when @c size @c == @c 0.
172 *
173 * Exactly one of @c VM_SANITIZE_FLAGS_SIZE_ZERO_* must be passed to sanitizers
174 * that return a sanitized size.
175 *
176 * @const VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH
177 * In sanitizers that have a @c size parameter, the sanitizer will not ask
178 * the caller to return when @c size @c == @c 0, thus falling through into
179 * the caller's implementation.
180 *
181 * Exactly one of @c VM_SANITIZE_FLAGS_SIZE_ZERO_* must be passed to sanitizers
182 * that return a sanitized size.
183 *
184 * @const VM_SANITIZE_FLAGS_GET_UNALIGNED_VALUES
185 * Return unaligned start/end/size rather than realigned values.
186 *
187 * @const VM_SANITIZE_FLAGS_REALIGN_START
188 * Ignore the misaligned bits of the start address when sanitizing an address.
189 *
190 * @const VM_SANITIZE_FLAGS_CHECK_USER_MEM_MAP_FLAGS
191 * Reject non user allowed mem map flags for memory entry.
192 *
193 * @const VM_SANITIZE_FLAGS_CANONICALIZE
194 * Canonicalize address for KASAN_TBI
195 *
196 * @const VM_SANITIZE_FLAGS_CHECK_ALIGNED_SIZE
197 * Checks that the size is aligned to map page size.
198 *
199 * @const VM_SANITIZE_FLAGS_CHECK_ADDR_RANGE
200 * Checks that computing values within the range [start, end) does not overflow
201 * into bits above the supported VA bits for the system. These bits may be used
202 * by the kernel or hardware to store additional values.
203 */
204
205 __options_closed_decl(vm_sanitize_flags_t, uint32_t, {
206 VM_SANITIZE_FLAGS_NONE = 0x00000000,
207 VM_SANITIZE_FLAGS_CHECK_ALIGNED_START = 0x00000001,
208 VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS = 0x00000002,
209 VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS = 0x00000004,
210 VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH = 0x00000008,
211 VM_SANITIZE_FLAGS_GET_UNALIGNED_VALUES = 0x00000010,
212 VM_SANITIZE_FLAGS_REALIGN_START = 0x00000020,
213 VM_SANITIZE_FLAGS_CHECK_USER_MEM_MAP_FLAGS = 0x00000040,
214 VM_SANITIZE_FLAGS_CANONICALIZE = 0x00000080,
215 VM_SANITIZE_FLAGS_CHECK_ALIGNED_SIZE = 0x00000100,
216 VM_SANITIZE_FLAGS_CHECK_ADDR_RANGE = 0x00000200,
217 });
218
219 #define __vm_sanitize_bits_one_of(flags) \
220 ((flags) != 0 && ((flags) & ((flags) - 1)) == 0)
221
222 #define __vm_sanitize_assert_one_of(arg, mask) \
223 __attribute__((diagnose_if(!__vm_sanitize_bits_one_of((arg) & (mask)), \
224 "`" #arg "` must have one of these flags `" #mask "`", "error")))
225
226 #define __vm_sanitize_require_size_zero_flag(arg) \
227 __vm_sanitize_assert_one_of(arg, \
228 VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS | VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS | VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH)
229
230 /*
231 * Error compat rewrite result:
232 * compat_kr: the more-compatible return value
233 * should_rewrite: true if compat_kr should be returned
234 * should_telemeter: true if compat_kr should be telemetered
235 */
236 typedef struct {
237 kern_return_t compat_kr;
238 bool should_rewrite;
239 bool should_telemeter;
240 } vm_sanitize_compat_rewrite_t;
241
242 typedef vm_sanitize_compat_rewrite_t (*vm_sanitize_err_compat_addr_size_fn)(kern_return_t kr,
243 vm_address_t addr, vm_size_t size, vm_offset_t pgmask, vm_map_t map_or_null);
244 typedef vm_sanitize_compat_rewrite_t (*vm_sanitize_err_compat_cur_and_max_prots_fn)(kern_return_t kr,
245 vm_prot_t *cur_inout, vm_prot_t *max_inout, vm_prot_t extra_mask);
246
247 typedef const struct vm_sanitize_caller {
248 vm_sanitize_caller_id_t vmsc_caller_id;
249 const char *vmsc_caller_name;
250 vm_sanitize_method_t vmsc_telemetry_id;
251 enum vm_sanitize_subsys_error_codes vmsc_ktriage_id;
252
253 vm_sanitize_err_compat_addr_size_fn err_compat_addr_size;
254 vm_sanitize_err_compat_cur_and_max_prots_fn err_compat_prot_cur_max;
255 } *vm_sanitize_caller_t;
256
257 /*
258 * Macros to declare and define callers of sanitization functions
259 */
260 #define VM_SANITIZE_DECL_CALLER(name) \
261 extern vm_sanitize_caller_t const VM_SANITIZE_CALLER_ ## name;
262
263 #define VM_SANITIZE_DEFINE_CALLER(name, ... /* error compat functions */) \
264 static const struct vm_sanitize_caller vm_sanitize_caller_storage_ ## name = { \
265 .vmsc_caller_id = VM_SANITIZE_CALLER_ID_ ## name, \
266 .vmsc_caller_name = #name, \
267 .vmsc_telemetry_id = VM_SANITIZE_METHOD_ ## name, \
268 .vmsc_ktriage_id = KDBG_TRIAGE_VM_SANITIZE_ ## name, \
269 __VA_ARGS__ \
270 }; \
271 vm_sanitize_caller_t const VM_SANITIZE_CALLER_ ## name = &vm_sanitize_caller_storage_ ## name
272
273 /*
274 * Declaration of callers of VM sanitization functions
275 */
276 /* memory entry */
277 VM_SANITIZE_DECL_CALLER(MACH_MAKE_MEMORY_ENTRY);
278 VM_SANITIZE_DECL_CALLER(MACH_MEMORY_ENTRY_PAGE_OP);
279 VM_SANITIZE_DECL_CALLER(MACH_MEMORY_ENTRY_RANGE_OP);
280 VM_SANITIZE_DECL_CALLER(MACH_MEMORY_ENTRY_MAP_SIZE);
281 VM_SANITIZE_DECL_CALLER(MACH_MEMORY_OBJECT_MEMORY_ENTRY);
282
283 /* alloc/dealloc */
284 VM_SANITIZE_DECL_CALLER(VM_ALLOCATE_FIXED);
285 VM_SANITIZE_DECL_CALLER(VM_ALLOCATE_ANYWHERE);
286 VM_SANITIZE_DECL_CALLER(VM_DEALLOCATE);
287 VM_SANITIZE_DECL_CALLER(MUNMAP);
288
289 /* map/remap */
290 VM_SANITIZE_DECL_CALLER(VM_MAP_REMAP);
291 VM_SANITIZE_DECL_CALLER(MMAP);
292 VM_SANITIZE_DECL_CALLER(MREMAP_ENCRYPTED);
293 VM_SANITIZE_DECL_CALLER(MAP_WITH_LINKING_NP);
294 VM_SANITIZE_DECL_CALLER(ENTER_MEM_OBJ);
295 VM_SANITIZE_DECL_CALLER(ENTER_MEM_OBJ_CTL);
296
297 /* wire/unwire */
298 VM_SANITIZE_DECL_CALLER(VM_WIRE_USER);
299 VM_SANITIZE_DECL_CALLER(VM_UNWIRE_USER);
300 VM_SANITIZE_DECL_CALLER(VM_MAP_WIRE);
301 VM_SANITIZE_DECL_CALLER(VM_MAP_UNWIRE);
302 VM_SANITIZE_DECL_CALLER(VSLOCK);
303 VM_SANITIZE_DECL_CALLER(VSUNLOCK);
304
305 /* copyin/copyout */
306 VM_SANITIZE_DECL_CALLER(VM_MAP_COPY_OVERWRITE);
307 VM_SANITIZE_DECL_CALLER(VM_MAP_COPYIN);
308 VM_SANITIZE_DECL_CALLER(VM_MAP_READ_USER);
309 VM_SANITIZE_DECL_CALLER(VM_MAP_WRITE_USER);
310
311 /* inherit */
312 VM_SANITIZE_DECL_CALLER(MACH_VM_INHERIT);
313 VM_SANITIZE_DECL_CALLER(VM_INHERIT);
314 VM_SANITIZE_DECL_CALLER(VM32_INHERIT);
315 VM_SANITIZE_DECL_CALLER(VM_MAP_INHERIT);
316 VM_SANITIZE_DECL_CALLER(MINHERIT);
317
318 /* protect */
319 VM_SANITIZE_DECL_CALLER(MACH_VM_PROTECT);
320 VM_SANITIZE_DECL_CALLER(VM_PROTECT);
321 VM_SANITIZE_DECL_CALLER(VM32_PROTECT);
322 VM_SANITIZE_DECL_CALLER(VM_MAP_PROTECT);
323 VM_SANITIZE_DECL_CALLER(MPROTECT);
324 VM_SANITIZE_DECL_CALLER(USERACC);
325
326 /* behavior */
327 VM_SANITIZE_DECL_CALLER(VM_BEHAVIOR_SET);
328 VM_SANITIZE_DECL_CALLER(MADVISE);
329
330 /* msync */
331 VM_SANITIZE_DECL_CALLER(VM_MAP_MSYNC);
332 VM_SANITIZE_DECL_CALLER(MSYNC);
333
334 /* machine attribute */
335 VM_SANITIZE_DECL_CALLER(VM_MAP_MACHINE_ATTRIBUTE);
336
337 /* page info */
338 VM_SANITIZE_DECL_CALLER(VM_MAP_PAGE_RANGE_INFO);
339 VM_SANITIZE_DECL_CALLER(VM_MAP_PAGE_RANGE_QUERY);
340 VM_SANITIZE_DECL_CALLER(MINCORE);
341
342 /* single */
343 VM_SANITIZE_DECL_CALLER(MACH_VM_DEFERRED_RECLAMATION_BUFFER_INIT);
344 VM_SANITIZE_DECL_CALLER(MACH_VM_RANGE_CREATE);
345 VM_SANITIZE_DECL_CALLER(SHARED_REGION_MAP_AND_SLIDE_2_NP);
346
347 /* test */
348 VM_SANITIZE_DECL_CALLER(TEST);
349
350 /*
351 * Macro that extracts the inner struct member from a wrapped type. Should be
352 * used in all cases, including validation functions, when accessing the
353 * inner struct member.
354 */
355 #define VM_SANITIZE_UNSAFE_UNWRAP(_val) (_val).UNSAFE
356
357 /*
358 * Macro to check if unsafe value is a specific safe value
359 */
360 #define VM_SANITIZE_UNSAFE_IS_EQUAL(_var, _val) ((_var).UNSAFE == (_val))
361
362 /*
363 * Macro to check if unsafe value is zero
364 */
365 #define VM_SANITIZE_UNSAFE_IS_ZERO(_var) VM_SANITIZE_UNSAFE_IS_EQUAL(_var, 0)
366
367 /*
368 * returns whether a given unsafe value fits a given type
369 */
370 #define VM_SANITIZE_UNSAFE_FITS(_var, type_t) ({ \
371 __auto_type __tmp = (_var).UNSAFE; \
372 __tmp == (type_t)__tmp; \
373 })
374
375 /*
376 * Macro that sets a value of unsafe type to a value of safe type.
377 * This is safe to do because we are only forcing ourselves to perform
378 * checks on a value we already have direct access to.
379 */
380 #define VM_SANITIZE_UT_SET(_var, _val) ((_var).UNSAFE) = (_val)
381
382 /*!
383 * @function vm_sanitize_wrap_addr
384 *
385 * @abstract
386 * Function that wraps unsanitized safe address into unsafe address
387 *
388 * @param val safe address
389 * @returns unsafe address
390 */
391 __attribute__((always_inline, warn_unused_result))
392 vm_addr_struct_t vm_sanitize_wrap_addr(vm_address_t val);
393
394 /*!
395 * @function vm_sanitize_wrap_addr_ref
396 *
397 * @abstract
398 * Function that wraps a safe address pointer,
399 * into unsafe address pointer.
400 *
401 * @param val safe address ref
402 * @returns unsafe address reference
403 */
404 #define vm_sanitize_wrap_addr_ref(var) _Generic(var, \
405 mach_vm_address_t *: (vm_addr_struct_t *)(var), \
406 vm_address_t *: (vm_addr_struct_t *)(var), \
407 default: (var))
408
409 /*!
410 * @function vm_sanitize_wrap_size
411 *
412 * @abstract
413 * Function that wraps unsanitized safe size into unsafe size
414 *
415 * @param val safe size
416 * @returns unsafe size
417 */
418 __attribute__((always_inline, warn_unused_result))
419 vm_size_struct_t vm_sanitize_wrap_size(vm_size_t val);
420
421 /*
422 * bsd doesn't use 32bit interfaces and the types aren't even defined for them,
423 * so we just expose this to MACH.
424 */
425 #ifdef MACH_KERNEL_PRIVATE
426 /*!
427 * @function vm32_sanitize_wrap_size
428 *
429 * @abstract
430 * Function that wraps unsanitized 32bit safe size into 32bit unsafe size
431 *
432 * @param val safe size
433 * @returns unsafe size
434 */
435 __attribute__((always_inline, warn_unused_result))
436 vm32_size_struct_t vm32_sanitize_wrap_size(vm32_size_t val);
437 #endif /* MACH_KERNEL_PRIVATE */
438
439 /*!
440 * @function vm_sanitize_wrap_prot
441 *
442 * @abstract
443 * Function that wraps unsanitized safe protection into unsafe protection
444 *
445 * @param val safe protection
446 * @returns unsafe protection
447 */
448 __attribute__((always_inline, warn_unused_result))
449 vm_prot_ut vm_sanitize_wrap_prot(vm_prot_t val);
450
451 /*!
452 * @function vm_sanitize_wrap_prot_ref
453 *
454 * @abstract
455 * Function that wraps a safe protection pointer into unsafe protection pointer.
456 *
457 * @param val safe protection pointer
458 * @returns unsafe protection pointer
459 */
460 __attribute__((always_inline, warn_unused_result))
461 static inline vm_prot_ut *
vm_sanitize_wrap_prot_ref(vm_prot_t * val)462 vm_sanitize_wrap_prot_ref(vm_prot_t *val)
463 {
464 return (vm_prot_ut *)val;
465 }
466
467 /*!
468 * @function vm_sanitize_wrap_inherit
469 *
470 * @abstract
471 * Function that wraps unsanitized safe vm_inherit into unsafe vm_inherit
472 *
473 * @param val safe vm_inherit
474 * @returns unsafe vm_inherit
475 */
476 __attribute__((always_inline, warn_unused_result))
477 vm_inherit_ut vm_sanitize_wrap_inherit(vm_inherit_t val);
478
479 /*!
480 * @function vm_sanitize_wrap_behavior
481 *
482 * @abstract
483 * Function that wraps a safe vm_behavior into an unsafe vm_behavior
484 *
485 * @param val safe vm_behavior
486 * @returns unsafe vm_behavior
487 */
488 __attribute__((always_inline, warn_unused_result))
489 vm_behavior_ut vm_sanitize_wrap_behavior(vm_behavior_t val);
490
491 #ifdef MACH_KERNEL_PRIVATE
492
493 /*!
494 * @function vm_sanitize_expand_addr_to_64
495 *
496 * @abstract
497 * Function used by the vm32 functions to cast 32bit unsafe address
498 * to 64bit unsafe address
499 *
500 * @param val 32bit unsafe address
501 * @returns 64bit unsafe address
502 */
503 __attribute__((always_inline, warn_unused_result))
504 vm_addr_struct_t vm_sanitize_expand_addr_to_64(vm32_address_ut val);
505
506 /*!
507 * @function vm_sanitize_expand_size_to_64
508 *
509 * @abstract
510 * Function used by the vm32 functions to cast 32bit unsafe size
511 * to 64bit unsafe size
512 *
513 * @param val 32bit unsafe size
514 * @returns 64bit unsafe size
515 */
516 __attribute__((always_inline, warn_unused_result))
517 vm_size_struct_t vm_sanitize_expand_size_to_64(vm32_size_ut val);
518
519 /*!
520 * @function vm_sanitize_trunc_addr_to_32
521 *
522 * @abstract
523 * Function used by the vm32 functions to cast 64bit unsafe address
524 * to 32bit unsafe address
525 *
526 * @param val 64bit unsafe address
527 * @returns 32bit unsafe address
528 */
529 __attribute__((always_inline, warn_unused_result))
530 vm32_address_ut vm_sanitize_trunc_addr_to_32(vm_addr_struct_t val);
531
532 /*!
533 * @function vm_sanitize_trunc_size_to_32
534 *
535 * @abstract
536 * Function used by the vm32 functions to cast 64bit unsafe size
537 * to 32bit unsafe size
538 *
539 * @param val 64bit unsafe size
540 * @returns 32bit unsafe size
541 */
542 __attribute__((always_inline, warn_unused_result))
543 vm32_size_ut vm_sanitize_trunc_size_to_32(vm_size_struct_t val);
544
545 /*!
546 * @function vm_sanitize_add_overflow()
547 *
548 * @abstract
549 * Computes the sum of an address and a size checking for overflow,
550 * staying in the unsafe world.
551 *
552 * @param addr_u unsafe address
553 * @param size_u unsafe size
554 * @param addr_out_u unsafe result
555 * @returns whether the operation overflowed
556 */
557 __attribute__((always_inline, warn_unused_result, overloadable))
558 bool vm_sanitize_add_overflow(
559 vm32_address_ut addr_u,
560 vm32_size_ut size_u,
561 vm32_address_ut *addr_out_u);
562
563 #endif /* MACH_KERNEL_PRIVATE */
564
565 /*!
566 * @function vm_sanitize_add_overflow()
567 *
568 * @abstract
569 * Computes the sum of an address and a size checking for overflow,
570 * staying in the unsafe world.
571 *
572 * @param addr_u unsafe address
573 * @param size_u unsafe size
574 * @param addr_out_u unsafe result
575 * @returns whether the operation overflowed
576 */
577 __attribute__((always_inline, warn_unused_result, overloadable))
578 bool vm_sanitize_add_overflow(
579 vm_addr_struct_t addr_u,
580 vm_size_struct_t size_u,
581 vm_addr_struct_t *addr_out_u);
582
583 /*!
584 * @function vm_sanitize_add_overflow()
585 *
586 * @abstract
587 * Computes the sum of two sizes checking for overflow,
588 * staying in the unsafe world.
589 *
590 * @param size1_u unsafe size 1
591 * @param size2_u unsafe size 2
592 * @param size_out_u unsafe result
593 * @returns whether the operation overflowed
594 */
595 __attribute__((always_inline, warn_unused_result, overloadable))
596 bool vm_sanitize_add_overflow(
597 vm_size_struct_t size1_u,
598 vm_size_struct_t size2_u,
599 vm_size_struct_t *size_out_u);
600
601 /*!
602 * @function vm_sanitize_compute_ut_end
603 *
604 * @abstract
605 * Computes and returns unsafe end from unsafe start and size
606 *
607 * @param addr_u unsafe start
608 * @param size_u unsafe size
609 * @returns unsafe end
610 */
611 __attribute__((always_inline, warn_unused_result))
612 vm_addr_struct_t vm_sanitize_compute_ut_end(
613 vm_addr_struct_t addr_u,
614 vm_size_struct_t size_u);
615
616 /*!
617 * @function vm_sanitize_compute_ut_size
618 *
619 * @abstract
620 * Computes and returns unsafe size from unsafe start and end
621 *
622 * @param addr_u unsafe start
623 * @param end_u unsafe end
624 * @returns unsafe size
625 */
626 __attribute__((always_inline, warn_unused_result))
627 vm_size_struct_t vm_sanitize_compute_ut_size(
628 vm_addr_struct_t addr_u,
629 vm_addr_struct_t end_u);
630
631 /*!
632 * @function vm_sanitize_addr
633 *
634 * @abstract
635 * Sanitization function that takes unsafe address, and returns a truncated
636 * address.
637 *
638 * @param map map the address belongs to
639 * @param addr_u unsafe address to sanitize
640 * @returns a sanitized address
641 */
642 __attribute__((always_inline, warn_unused_result))
643 mach_vm_address_t vm_sanitize_addr(
644 vm_map_t map,
645 vm_addr_struct_t addr_u);
646
647 /*!
648 * @function vm_sanitize_offset_in_page
649 *
650 * @abstract
651 * Sanitization function that takes unsafe address,
652 * and returns the offset in the page for this address.
653 *
654 * @param mask page mask to use
655 * @param addr_u unsafe address to sanitize
656 * @returns a sanitized offset in page
657 */
658 __attribute__((always_inline, warn_unused_result))
659 mach_vm_offset_t vm_sanitize_offset_in_page(
660 vm_map_offset_t mask,
661 vm_addr_struct_t addr_u);
662
663 /*
664 * @function vm_sanitize_offset_in_page
665 *
666 * @abstract
667 * Sanitization function that takes unsafe address,
668 * and returns the offset in the page for this address.
669 *
670 * @param map map the address belongs to
671 * @param addr_u unsafe address to sanitize
672 * @returns a sanitized offset in page
673 */
674 __attribute__((always_inline, warn_unused_result, overloadable))
675 static inline mach_vm_offset_t
vm_sanitize_offset_in_page(vm_map_t map,vm_addr_struct_t addr_u)676 vm_sanitize_offset_in_page(
677 vm_map_t map,
678 vm_addr_struct_t addr_u)
679 {
680 return vm_sanitize_offset_in_page(vm_map_page_mask(map), addr_u);
681 }
682
683 /*!
684 * @function vm_sanitize_offset
685 *
686 * @abstract
687 * Sanitization function that takes unsafe offset and validates
688 * that it is within addr and end provided.
689 *
690 * @param offset_u unsafe offset to sanitize
691 * @param vm_sanitize_caller caller of the sanitization function
692 * @param addr sanitized start address
693 * @param end sanitized end address
694 * @param offset sanitized offset
695 * @returns return code indicating success/failure of sanitization
696 */
697 __attribute__((always_inline, warn_unused_result))
698 kern_return_t vm_sanitize_offset(
699 vm_addr_struct_t offset_u,
700 vm_sanitize_caller_t vm_sanitize_caller,
701 vm_map_address_t addr,
702 vm_map_address_t end,
703 vm_map_offset_t *offset);
704
705 /*!
706 * @function vm_sanitize_mask
707 *
708 * @abstract
709 * Sanitization function that takes unsafe mask and sanitizes it.
710 *
711 * @param mask_u unsafe mask to sanitize
712 * @param vm_sanitize_caller caller of the sanitization function
713 * @param mask sanitized mask
714 * @returns return code indicating success/failure of sanitization
715 */
716 __attribute__((always_inline, warn_unused_result))
717 kern_return_t vm_sanitize_mask(
718 vm_addr_struct_t mask_u,
719 vm_sanitize_caller_t vm_sanitize_caller,
720 vm_map_offset_t *mask);
721
722 /*!
723 * @function vm_sanitize_object_size
724 *
725 * @abstract
726 * Sanitization function that takes unsafe VM object size and safely rounds it
727 * up wrt a VM object.
728 *
729 * @param size_u unsafe size to sanitize
730 * @param vm_sanitize_caller caller of the sanitization function
731 * @param flags flags that influence sanitization performed
732 * @param size sanitized object size
733 * @returns return code indicating success/failure of sanitization
734 */
735 __attribute__((always_inline, warn_unused_result))
736 kern_return_t vm_sanitize_object_size(
737 vm_size_struct_t size_u,
738 vm_sanitize_caller_t vm_sanitize_caller,
739 vm_sanitize_flags_t flags,
740 vm_object_offset_t *size)
741 __vm_sanitize_require_size_zero_flag(flags);
742
743 /*!
744 * @function vm_sanitize_size
745 *
746 * @abstract
747 * Sanitization function that takes unsafe size and safely rounds it up.
748 *
749 * @param offset_u an offset/address which marks the beginning of the
750 * memory region of size @c size_u. Overflow checks
751 * will be performed on @c size_u+offset_u, and the
752 * low bits of @c offset_u may influence the rounding
753 * of @c size_u to ensure the returned size covers all
754 * pages that intersect with the region that starts at
755 * @c offset_u and has size @c size_u.
756 * @param size_u unsafe size to sanitize
757 * @param vm_sanitize_caller caller of the sanitization function
758 * @param map map the address belongs to
759 * @param flags flags that influence sanitization performed
760 * @param size sanitized size
761 * @returns return code indicating success/failure of sanitization
762 */
763 __attribute__((always_inline, warn_unused_result))
764 kern_return_t vm_sanitize_size(
765 vm_addr_struct_t offset_u,
766 vm_size_struct_t size_u,
767 vm_sanitize_caller_t vm_sanitize_caller,
768 vm_map_t map,
769 vm_sanitize_flags_t flags,
770 mach_vm_size_t *size)
771 __vm_sanitize_require_size_zero_flag(flags);
772
773 /*!
774 * @function vm_sanitize_addr_size
775 *
776 * @abstract
777 * Sanitization function that takes unsafe address and size and returns
778 * sanitized start, end and size via out parameters.
779 *
780 * @param addr_u unsafe address to sanitize
781 * @param size_u unsafe size to sanitize
782 * @param vm_sanitize_caller caller of the sanitization function
783 * @param mask page mask to use
784 * @param map_or_null optional map, used for error compat for some callers
785 * @param flags flags that influence sanitization performed
786 * @param addr sanitized start
787 * @param end sanitized end
788 * @param size sanitized size
789 * @returns return code indicating success/failure of sanitization
790 */
791 __attribute__((always_inline, warn_unused_result))
792 kern_return_t vm_sanitize_addr_size(
793 vm_addr_struct_t addr_u,
794 vm_size_struct_t size_u,
795 vm_sanitize_caller_t vm_sanitize_caller,
796 mach_vm_offset_t mask,
797 vm_map_t map_or_null,
798 vm_sanitize_flags_t flags,
799 vm_map_offset_t *addr,
800 vm_map_offset_t *end,
801 vm_map_size_t *size)
802 __vm_sanitize_require_size_zero_flag(flags);
803
804 /*!
805 * @function vm_sanitize_addr_size
806 *
807 * @abstract
808 * Sanitization function that takes unsafe address and size and returns
809 * sanitized start, end and size via out parameters.
810 *
811 * @param addr_u unsafe address to sanitize
812 * @param size_u unsafe size to sanitize
813 * @param vm_sanitize_caller caller of the sanitization function
814 * @param mask page mask to use
815 * @param flags flags that influence sanitization performed
816 * @param addr sanitized start
817 * @param end sanitized end
818 * @param size sanitized size
819 * @returns return code indicating success/failure of sanitization
820 */
821 __attribute__((always_inline, warn_unused_result, overloadable))
822 static inline kern_return_t
vm_sanitize_addr_size(vm_addr_struct_t addr_u,vm_size_struct_t size_u,vm_sanitize_caller_t vm_sanitize_caller,mach_vm_offset_t mask,vm_sanitize_flags_t flags,vm_map_offset_t * addr,vm_map_offset_t * end,vm_map_size_t * size)823 vm_sanitize_addr_size(
824 vm_addr_struct_t addr_u,
825 vm_size_struct_t size_u,
826 vm_sanitize_caller_t vm_sanitize_caller,
827 mach_vm_offset_t mask,
828 vm_sanitize_flags_t flags,
829 vm_map_offset_t *addr,
830 vm_map_offset_t *end,
831 vm_map_size_t *size)
832 __vm_sanitize_require_size_zero_flag(flags)
833 {
834 return vm_sanitize_addr_size(addr_u, size_u, vm_sanitize_caller, mask,
835 VM_MAP_NULL, flags, addr, end, size);
836 }
837
838
839 /*!
840 * @function vm_sanitize_addr_size
841 *
842 * @abstract
843 * Sanitization function that takes unsafe address and size and returns
844 * sanitized start, end and size via out parameters.
845 *
846 * @param addr_u unsafe address to sanitize
847 * @param size_u unsafe size to sanitize
848 * @param vm_sanitize_caller caller of the sanitization function
849 * @param map map the address belongs to
850 * @param flags flags that influence sanitization performed
851 * @param addr sanitized start
852 * @param end sanitized end
853 * @param size sanitized size
854 * @returns return code indicating success/failure of sanitization
855 */
856 __attribute__((always_inline, warn_unused_result, overloadable))
857 static inline kern_return_t
vm_sanitize_addr_size(vm_addr_struct_t addr_u,vm_size_struct_t size_u,vm_sanitize_caller_t vm_sanitize_caller,vm_map_t map,vm_sanitize_flags_t flags,vm_map_offset_t * addr,vm_map_offset_t * end,vm_map_size_t * size)858 vm_sanitize_addr_size(
859 vm_addr_struct_t addr_u,
860 vm_size_struct_t size_u,
861 vm_sanitize_caller_t vm_sanitize_caller,
862 vm_map_t map,
863 vm_sanitize_flags_t flags,
864 vm_map_offset_t *addr,
865 vm_map_offset_t *end,
866 vm_map_size_t *size)
867 __vm_sanitize_require_size_zero_flag(flags)
868 {
869 mach_vm_offset_t mask = vm_map_page_mask(map);
870
871 return vm_sanitize_addr_size(addr_u, size_u, vm_sanitize_caller, mask,
872 map, flags, addr, end, size);
873 }
874
875 /*!
876 * @function vm_sanitize_addr_end
877 *
878 * @abstract
879 * Sanitization function that takes unsafe address and end and returns
880 * sanitized start, end and size via out parameters.
881 *
882 * @param addr_u unsafe address to sanitize
883 * @param end_u unsafe end to sanitize
884 * @param vm_sanitize_caller caller of the sanitization function
885 * @param mask page mask to use
886 * @param map_or_null optional map, used for error compat for some callers
887 * @param flags flags that influence sanitization performed
888 * @param start sanitized start
889 * @param end sanitized end
890 * @param size sanitized size
891 * @returns return code indicating success/failure of sanitization
892 */
893 __attribute__((always_inline, warn_unused_result))
894 kern_return_t vm_sanitize_addr_end(
895 vm_addr_struct_t addr_u,
896 vm_addr_struct_t end_u,
897 vm_sanitize_caller_t vm_sanitize_caller,
898 mach_vm_offset_t mask,
899 vm_map_t map_or_null,
900 vm_sanitize_flags_t flags,
901 vm_map_offset_t *start,
902 vm_map_offset_t *end,
903 vm_map_size_t *size)
904 __vm_sanitize_require_size_zero_flag(flags);
905
906 /*!
907 * @function vm_sanitize_addr_end
908 *
909 * @abstract
910 * Sanitization function that takes unsafe address and end and returns
911 * sanitized start, end and size via out parameters.
912 *
913 * @param addr_u unsafe address to sanitize
914 * @param end_u unsafe end to sanitize
915 * @param vm_sanitize_caller caller of the sanitization function
916 * @param mask page mask to use
917 * @param flags flags that influence sanitization performed
918 * @param start sanitized start
919 * @param end sanitized end
920 * @param size sanitized size
921 * @returns return code indicating success/failure of sanitization
922 */
923 __attribute__((always_inline, warn_unused_result, overloadable))
924 static inline kern_return_t
vm_sanitize_addr_end(vm_addr_struct_t addr_u,vm_addr_struct_t end_u,vm_sanitize_caller_t vm_sanitize_caller,mach_vm_offset_t mask,vm_sanitize_flags_t flags,vm_map_offset_t * start,vm_map_offset_t * end,vm_map_size_t * size)925 vm_sanitize_addr_end(
926 vm_addr_struct_t addr_u,
927 vm_addr_struct_t end_u,
928 vm_sanitize_caller_t vm_sanitize_caller,
929 mach_vm_offset_t mask,
930 vm_sanitize_flags_t flags,
931 vm_map_offset_t *start,
932 vm_map_offset_t *end,
933 vm_map_size_t *size)
934 __vm_sanitize_require_size_zero_flag(flags)
935 {
936 return vm_sanitize_addr_end(addr_u, end_u, vm_sanitize_caller, mask,
937 VM_MAP_NULL, flags, start, end, size);
938 }
939
940 /*!
941 * @function vm_sanitize_addr_end
942 *
943 * @abstract
944 * Sanitization function that takes unsafe address and end and returns
945 * sanitized start, end and size via out parameters.
946 *
947 * @param addr_u unsafe address to sanitize
948 * @param end_u unsafe end to sanitize
949 * @param vm_sanitize_caller caller of the sanitization function
950 * @param map map the address belongs to
951 * @param flags flags that influence sanitization performed
952 * @param start sanitized start
953 * @param end sanitized end
954 * @param size sanitized size
955 * @returns return code indicating success/failure of sanitization
956 */
957 __attribute__((always_inline, warn_unused_result, overloadable))
958 static inline kern_return_t
vm_sanitize_addr_end(vm_addr_struct_t addr_u,vm_addr_struct_t end_u,vm_sanitize_caller_t vm_sanitize_caller,vm_map_t map,vm_sanitize_flags_t flags,vm_map_offset_t * start,vm_map_offset_t * end,vm_map_size_t * size)959 vm_sanitize_addr_end(
960 vm_addr_struct_t addr_u,
961 vm_addr_struct_t end_u,
962 vm_sanitize_caller_t vm_sanitize_caller,
963 vm_map_t map,
964 vm_sanitize_flags_t flags,
965 vm_map_offset_t *start,
966 vm_map_offset_t *end,
967 vm_map_size_t *size)
968 __vm_sanitize_require_size_zero_flag(flags)
969 {
970 mach_vm_offset_t mask = vm_map_page_mask(map);
971
972 return vm_sanitize_addr_end(addr_u, end_u, vm_sanitize_caller, mask,
973 map, flags, start, end, size);
974 }
975
976 /*!
977 * @function vm_sanitize_prot
978 *
979 * @abstract
980 * Sanitization function that takes unsafe protections and sanitizes it.
981 *
982 * @param prot_u unsafe protections
983 * @param vm_sanitize_caller caller of the sanitization function
984 * @param map map in which protections are going to be changed
985 * @param extra_mask extra mask to allow on top of (VM_PROT_ALL | VM_PROT_ALLEXEC)
986 * @param prot sanitized protections
987 * @returns return code indicating success/failure of sanitization
988 */
989 __attribute__((always_inline, warn_unused_result))
990 kern_return_t vm_sanitize_prot(
991 vm_prot_ut prot_u,
992 vm_sanitize_caller_t vm_sanitize_caller,
993 vm_map_t map,
994 vm_prot_t extra_mask,
995 vm_prot_t *prot);
996
997 __attribute__((always_inline, warn_unused_result, overloadable))
998 static inline kern_return_t
vm_sanitize_prot(vm_prot_ut prot_u,vm_sanitize_caller_t vm_sanitize_caller,vm_map_t map,vm_prot_t * prot)999 vm_sanitize_prot(
1000 vm_prot_ut prot_u,
1001 vm_sanitize_caller_t vm_sanitize_caller,
1002 vm_map_t map,
1003 vm_prot_t *prot)
1004 {
1005 return vm_sanitize_prot(prot_u, vm_sanitize_caller, map, VM_PROT_NONE, prot);
1006 }
1007
1008 /*!
1009 * @function vm_sanitize_cur_and_max_prots
1010 *
1011 * @abstract
1012 * Sanitization function that takes a pair of unsafe current and max protections
1013 * and sanitizes it.
1014 *
1015 * @param cur_prot_u unsafe current protections
1016 * @param max_prot_u unsafe max protections
1017 * @param vm_sanitize_caller caller of the sanitization function
1018 * @param map map in which protections are going to be changed
1019 * @param extra_mask extra mask to allow on top of (VM_PROT_ALL | VM_PROT_ALLEXEC)
1020 * @param cur_prot sanitized current protections
1021 * @param max_prot sanitized max protections
1022 * @returns return code indicating success/failure of sanitization
1023 */
1024 __attribute__((always_inline, warn_unused_result))
1025 kern_return_t vm_sanitize_cur_and_max_prots(
1026 vm_prot_ut cur_prot_u,
1027 vm_prot_ut max_prot_u,
1028 vm_sanitize_caller_t vm_sanitize_caller,
1029 vm_map_t map,
1030 vm_prot_t extra_mask,
1031 vm_prot_t *cur_prot,
1032 vm_prot_t *max_prot);
1033
1034 __attribute__((always_inline, warn_unused_result, overloadable))
1035 static inline kern_return_t
vm_sanitize_cur_and_max_prots(vm_prot_ut cur_prot_u,vm_prot_ut max_prot_u,vm_sanitize_caller_t vm_sanitize_caller,vm_map_t map,vm_prot_t * cur_prot,vm_prot_t * max_prot)1036 vm_sanitize_cur_and_max_prots(
1037 vm_prot_ut cur_prot_u,
1038 vm_prot_ut max_prot_u,
1039 vm_sanitize_caller_t vm_sanitize_caller,
1040 vm_map_t map,
1041 vm_prot_t *cur_prot,
1042 vm_prot_t *max_prot)
1043 {
1044 return vm_sanitize_cur_and_max_prots(cur_prot_u, max_prot_u, vm_sanitize_caller, map,
1045 VM_PROT_NONE, cur_prot, max_prot);
1046 }
1047
1048 /*!
1049 * @function vm_sanitize_memory_entry_perm
1050 *
1051 * @abstract
1052 * Sanitization function that takes unsafe memory entry permissions and
1053 * sanitizes it.
1054 *
1055 * @param perm_u unsafe permissions to sanitize
1056 * @param vm_sanitize_caller caller of the sanitization function
1057 * @param flags flags that influence sanitization performed
1058 * @param extra_mask extra mask to allow on top of VM_PROT_ALL
1059 * @param perm sanitized memory entry permissions
1060 * @returns return code indicating success/failure of sanitization
1061 */
1062 __attribute__((always_inline, warn_unused_result))
1063 kern_return_t vm_sanitize_memory_entry_perm(
1064 vm_prot_ut perm_u,
1065 vm_sanitize_caller_t vm_sanitize_caller,
1066 vm_sanitize_flags_t flags,
1067 vm_prot_t extra_mask,
1068 vm_prot_t *perm);
1069
1070 /*!
1071 * @function vm_sanitize_prot_bsd
1072 *
1073 * @abstract
1074 * Sanitization function that takes unsafe protections and sanitizes it.
1075 *
1076 * @discussion
1077 * Use this function for BSD callers as it strips invalid protections instead
1078 * of returning an error.
1079 *
1080 * @param prot_u unsafe protections
1081 * @param vm_sanitize_caller caller of the sanitization function
1082 * @returns sanitized protections
1083 */
1084 __attribute__((always_inline, warn_unused_result))
1085 vm_prot_t vm_sanitize_prot_bsd(
1086 vm_prot_ut prot_u,
1087 vm_sanitize_caller_t vm_sanitize_caller);
1088
1089 /*!
1090 * @function vm_sanitize_inherit
1091 *
1092 * @abstract
1093 * Sanitization function that takes unsafe vm_inherit and sanitizes it.
1094 *
1095 * @param inherit_u unsafe vm_inherit
1096 * @param vm_sanitize_caller caller of the sanitization function
1097 * @param inherit sanitized vm_inherit
1098 * @returns return code indicating success/failure of sanitization
1099 */
1100 __attribute__((always_inline, warn_unused_result))
1101 kern_return_t vm_sanitize_inherit(
1102 vm_inherit_ut inherit_u,
1103 vm_sanitize_caller_t vm_sanitize_caller,
1104 vm_inherit_t *inherit);
1105
1106 /*!
1107 * @function vm_sanitize_behavior
1108 *
1109 * @abstract
1110 * Sanitization function that takes an unsafe vm_behavior and sanitizes it.
1111 *
1112 * @param behavior_u unsafe vm_behavior
1113 * @param vm_sanitize_caller caller of the sanitization function
1114 * @param behavior sanitized vm_behavior
1115 * @returns return code indicating success/failure of sanitization
1116 */
1117 __attribute__((always_inline, warn_unused_result))
1118 kern_return_t vm_sanitize_behavior(
1119 vm_behavior_ut behavior_u,
1120 vm_sanitize_caller_t vm_sanitize_caller __unused,
1121 vm_behavior_t *behavior);
1122
1123 #pragma GCC visibility pop
1124 __END_DECLS
1125 #endif /* _VM_SANITIZE_INTERNAL_H_ */
1126