+
+ return kr;
+}
+
+/*
+ * task_set_port_space:
+ *
+ * Set port name space of task to specified size.
+ */
+kern_return_t
+task_set_port_space(
+ ipc_space_t space,
+ int table_entries)
+{
+ kern_return_t kr;
+
+ if (space == IS_NULL)
+ return KERN_INVALID_TASK;
+
+ is_write_lock(space);
+
+ if (!is_active(space)) {
+ is_write_unlock(space);
+ return KERN_INVALID_TASK;
+ }
+
+ kr = ipc_entry_grow_table(space, table_entries);
+ if (kr == KERN_SUCCESS)
+ is_write_unlock(space);
+ return kr;
+}
+
+/*
+ * Routine: mach_port_guard_locked [helper routine]
+ * Purpose:
+ * Sets a new guard for a locked port.
+ * Conditions:
+ * Port Locked.
+ * Returns:
+ * KERN_SUCCESS Port Guarded.
+ * KERN_INVALID_ARGUMENT Port already contains a context/guard.
+ */
+static kern_return_t
+mach_port_guard_locked(
+ ipc_port_t port,
+ uint64_t guard,
+ boolean_t strict)
+{
+ if (port->ip_context)
+ return KERN_INVALID_ARGUMENT;
+
+ port->ip_context = guard;
+ port->ip_guarded = 1;
+ port->ip_strict_guard = (strict)?1:0;
+ return KERN_SUCCESS;
+}
+
+/*
+ * Routine: mach_port_unguard_locked [helper routine]
+ * Purpose:
+ * Removes guard for a locked port.
+ * Conditions:
+ * Port Locked.
+ * Returns:
+ * KERN_SUCCESS Port Unguarded.
+ * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
+ * This also raises a EXC_GUARD exception.
+ */
+static kern_return_t
+mach_port_unguard_locked(
+ ipc_port_t port,
+ mach_port_name_t name,
+ uint64_t guard)
+{
+ /* Port locked and active */
+ if (!port->ip_guarded) {
+ /* Port already unguarded; Raise exception */
+ mach_port_guard_exception(name, guard, 0, kGUARD_EXC_UNGUARDED);
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ if (port->ip_context != guard) {
+ /* Incorrect guard; Raise exception */
+ mach_port_guard_exception(name, guard, port->ip_context, kGUARD_EXC_INCORRECT_GUARD);
+ return KERN_INVALID_ARGUMENT;
+ }
+
+ port->ip_context = 0;
+ port->ip_guarded = port->ip_strict_guard = 0;
+ return KERN_SUCCESS;
+}
+
+
+/*
+ * Routine: mach_port_guard_exception [helper routine]
+ * Purpose:
+ * Marks the thread with AST_GUARD for mach port guard violation.
+ * Also saves exception info in thread structure.
+ * Conditions:
+ * None.
+ * Returns:
+ * KERN_FAILURE Thread marked with AST_GUARD.
+ */
+kern_return_t
+mach_port_guard_exception(
+ mach_port_name_t name,
+ __unused uint64_t inguard,
+ uint64_t portguard,
+ unsigned reason)
+{
+ mach_exception_code_t code = 0;
+ EXC_GUARD_ENCODE_TYPE(code, GUARD_TYPE_MACH_PORT);
+ EXC_GUARD_ENCODE_FLAVOR(code, reason);
+ EXC_GUARD_ENCODE_TARGET(code, name);
+ mach_exception_subcode_t subcode = (uint64_t)portguard;
+ thread_t t = current_thread();
+ thread_guard_violation(t, code, subcode);
+ return KERN_FAILURE;
+}
+
+
+/*
+ * Routine: mach_port_guard_ast
+ * Purpose:
+ * Raises an exception for mach port guard violation.
+ * Conditions:
+ * None.
+ * Returns:
+ * None.
+ */
+
+void
+mach_port_guard_ast(thread_t __unused t,
+ mach_exception_data_type_t code, mach_exception_data_type_t subcode)
+{
+ assert(t->task != kernel_task);
+
+ /* Raise an EXC_GUARD exception */
+ task_exception_notify(EXC_GUARD, code, subcode);
+
+ /* Terminate task which caused the exception */
+ task_bsdtask_kill(current_task());
+}
+
+/*
+ * Routine: mach_port_construct [kernel call]
+ * Purpose:
+ * Constructs a mach port with the provided set of options.
+ * Conditions:
+ * None.
+ * Returns:
+ * KERN_SUCCESS The right is allocated.
+ * KERN_INVALID_TASK The space is null.
+ * KERN_INVALID_TASK The space is dead.
+ * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
+ * KERN_NO_SPACE No room in space for another right.
+ * KERN_FAILURE Illegal option values requested.
+ */
+
+kern_return_t
+mach_port_construct(
+ ipc_space_t space,
+ mach_port_options_t *options,
+ uint64_t context,
+ mach_port_name_t *name)
+{
+ kern_return_t kr;
+ ipc_port_t port;
+
+ if (space == IS_NULL)
+ return (KERN_INVALID_TASK);
+
+ /* Allocate a new port in the IPC space */
+ kr = ipc_port_alloc(space, name, &port);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ /* Port locked and active */
+ if (options->flags & MPO_CONTEXT_AS_GUARD) {
+ kr = mach_port_guard_locked(port, (uint64_t) context, (options->flags & MPO_STRICT));
+ /* A newly allocated and locked port should always be guarded successfully */
+ assert(kr == KERN_SUCCESS);
+ } else {
+ port->ip_context = context;
+ }
+
+ /* Unlock port */
+ ip_unlock(port);
+
+ /* Set port attributes as requested */
+
+ if (options->flags & MPO_QLIMIT) {
+ kr = mach_port_set_attributes(space, *name, MACH_PORT_LIMITS_INFO,
+ (mach_port_info_t)&options->mpl, sizeof(options->mpl)/sizeof(int));
+ if (kr != KERN_SUCCESS)
+ goto cleanup;
+ }
+
+ if (options->flags & MPO_TEMPOWNER) {
+ kr = mach_port_set_attributes(space, *name, MACH_PORT_TEMPOWNER, NULL, 0);
+ if (kr != KERN_SUCCESS)
+ goto cleanup;
+ }
+
+ if (options->flags & MPO_IMPORTANCE_RECEIVER) {
+ kr = mach_port_set_attributes(space, *name, MACH_PORT_IMPORTANCE_RECEIVER, NULL, 0);
+ if (kr != KERN_SUCCESS)
+ goto cleanup;
+ }
+
+ if (options->flags & MPO_DENAP_RECEIVER) {
+ kr = mach_port_set_attributes(space, *name, MACH_PORT_DENAP_RECEIVER, NULL, 0);
+ if (kr != KERN_SUCCESS)
+ goto cleanup;
+ }
+
+ if (options->flags & MPO_INSERT_SEND_RIGHT) {
+ kr = ipc_object_copyin(space, *name, MACH_MSG_TYPE_MAKE_SEND, (ipc_object_t *)&port);
+ if (kr != KERN_SUCCESS)
+ goto cleanup;
+
+ kr = mach_port_insert_right(space, *name, port, MACH_MSG_TYPE_PORT_SEND);
+ if (kr != KERN_SUCCESS)
+ goto cleanup;
+ }
+
+ return KERN_SUCCESS;
+
+cleanup:
+ /* Attempt to destroy port. If its already destroyed by some other thread, we're done */
+ (void) mach_port_destruct(space, *name, 0, context);
+ return kr;
+}
+
+/*
+ * Routine: mach_port_destruct [kernel call]
+ * Purpose:
+ * Destroys a mach port with appropriate guard
+ * Conditions:
+ * None.
+ * Returns:
+ * KERN_SUCCESS The name is destroyed.
+ * KERN_INVALID_TASK The space is null.
+ * KERN_INVALID_TASK The space is dead.
+ * KERN_INVALID_NAME The name doesn't denote a right.
+ * KERN_INVALID_RIGHT The right isn't correct.
+ * KERN_INVALID_VALUE The delta for send right is incorrect.
+ * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
+ * This also raises a EXC_GUARD exception.
+ */
+
+kern_return_t
+mach_port_destruct(
+ ipc_space_t space,
+ mach_port_name_t name,
+ mach_port_delta_t srdelta,
+ uint64_t guard)
+{
+ kern_return_t kr;
+ ipc_entry_t entry;
+
+ if (space == IS_NULL)
+ return KERN_INVALID_TASK;
+
+ if (!MACH_PORT_VALID(name))
+ return KERN_INVALID_NAME;
+
+ /* Remove reference for receive right */
+ kr = ipc_right_lookup_write(space, name, &entry);
+ if (kr != KERN_SUCCESS)
+ return kr;
+ /* space is write-locked and active */
+ kr = ipc_right_destruct(space, name, entry, srdelta, guard); /* unlocks */
+
+ return kr;
+}
+
+/*
+ * Routine: mach_port_guard [kernel call]
+ * Purpose:
+ * Guard a mach port with specified guard value.
+ * The context field of the port is used as the guard.
+ * Conditions:
+ * None.
+ * Returns:
+ * KERN_SUCCESS The name is destroyed.
+ * KERN_INVALID_TASK The space is null.
+ * KERN_INVALID_TASK The space is dead.
+ * KERN_INVALID_NAME The name doesn't denote a right.
+ * KERN_INVALID_RIGHT The right isn't correct.
+ * KERN_INVALID_ARGUMENT Port already contains a context/guard.
+ */
+kern_return_t
+mach_port_guard(
+ ipc_space_t space,
+ mach_port_name_t name,
+ uint64_t guard,
+ boolean_t strict)
+{
+ kern_return_t kr;
+ ipc_port_t port;
+
+ if (space == IS_NULL)
+ return KERN_INVALID_TASK;
+
+ if (!MACH_PORT_VALID(name))
+ return KERN_INVALID_NAME;
+
+ /* Guard can be applied only to receive rights */
+ kr = ipc_port_translate_receive(space, name, &port);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ /* Port locked and active */
+ kr = mach_port_guard_locked(port, guard, strict);
+ ip_unlock(port);
+
+ return kr;
+
+}
+
+/*
+ * Routine: mach_port_unguard [kernel call]
+ * Purpose:
+ * Unguard a mach port with specified guard value.
+ * Conditions:
+ * None.
+ * Returns:
+ * KERN_SUCCESS The name is destroyed.
+ * KERN_INVALID_TASK The space is null.
+ * KERN_INVALID_TASK The space is dead.
+ * KERN_INVALID_NAME The name doesn't denote a right.
+ * KERN_INVALID_RIGHT The right isn't correct.
+ * KERN_INVALID_ARGUMENT Port is either unguarded already or guard mismatch.
+ * This also raises a EXC_GUARD exception.
+ */
+kern_return_t
+mach_port_unguard(
+ ipc_space_t space,
+ mach_port_name_t name,
+ uint64_t guard)
+{
+
+ kern_return_t kr;
+ ipc_port_t port;
+
+ if (space == IS_NULL)
+ return KERN_INVALID_TASK;
+
+ if (!MACH_PORT_VALID(name))
+ return KERN_INVALID_NAME;
+
+ kr = ipc_port_translate_receive(space, name, &port);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ /* Port locked and active */
+ kr = mach_port_unguard_locked(port, name, guard);
+ ip_unlock(port);