This is xnu-11215.1.10. See this file in:
/*
 * 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_ */