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