+/*
+ * Routine: ipc_thread_reset
+ * Purpose:
+ * Reset the IPC state for a given Mach thread when
+ * its task enters an elevated security context.
+ * Both the thread port and its exception ports have
+ * to be reset. Its RPC reply port cannot have any
+ * rights outstanding, so it should be fine.
+ * Conditions:
+ * Nothing locked.
+ */
+
+void
+ipc_thread_reset(
+ thread_t thread)
+{
+ ipc_port_t old_kport, new_kport;
+ ipc_port_t old_sself;
+ ipc_port_t old_exc_actions[EXC_TYPES_COUNT];
+ int i;
+
+ new_kport = ipc_port_alloc_kernel();
+ if (new_kport == IP_NULL)
+ panic("ipc_task_reset");
+
+ thread_mtx_lock(thread);
+
+ old_kport = thread->ith_self;
+
+ if (old_kport == IP_NULL) {
+ /* the is already terminated (can this happen?) */
+ thread_mtx_unlock(thread);
+ ipc_port_dealloc_kernel(new_kport);
+ return;
+ }
+
+ thread->ith_self = new_kport;
+ old_sself = thread->ith_sself;
+ thread->ith_sself = ipc_port_make_send(new_kport);
+ ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE);
+ ipc_kobject_set(new_kport, (ipc_kobject_t) thread, IKOT_THREAD);
+
+ for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
+ if (!thread->exc_actions[i].privileged) {
+ old_exc_actions[i] = thread->exc_actions[i].port;
+ thread->exc_actions[i].port = IP_NULL;
+ } else {
+ old_exc_actions[i] = IP_NULL;
+ }
+ }/* for */
+
+ thread_mtx_unlock(thread);
+
+ /* release the naked send rights */
+
+ if (IP_VALID(old_sself))
+ ipc_port_release_send(old_sself);
+
+ for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
+ if (IP_VALID(old_exc_actions[i])) {
+ ipc_port_release_send(old_exc_actions[i]);
+ }
+ }/* for */
+
+ /* destroy the kernel port */
+ ipc_port_dealloc_kernel(old_kport);
+}
+