/*
* Copyright (c) 2024 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#ifndef _VM_SANITIZE_INTERNAL_H_
#define _VM_SANITIZE_INTERNAL_H_
#include <mach/vm_types_unsafe.h>
#include <mach/error.h>
#include <stdbool.h>
#include <sys/kdebug_triage.h>
#if MACH_KERNEL_PRIVATE
#include <vm/vm_sanitize_telemetry.h>
#else
// fixme bsd/kern/kern_mman.c can't see vm/vm_sanitize_telemetry.h
typedef uint64_t vm_sanitize_method_t;
#endif
__BEGIN_DECLS
#pragma GCC visibility push(hidden)
/*
* kern_return_t errors used internally by VM
*/
/*!
* @define VM_ERR_RETURN_NOW
* @abstract Communicate to a caller that they should
* return @c KERN_SUCCESS immediately after completing sanitization checks.
*/
#define VM_ERR_RETURN_NOW (err_vm | err_sub(0) | 1)
/*!
* @function vm_sanitize_get_kr
* @abstract When a VM sanitizer returns an error, use this to extract
* the real value that the sanitizers request that you return.
*
* @discussion errno-returning callers may need to transform this result further
*
* @param kr error code set by the sanitizers
* @returns a (possibly different) error code
*/
static inline
kern_return_t
vm_sanitize_get_kr(kern_return_t kr)
{
if (kr == VM_ERR_RETURN_NOW) {
return KERN_SUCCESS;
}
return kr;
}
/*!
* @enum vm_sanitize_caller_id_t
*
* @brief
* IDs for callers of sanitization functions that have different
* set of return values.
*/
__enum_closed_decl(vm_sanitize_caller_id_t, uint32_t, {
VM_SANITIZE_CALLER_ID_NONE,
/* memory entry */
VM_SANITIZE_CALLER_ID_MACH_MAKE_MEMORY_ENTRY,
VM_SANITIZE_CALLER_ID_MACH_MEMORY_ENTRY_PAGE_OP,
VM_SANITIZE_CALLER_ID_MACH_MEMORY_ENTRY_RANGE_OP,
VM_SANITIZE_CALLER_ID_MACH_MEMORY_ENTRY_MAP_SIZE,
VM_SANITIZE_CALLER_ID_MACH_MEMORY_OBJECT_MEMORY_ENTRY,
/* alloc/dealloc */
VM_SANITIZE_CALLER_ID_VM_ALLOCATE_FIXED,
VM_SANITIZE_CALLER_ID_VM_ALLOCATE_ANYWHERE,
VM_SANITIZE_CALLER_ID_VM_DEALLOCATE,
VM_SANITIZE_CALLER_ID_MUNMAP,
/* map/remap */
VM_SANITIZE_CALLER_ID_VM_MAP_REMAP,
VM_SANITIZE_CALLER_ID_MMAP,
VM_SANITIZE_CALLER_ID_MREMAP_ENCRYPTED,
VM_SANITIZE_CALLER_ID_MAP_WITH_LINKING_NP,
VM_SANITIZE_CALLER_ID_ENTER_MEM_OBJ,
VM_SANITIZE_CALLER_ID_ENTER_MEM_OBJ_CTL,
/* wire/unwire */
VM_SANITIZE_CALLER_ID_VM_WIRE_USER,
VM_SANITIZE_CALLER_ID_VM_UNWIRE_USER,
VM_SANITIZE_CALLER_ID_VM_MAP_WIRE,
VM_SANITIZE_CALLER_ID_VM_MAP_UNWIRE,
VM_SANITIZE_CALLER_ID_VSLOCK,
VM_SANITIZE_CALLER_ID_VSUNLOCK,
/* copyin/copyout */
VM_SANITIZE_CALLER_ID_VM_MAP_COPY_OVERWRITE,
VM_SANITIZE_CALLER_ID_VM_MAP_COPYIN,
VM_SANITIZE_CALLER_ID_VM_MAP_READ_USER,
VM_SANITIZE_CALLER_ID_VM_MAP_WRITE_USER,
/* inherit */
/* protect */
/* behavior */
/* msync */
/* machine attribute */
/* page info */
/* test */
VM_SANITIZE_CALLER_ID_TEST
});
/*!
* @enum vm_sanitize_flags_t
*
* @brief
* Flags that influence the sanitization being performed.
*
* @const VM_SANITIZE_FLAGS_NONE
* Default value.
*
* @const VM_SANITIZE_FLAGS_CHECK_ALIGNED_START
* Checks that the start address is aligned to map page size.
*
* @const VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS
* In sanitizers that have a @c size parameter, the sanitizer will ask
* the caller to return @c KERN_SUCCESS when @c size @c == @c 0.
*
* Exactly one of @c VM_SANITIZE_FLAGS_SIZE_ZERO_* must be passed to sanitizers
* that return a sanitized size.
*
* @const VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS
* In sanitizers that have a @c size parameter, the sanitizer will ask
* the caller to return @c KERN_INVALID_ARGUMENT when @c size @c == @c 0.
*
* Exactly one of @c VM_SANITIZE_FLAGS_SIZE_ZERO_* must be passed to sanitizers
* that return a sanitized size.
*
* @const VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH
* In sanitizers that have a @c size parameter, the sanitizer will not ask
* the caller to return when @c size @c == @c 0, thus falling through into
* the caller's implementation.
*
* Exactly one of @c VM_SANITIZE_FLAGS_SIZE_ZERO_* must be passed to sanitizers
* that return a sanitized size.
*
* @const VM_SANITIZE_FLAGS_GET_UNALIGNED_VALUES
* Return unaligned start/end/size rather than realigned values.
*
* @const VM_SANITIZE_FLAGS_REALIGN_START
* Ignore the misaligned bits of the start address when sanitizing an address.
*
* @const VM_SANITIZE_FLAGS_CHECK_USER_MEM_MAP_FLAGS
* Reject non user allowed mem map flags for memory entry.
*
* @const VM_SANITIZE_FLAGS_CANONICALIZE
* Canonicalize address for CONFIG_KERNEL_TAGGING
*/
__options_closed_decl(vm_sanitize_flags_t, uint32_t, {
VM_SANITIZE_FLAGS_NONE = 0x00000000,
VM_SANITIZE_FLAGS_CHECK_ALIGNED_START = 0x00000001,
VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS = 0x00000002,
VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS = 0x00000004,
VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH = 0x00000008,
VM_SANITIZE_FLAGS_GET_UNALIGNED_VALUES = 0x00000010,
VM_SANITIZE_FLAGS_REALIGN_START = 0x00000020,
VM_SANITIZE_FLAGS_CHECK_USER_MEM_MAP_FLAGS = 0x00000040,
VM_SANITIZE_FLAGS_CANONICALIZE = 0x00000080,
});
#define __vm_sanitize_bits_one_of(flags) \
((flags) != 0 && ((flags) & ((flags) - 1)) == 0)
#define __vm_sanitize_assert_one_of(arg, mask) \
__attribute__((diagnose_if(!__vm_sanitize_bits_one_of((arg) & (mask)), \
"`" #arg "` must have one of these flags `" #mask "`", "error")))
#define __vm_sanitize_require_size_zero_flag(arg) \
__vm_sanitize_assert_one_of(arg, \
VM_SANITIZE_FLAGS_SIZE_ZERO_SUCCEEDS | VM_SANITIZE_FLAGS_SIZE_ZERO_FAILS | VM_SANITIZE_FLAGS_SIZE_ZERO_FALLTHROUGH)
/*
* Error compat rewrite result:
* compat_kr: the more-compatible return value
* should_rewrite: true if compat_kr should be returned
* should_telemeter: true if compat_kr should be telemetered
*/
typedef struct {
kern_return_t compat_kr;
bool should_rewrite;
bool should_telemeter;
} vm_sanitize_compat_rewrite_t;
typedef vm_sanitize_compat_rewrite_t (*vm_sanitize_err_compat_addr_size_fn)(kern_return_t kr,
vm_address_t addr, vm_size_t size, vm_offset_t pgmask);
typedef vm_sanitize_compat_rewrite_t (*vm_sanitize_err_compat_cur_and_max_prots_fn)(kern_return_t kr,
vm_prot_t *cur_inout, vm_prot_t *max_inout, vm_prot_t extra_mask);
typedef const struct vm_sanitize_caller {
vm_sanitize_caller_id_t vm_sanitize_caller_id;
const char *vm_sanitize_caller_name;
vm_sanitize_method_t vm_sanitize_telemetry_id;
enum vm_sanitize_subsys_error_codes vm_sanitize_ktriage_id;
vm_sanitize_err_compat_addr_size_fn err_compat_addr_size;
vm_sanitize_err_compat_cur_and_max_prots_fn err_compat_prot_cur_max;
} *vm_sanitize_caller_t;
/*
* Macros to declare and define callers of sanitization functions
*/
#define VM_SANITIZE_DECL_CALLER(name) \
extern vm_sanitize_caller_t const VM_SANITIZE_CALLER_ ## name;
#define VM_SANITIZE_DEFINE_CALLER(name, ... /* error compat functions */) \
static const struct vm_sanitize_caller vm_sanitize_caller_storage_ ## name = { \
.vm_sanitize_caller_id = VM_SANITIZE_CALLER_ID_ ## name, \
.vm_sanitize_caller_name = #name, \
.vm_sanitize_telemetry_id = VM_SANITIZE_METHOD_ ## name, \
.vm_sanitize_ktriage_id = KDBG_TRIAGE_VM_SANITIZE_ ## name, \
__VA_ARGS__ \
}; \
vm_sanitize_caller_t const VM_SANITIZE_CALLER_ ## name = &vm_sanitize_caller_storage_ ## name
/*
* Declaration of callers of VM sanitization functions
*/
/* memory entry */
VM_SANITIZE_DECL_CALLER(MACH_MAKE_MEMORY_ENTRY);
VM_SANITIZE_DECL_CALLER(MACH_MEMORY_ENTRY_PAGE_OP);
VM_SANITIZE_DECL_CALLER(MACH_MEMORY_ENTRY_RANGE_OP);
VM_SANITIZE_DECL_CALLER(MACH_MEMORY_ENTRY_MAP_SIZE);
VM_SANITIZE_DECL_CALLER(MACH_MEMORY_OBJECT_MEMORY_ENTRY);
/* alloc/dealloc */
VM_SANITIZE_DECL_CALLER(VM_ALLOCATE_FIXED);
VM_SANITIZE_DECL_CALLER(VM_ALLOCATE_ANYWHERE);
VM_SANITIZE_DECL_CALLER(VM_DEALLOCATE);
VM_SANITIZE_DECL_CALLER(MUNMAP);
/* map/remap */
VM_SANITIZE_DECL_CALLER(VM_MAP_REMAP);
VM_SANITIZE_DECL_CALLER(MMAP);
VM_SANITIZE_DECL_CALLER(MREMAP_ENCRYPTED);
VM_SANITIZE_DECL_CALLER(MAP_WITH_LINKING_NP);
VM_SANITIZE_DECL_CALLER(ENTER_MEM_OBJ);
VM_SANITIZE_DECL_CALLER(ENTER_MEM_OBJ_CTL);
/* wire/unwire */
VM_SANITIZE_DECL_CALLER(VM_WIRE_USER);
VM_SANITIZE_DECL_CALLER(VM_UNWIRE_USER);
VM_SANITIZE_DECL_CALLER(VM_MAP_WIRE);
VM_SANITIZE_DECL_CALLER(VM_MAP_UNWIRE);
VM_SANITIZE_DECL_CALLER(VSLOCK);
VM_SANITIZE_DECL_CALLER(VSUNLOCK);
/* copyin/copyout */
VM_SANITIZE_DECL_CALLER(VM_MAP_COPY_OVERWRITE);
VM_SANITIZE_DECL_CALLER(VM_MAP_COPYIN);
VM_SANITIZE_DECL_CALLER(VM_MAP_READ_USER);
VM_SANITIZE_DECL_CALLER(VM_MAP_WRITE_USER);
/* inherit */
/* protect */
/* behavior */
/* msync */
/* machine attribute */
/* page info */
/* test */
VM_SANITIZE_DECL_CALLER(TEST);
/*
* Macro that extracts the inner struct member from a wrapped type. Should be
* used in all cases, including validation functions, when accessing the
* inner struct member.
*/
#define VM_SANITIZE_UNSAFE_UNWRAP(_val) (_val).UNSAFE
/*
* Macro that sets an unsafe value
*/
#define VM_SANITIZE_UNSAFE_SET(_var, _val) ((_var).UNSAFE) = (_val)
/*
* Macro to check if unsafe value is a specific safe value
*/
#define VM_SANITIZE_UNSAFE_IS_EQUAL(_var, _val) ((_var).UNSAFE == (_val))
/*
* Macro to check if unsafe value is zero
*/
#define VM_SANITIZE_UNSAFE_IS_ZERO(_var) VM_SANITIZE_UNSAFE_IS_EQUAL(_var, 0)
/*
* returns whether a given unsafe value fits a given type
*/
#define VM_SANITIZE_UNSAFE_FITS(_var, type_t) ({ \
__auto_type __tmp = (_var).UNSAFE; \
__tmp == (type_t)__tmp; \
})
/*!
* @function vm_sanitize_wrap_addr
*
* @abstract
* Function that wrap unsanitized safe address into unsafe address
*
* @param val safe address
* @returns unsafe address
*/
__attribute__((always_inline, warn_unused_result))
vm_addr_struct_t vm_sanitize_wrap_addr(vm_address_t val);
/*!
* @function vm_sanitize_wrap_addr_ref
*
* @abstract
* Function that wrap a safe address pointer,
* into unsafe address pointer.
*
* @param val safe address ref
* @returns unsafe address reference
*/
#define vm_sanitize_wrap_addr_ref(var) _Generic(var, \
mach_vm_address_t *: (vm_addr_struct_t *)(var), \
vm_address_t *: (vm_addr_struct_t *)(var), \
default: (var))
/*!
* @function vm_sanitize_wrap_size
*
* @abstract
* Function that wrap unsanitized safe size into unsafe size
*
* @param val safe size
* @returns unsafe size
*/
__attribute__((always_inline, warn_unused_result))
vm_size_struct_t vm_sanitize_wrap_size(vm_size_t val);
/*
* bsd doesn't use 32bit interfaces and the types aren't even defined for them,
* so we just expose this to MACH.
*/
#ifdef MACH_KERNEL_PRIVATE
/*!
* @function vm32_sanitize_wrap_size
*
* @abstract
* Function that wrap unsanitized 32bit safe size into 32bit unsafe size
*
* @param val safe size
* @returns unsafe size
*/
__attribute__((always_inline, warn_unused_result))
vm32_size_struct_t vm32_sanitize_wrap_size(vm32_size_t val);
#endif /* MACH_KERNEL_PRIVATE */
/*!
* @function vm_sanitize_wrap_prot
*
* @abstract
* Function that wrap unsanitized safe protection into unsafe protection
*
* @param val safe protection
* @returns unsafe protection
*/
__attribute__((always_inline, warn_unused_result))
vm_prot_ut vm_sanitize_wrap_prot(vm_prot_t val);
/*!
* @function vm_sanitize_wrap_prot_ref
*
* @abstract
* Function that wrap a safe protection pointer into unsafe protection pointer.
*
* @param val safe protection pointer
* @returns unsafe protection pointer
*/
__attribute__((always_inline, warn_unused_result))
static inline vm_prot_ut *
vm_sanitize_wrap_prot_ref(vm_prot_t *val)
{
return (vm_prot_ut *)val;
}
/*!
* @function vm_sanitize_wrap_inherit
*
* @abstract
* Function that wrap unsanitized safe vm_inherit into unsafe vm_inherit
*
* @param val safe vm_inherit
* @returns unsafe vm_inherit
*/
__attribute__((always_inline, warn_unused_result))
vm_inherit_ut vm_sanitize_wrap_inherit(vm_inherit_t val);
#ifdef MACH_KERNEL_PRIVATE
/*!
* @function vm_sanitize_expand_addr_to_64
*
* @abstract
* Function used by the vm32 functions to cast 32bit unsafe address
* to 64bit unsafe address
*
* @param val 32bit unsafe address
* @returns 64bit unsafe address
*/
__attribute__((always_inline, warn_unused_result))
vm_addr_struct_t vm_sanitize_expand_addr_to_64(vm32_address_ut val);
/*!
* @function vm_sanitize_expand_size_to_64
*
* @abstract
* Function used by the vm32 functions to cast 32bit unsafe size
* to 64bit unsafe size
*
* @param val 32bit unsafe size
* @returns 64bit unsafe size
*/
__attribute__((always_inline, warn_unused_result))
vm_size_struct_t vm_sanitize_expand_size_to_64(vm32_size_ut val);
/*!
* @function vm_sanitize_expand_addr_size_to_64
*
* @abstract
* Sanitization function used to transform a pair of 32bit {addr,size} values
* into a set of unsafe addr/end pairs checking that it doesn't overflow the
* 32bit space.
*
* @discussion
* Use VM_BIND_* macros to bind return values to arguments.
*
* Note: this function is relatively approximate, which isn't a huge concern
* for kernel security because all maps function on 64bit values and no
* arithmetics is performed on 32bit quantities. The "worst" outcome is that
* values returned to userspace truncate incorrectly.
*
* @param [in] addr32_u unsafe address to sanitize
* @param [in] size32_u unsafe size to sanitize
* @param [out] addr_u unsafe address to sanitize
* @param [out] size_u unsafe size to sanitize
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_expand_addr_size_to_64(
vm32_address_ut addr32_u,
vm32_size_ut size32_u,
vm_address_ut *addr_u,
vm_size_ut *size_u);
/*!
* @function vm_sanitize_trunc_addr_to_32
*
* @abstract
* Function used by the vm32 functions to cast 64bit unsafe address
* to 32bit unsafe address
*
* @param val 64bit unsafe address
* @returns 32bit unsafe address
*/
__attribute__((always_inline, warn_unused_result))
vm32_address_ut vm_sanitize_trunc_addr_to_32(vm_addr_struct_t val);
/*!
* @function vm_sanitize_trunc_size_to_32
*
* @abstract
* Function used by the vm32 functions to cast 64bit unsafe size
* to 32bit unsafe size
*
* @param val 64bit unsafe size
* @returns 32bit unsafe size
*/
__attribute__((always_inline, warn_unused_result))
vm32_size_ut vm_sanitize_trunc_size_to_32(vm_size_struct_t val);
#endif /* MACH_KERNEL_PRIVATE */
/*!
* @function vm_sanitize_add_overflow()
*
* @abstract
* Computes the sum of an address and a size checking for overflow,
* staying in the unsafe world.
*
* @param addr_u unsafe address
* @param size_u unsafe size
* @param addr_out_u unsafe result
* @returns whether the operation overflowed
*/
__attribute__((always_inline, warn_unused_result, overloadable))
bool vm_sanitize_add_overflow(
vm_addr_struct_t addr_u,
vm_size_struct_t size_u,
vm_addr_struct_t *addr_out_u);
/*!
* @function vm_sanitize_add_overflow()
*
* @abstract
* Computes the sum of two sizes checking for overflow,
* staying in the unsafe world.
*
* @param size1_u unsafe size 1
* @param size2_u unsafe size 2
* @param size_out_u unsafe result
* @returns whether the operation overflowed
*/
__attribute__((always_inline, warn_unused_result, overloadable))
bool vm_sanitize_add_overflow(
vm_size_struct_t size1_u,
vm_size_struct_t size2_u,
vm_size_struct_t *size_out_u);
/*!
* @function vm_sanitize_compute_unsafe_end
*
* @abstract
* Computes and returns unsafe end from unsafe start and size
*
* @param addr_u unsafe start
* @param size_u unsafe size
* @returns unsafe end
*/
__attribute__((always_inline, warn_unused_result))
vm_addr_struct_t vm_sanitize_compute_unsafe_end(
vm_addr_struct_t addr_u,
vm_size_struct_t size_u);
/*!
* @function vm_sanitize_compute_unsafe_size
*
* @abstract
* Computes and returns unsafe size from unsafe start and end
*
* @param addr_u unsafe start
* @param end_u unsafe end
* @returns unsafe size
*/
__attribute__((always_inline, warn_unused_result))
vm_size_struct_t vm_sanitize_compute_unsafe_size(
vm_addr_struct_t addr_u,
vm_addr_struct_t end_u);
/*!
* @function vm_sanitize_addr
*
* @abstract
* Sanitization function that takes unsafe address, and returns a truncated
* address.
*
* @param map map the address belongs to
* @param addr_u unsafe address to sanitize
* @returns a sanitized address
*/
__attribute__((always_inline, warn_unused_result))
mach_vm_address_t vm_sanitize_addr(
vm_map_t map,
vm_addr_struct_t addr_u);
/*!
* @function vm_sanitize_offset_in_page
*
* @abstract
* Sanitization function that takes unsafe address,
* and returns the offset in the page for this address.
*
* @param map map the address belongs to
* @param addr_u unsafe address to sanitize
* @returns a sanitized offset in page
*/
__attribute__((always_inline, warn_unused_result))
mach_vm_offset_t vm_sanitize_offset_in_page(
vm_map_t map,
vm_addr_struct_t addr_u);
/*!
* @function vm_sanitize_offset
*
* @abstract
* Sanitization function that takes unsafe offset and validates
* that it is within addr and end provided.
*
* @param offset_u unsafe offset to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param addr sanitized start address
* @param end sanitized end address
* @param offset sanitized offset
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_offset(
vm_addr_struct_t offset_u,
vm_sanitize_caller_t vm_sanitize_caller,
vm_map_address_t addr,
vm_map_address_t end,
vm_map_offset_t *offset);
/*!
* @function vm_sanitize_mask
*
* @abstract
* Sanitization function that takes unsafe mask and sanitizes it.
*
* @param mask_u unsafe mask to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param mask sanitized mask
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_mask(
vm_addr_struct_t mask_u,
vm_sanitize_caller_t vm_sanitize_caller,
vm_map_offset_t *mask);
/*!
* @function vm_sanitize_object_size
*
* @abstract
* Sanitization function that takes unsafe VM object size and safely rounds it
* up wrt a VM object.
*
* @param size_u unsafe size to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param flags flags that influence sanitization performed
* @param size sanitized object size
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_object_size(
vm_size_struct_t size_u,
vm_sanitize_caller_t vm_sanitize_caller,
vm_sanitize_flags_t flags,
vm_object_offset_t *size)
__vm_sanitize_require_size_zero_flag(flags);
/*!
* @function vm_sanitize_size
*
* @abstract
* Sanitization function that takes unsafe size and safely rounds it up.
*
* @param offset_u an offset/address which marks the beginning of the
* memory region of size @c size_u. Overflow checks
* will be performed on @c size_u+offset_u, and the
* low bits of @c offset_u may influence the rounding
* of @c size_u to ensure the returned size covers all
* pages that intersect with the region that starts at
* @c offset_u and has size @c size_u.
* @param size_u unsafe size to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param map map the address belongs to
* @param flags flags that influence sanitization performed
* @param size sanitized size
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_size(
vm_addr_struct_t offset_u,
vm_size_struct_t size_u,
vm_sanitize_caller_t vm_sanitize_caller,
vm_map_t map,
vm_sanitize_flags_t flags,
mach_vm_size_t *size)
__vm_sanitize_require_size_zero_flag(flags);
/*!
* @function vm_sanitize_addr_size
*
* @abstract
* Sanitization function that takes unsafe address and size and returns
* sanitized start, end and size via out parameters.
*
* @param addr_u unsafe address to sanitize
* @param size_u unsafe size to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param mask page mask to use
* @param flags flags that influence sanitization performed
* @param addr sanitized start
* @param end sanitized end
* @param size sanitized size
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
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)
__vm_sanitize_require_size_zero_flag(flags);
/*!
* @function vm_sanitize_addr_size
*
* @abstract
* Sanitization function that takes unsafe address and size and returns
* sanitized start, end and size via out parameters.
*
* @param addr_u unsafe address to sanitize
* @param size_u unsafe size to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param map map the address belongs to
* @param flags flags that influence sanitization performed
* @param addr sanitized start
* @param end sanitized end
* @param size sanitized size
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result, overloadable))
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)
__vm_sanitize_require_size_zero_flag(flags)
{
mach_vm_offset_t mask = vm_map_page_mask(map);
return vm_sanitize_addr_size(addr_u, size_u, vm_sanitize_caller, mask, flags,
addr, end, size);
}
/*!
* @function vm_sanitize_addr_end
*
* @abstract
* Sanitization function that takes unsafe address and end and returns
* sanitized start, end and size via out parameters.
*
* @param addr_u unsafe address to sanitize
* @param end_u unsafe end to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param map map the address belongs to
* @param flags flags that influence sanitization performed
* @param start sanitized start
* @param end sanitized end
* @param size sanitized size
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
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)
__vm_sanitize_require_size_zero_flag(flags);
/*!
* @function vm_sanitize_prot
*
* @abstract
* Sanitization function that takes unsafe protections and sanitizes it.
*
* @param prot_u unsafe protections
* @param vm_sanitize_caller caller of the sanitization function
* @param map map in which protections are going to be changed
* @param extra_mask extra mask to allow on top of (VM_PROT_ALL | VM_PROT_ALLEXEC)
* @param prot sanitized protections
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
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 extra_mask,
vm_prot_t *prot);
__attribute__((always_inline, warn_unused_result, overloadable))
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)
{
return vm_sanitize_prot(prot_u, vm_sanitize_caller, map, VM_PROT_NONE, prot);
}
/*!
* @function vm_sanitize_cur_and_max_prots
*
* @abstract
* Sanitization function that takes a pair of unsafe current and max protections
* and sanitizes it.
*
* @param cur_prot_u unsafe current protections
* @param max_prot_u unsafe max protections
* @param vm_sanitize_caller caller of the sanitization function
* @param map map in which protections are going to be changed
* @param extra_mask extra mask to allow on top of (VM_PROT_ALL | VM_PROT_ALLEXEC)
* @param cur_prot sanitized current protections
* @param max_prot sanitized max protections
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
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 extra_mask,
vm_prot_t *cur_prot,
vm_prot_t *max_prot);
__attribute__((always_inline, warn_unused_result, overloadable))
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)
{
return vm_sanitize_cur_and_max_prots(cur_prot_u, max_prot_u, vm_sanitize_caller, map,
VM_PROT_NONE, cur_prot, max_prot);
}
/*!
* @function vm_sanitize_memory_entry_perm
*
* @abstract
* Sanitization function that takes unsafe memory entry permissions and
* sanitizes it.
*
* @param perm_u unsafe permissions to sanitize
* @param vm_sanitize_caller caller of the sanitization function
* @param flags flags that influence sanitization performed
* @param extra_mask extra mask to allow on top of VM_PROT_ALL
* @param perm sanitized memory entry permissions
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_memory_entry_perm(
vm_prot_ut perm_u,
vm_sanitize_caller_t vm_sanitize_caller,
vm_sanitize_flags_t flags,
vm_prot_t extra_mask,
vm_prot_t *perm);
/*!
* @function vm_sanitize_prot_bsd
*
* @abstract
* Sanitization function that takes unsafe protections and sanitizes it.
*
* @discussion
* Use this function for BSD callers as it strips invalid protections instead
* of returning an error.
*
* @param prot_u unsafe protections
* @param vm_sanitize_caller caller of the sanitization function
* @param prot sanitized protections
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_prot_bsd(
vm_prot_ut prot_u,
vm_sanitize_caller_t vm_sanitize_caller,
vm_prot_t *prot);
/*!
* @function vm_sanitize_inherit
*
* @abstract
* Sanitization function that takes unsafe vm_inherit and sanitizes it.
*
* @param inherit_u unsafe vm_inherit
* @param vm_sanitize_caller caller of the sanitization function
* @param inherit sanitized vm_inherit
* @returns return code indicating success/failure of sanitization
*/
__attribute__((always_inline, warn_unused_result))
kern_return_t vm_sanitize_inherit(
vm_inherit_ut inherit_u,
vm_sanitize_caller_t vm_sanitize_caller,
vm_inherit_t *inherit);
#pragma GCC visibility pop
__END_DECLS
#endif /* _VM_SANITIZE_INTERNAL_H_ */