xref: /xnu-11215.1.10/osfmk/vm/vm_sanitize_internal.h (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
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