Exception-port registration and restoration
Validation and ownership of task/thread exception-port registrations. Getters return masks, ports, behaviors and flavors; swap operations return previous settings while installing replacements. The source includes configuration-dependent policy checks and send-right copying and release.
set_exception_ports_validation source
Routine: set_exception_ports_validation
Purpose:
Common argument validation shared between all exception port
setting/swapping routines
Conditions:
Nothing locked.
Returns:
KERN_SUCCESS Setting the exception port is allowed
with these arguments
KERN_INVALID_ARGUMENT Invalid arguments
KERN_INVALID_RIGHT Incorrect port configuration
KERN_DENIED Denied by security policy
kern_return_t set_exception_ports_validation( task_t task, exception_mask_t exception_mask, ipc_port_t new_port, exception_behavior_t new_behavior, thread_state_flavor_t new_flavor, bool hardened_exception) { if (exception_mask & ~EXC_MASK_VALID) { return KERN_INVALID_ARGUMENT; } if (IP_VALID(new_port)) { switch (new_behavior & ~MACH_EXCEPTION_MASK) { case EXCEPTION_DEFAULT: case EXCEPTION_STATE: case EXCEPTION_STATE_IDENTITY: case EXCEPTION_IDENTITY_PROTECTED: case EXCEPTION_STATE_IDENTITY_PROTECTED: break; default: return KERN_INVALID_ARGUMENT; } } if (IP_VALID(new_port) && !ipc_is_valid_exception_port(task, new_port)) { return KERN_INVALID_RIGHT; } … more in source
thread_set_exception_ports_internal source
Routine: thread_set_exception_ports_internal
Purpose:
Set a new exception action on the thread
Conditions:
Arguments have been validated via `set_exception_ports_validation`
Nothing locked.
Returns:
KERN_SUCCESS Setting the exception port is allowed with these arguments
KERN_FAILURE Thread is inactive
kern_return_t thread_set_exception_ports_internal( thread_t thread, exception_mask_t exception_mask, ipc_port_t new_port, exception_behavior_t new_behavior, thread_state_flavor_t new_flavor, boolean_t hardened) { ipc_port_t old_port[EXC_TYPES_COUNT]; thread_ro_t tro; boolean_t privileged = task_is_privileged(current_task()); #if CONFIG_MACF if (mac_task_check_set_thread_exception_ports(current_task(), get_threadtask(thread), exception_mask, new_behavior) != 0) { return KERN_NO_ACCESS; } struct label *new_label = mac_exc_create_label_for_current_proc(); #endif tro = get_thread_ro(thread); thread_mtx_lock(thread); if (!thread->active) { thread_mtx_unlock(thread); #if CONFIG_MACF mac_exc_free_label(new_label); #endif return KERN_FAILURE; … more in source
thread_set_exception_ports source · thread_set_exception_ports reference
Routine: thread/task_set_exception_ports [kernel call]
Purpose:
Sets the thread/task exception port, flavor and
behavior for the exception types specified by the mask.
There will be one send right per exception per valid
port.
Conditions:
Nothing locked. If successful, consumes
the supplied send right.
Returns:
KERN_SUCCESS Changed the special port.
KERN_INVALID_ARGUMENT The thread is null,
Illegal mask bit set.
Illegal exception behavior
KERN_FAILURE The thread is dead.
KERN_NO_ACCESS Restricted access to set port
kern_return_t thread_set_exception_ports( thread_t thread, exception_mask_t exception_mask, ipc_port_t new_port, exception_behavior_t new_behavior, thread_state_flavor_t new_flavor) { if (thread == THREAD_NULL) { return KERN_INVALID_ARGUMENT; } bool hardened_exception_flow = false; kern_return_t kr = set_exception_ports_validation(get_threadtask(thread), exception_mask, new_port, new_behavior, new_flavor, hardened_exception_flow); if (kr != KERN_SUCCESS) { return kr; } return thread_set_exception_ports_internal(thread, exception_mask, new_port, new_behavior, new_flavor, false); }
task_set_exception_ports source · task_set_exception_ports reference
kern_return_t task_set_exception_ports( task_t task, exception_mask_t exception_mask, ipc_port_t new_port, exception_behavior_t new_behavior, thread_state_flavor_t new_flavor) { ipc_port_t old_port[EXC_TYPES_COUNT]; boolean_t privileged = task_is_privileged(current_task()); register int i; if (task == TASK_NULL) { return KERN_INVALID_ARGUMENT; } bool hardened_exception_flow = false; kern_return_t kr = set_exception_ports_validation(task, exception_mask, new_port, new_behavior, new_flavor, hardened_exception_flow); if (kr != KERN_SUCCESS) { return kr; } #if CONFIG_MACF if (mac_task_check_set_task_exception_ports(current_task(), task, exception_mask, new_behavior) != 0) { return KERN_NO_ACCESS; } struct label *new_label = mac_exc_create_label_for_current_proc(); #endif … more in source
thread_swap_exception_ports source · thread_swap_exception_ports reference
Routine: thread/task_swap_exception_ports [kernel call]
Purpose:
Sets the thread/task exception port, flavor and
behavior for the exception types specified by the
mask.
The old ports, behavior and flavors are returned
Count specifies the array sizes on input and
the number of returned ports etc. on output. The
arrays must be large enough to hold all the returned
data, MIG returnes an error otherwise. The masks
array specifies the corresponding exception type(s).
Conditions:
Nothing locked. If successful, consumes
the supplied send right.
Returns upto [in} CountCnt elements.
Returns:
KERN_SUCCESS Changed the special port.
KERN_INVALID_ARGUMENT The thread is null,
Illegal mask bit set.
Illegal exception behavior
KERN_FAILURE The thread is dead.
KERN_NO_ACCESS Restricted access to set port
kern_return_t thread_swap_exception_ports( thread_t thread, exception_mask_t exception_mask, ipc_port_t new_port, exception_behavior_t new_behavior, thread_state_flavor_t new_flavor, exception_mask_array_t masks, mach_msg_type_number_t *CountCnt, exception_port_array_t ports, exception_behavior_array_t behaviors, thread_state_flavor_array_t flavors) { ipc_port_t old_port[EXC_TYPES_COUNT]; thread_ro_t tro; boolean_t privileged = task_is_privileged(current_task()); unsigned int i, j, count; if (thread == THREAD_NULL) { return KERN_INVALID_ARGUMENT; } bool hardened_exception_flow = false; kern_return_t kr = set_exception_ports_validation(get_threadtask(thread), exception_mask, new_port, new_behavior, new_flavor, hardened_exception_flow); if (kr != KERN_SUCCESS) { return kr; } #if CONFIG_MACF if (mac_task_check_set_thread_exception_ports(current_task(), get_threadtask(thread), exception_mask, new_behavior) != 0) { … more in source
task_swap_exception_ports source · task_swap_exception_ports reference
kern_return_t task_swap_exception_ports( task_t task, exception_mask_t exception_mask, ipc_port_t new_port, exception_behavior_t new_behavior, thread_state_flavor_t new_flavor, exception_mask_array_t masks, mach_msg_type_number_t *CountCnt, exception_port_array_t ports, exception_behavior_array_t behaviors, thread_state_flavor_array_t flavors) { ipc_port_t old_port[EXC_TYPES_COUNT]; boolean_t privileged = task_is_privileged(current_task()); unsigned int i, j, count; #if CONFIG_MACF struct label *new_label; #endif if (task == TASK_NULL) { return KERN_INVALID_ARGUMENT; } bool hardened_exception_flow = false; kern_return_t kr = set_exception_ports_validation(task, exception_mask, new_port, new_behavior, new_flavor, hardened_exception_flow); if (kr != KERN_SUCCESS) { return kr; } … more in source
thread_get_exception_ports_internal source
Routine: thread/task_get_exception_ports [kernel call]
Purpose:
Clones a send right for each of the thread/task's exception
ports specified in the mask and returns the behaviour
and flavor of said port.
Returns upto [in} CountCnt elements.
Conditions:
Nothing locked.
Returns:
KERN_SUCCESS Extracted a send right.
KERN_INVALID_ARGUMENT The thread is null,
Invalid special port,
Illegal mask bit set.
KERN_FAILURE The thread is dead.
static kern_return_t thread_get_exception_ports_internal( thread_t thread, exception_mask_t exception_mask, exception_mask_array_t masks, mach_msg_type_number_t *CountCnt, exception_port_info_array_t ports_info, exception_port_array_t ports, exception_behavior_array_t behaviors, thread_state_flavor_array_t flavors) { unsigned int count; boolean_t info_only = (ports_info != NULL); thread_ro_t tro; ipc_port_t port_ptrs[EXC_TYPES_COUNT]; /* pointers only, does not hold right */ if (thread == THREAD_NULL) { return KERN_INVALID_ARGUMENT; } if (exception_mask & ~EXC_MASK_VALID) { return KERN_INVALID_ARGUMENT; } if (!info_only && !ports) { return KERN_INVALID_ARGUMENT; } /* * Allocate a save area for FP state before taking thread lock, … more in source
thread_get_exception_ports source · thread_get_exception_ports reference
kern_return_t thread_get_exception_ports( thread_t thread, exception_mask_t exception_mask, exception_mask_array_t masks, mach_msg_type_number_t *CountCnt, exception_port_array_t ports, exception_behavior_array_t behaviors, thread_state_flavor_array_t flavors) { return thread_get_exception_ports_internal(thread, exception_mask, masks, CountCnt, NULL, ports, behaviors, flavors); }
task_get_exception_ports_internal source
static kern_return_t task_get_exception_ports_internal( task_t task, exception_mask_t exception_mask, exception_mask_array_t masks, mach_msg_type_number_t *CountCnt, exception_port_info_array_t ports_info, exception_port_array_t ports, exception_behavior_array_t behaviors, thread_state_flavor_array_t flavors) { unsigned int count; boolean_t info_only = (ports_info != NULL); ipc_port_t port_ptrs[EXC_TYPES_COUNT]; /* pointers only, does not hold right */ if (task == TASK_NULL) { return KERN_INVALID_ARGUMENT; } if (exception_mask & ~EXC_MASK_VALID) { return KERN_INVALID_ARGUMENT; } if (!info_only && !ports) { return KERN_INVALID_ARGUMENT; } /* * Allocate a save area for FP state before taking task lock, * if necessary, to ensure that VM_KERNEL_ADDRHASH() doesn't cause … more in source
task_get_exception_ports source · task_get_exception_ports reference
kern_return_t task_get_exception_ports( task_t task, exception_mask_t exception_mask, exception_mask_array_t masks, mach_msg_type_number_t *CountCnt, exception_port_array_t ports, exception_behavior_array_t behaviors, thread_state_flavor_array_t flavors) { return task_get_exception_ports_internal(task, exception_mask, masks, CountCnt, NULL, ports, behaviors, flavors); }