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