]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ipc/ipc_port.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_port.c
index 2d6f7e7d14bb41c59a9beea2e12f43be6f3a8c51..2b7c9217ca75050241a10d47ece164b46a1f0a6f 100644 (file)
@@ -83,6 +83,7 @@
 #include <ipc/ipc_entry.h>
 #include <ipc/ipc_space.h>
 #include <ipc/ipc_object.h>
+#include <ipc/ipc_right.h>
 #include <ipc/ipc_port.h>
 #include <ipc/ipc_pset.h>
 #include <ipc/ipc_kmsg.h>
@@ -641,6 +642,8 @@ ipc_port_clear_receiver(
  *     Purpose:
  *             Initializes a newly-allocated port.
  *             Doesn't touch the ip_object fields.
+ *
+ *             The memory is expected to be zero initialized (allocated with Z_ZERO).
  */
 
 void
@@ -655,46 +658,23 @@ ipc_port_init(
        port->ip_receiver = space;
        port->ip_receiver_name = name;
 
-       port->ip_mscount = 0;
-       port->ip_srights = 0;
-       port->ip_sorights = 0;
        if (flags & IPC_PORT_INIT_MAKE_SEND_RIGHT) {
                port->ip_srights = 1;
                port->ip_mscount = 1;
        }
 
-       port->ip_nsrequest = IP_NULL;
-       port->ip_pdrequest = IP_NULL;
-       port->ip_requests = IPR_NULL;
-
-       port->ip_premsg = IKM_NULL;
-       port->ip_context = 0;
-       port->ip_reply_context = 0;
-
-       port->ip_sprequests  = 0;
-       port->ip_spimportant = 0;
-       port->ip_impdonation = 0;
-       port->ip_tempowner   = 0;
-
-       port->ip_guarded      = 0;
-       port->ip_strict_guard = 0;
-       port->ip_immovable_receive = 0;
-       port->ip_no_grant    = 0;
-       port->ip_immovable_send = 0;
-       port->ip_impcount    = 0;
-
        if (flags & IPC_PORT_INIT_FILTER_MESSAGE) {
                port->ip_object.io_bits |= IP_BIT_FILTER_MSG;
        }
 
        port->ip_tg_block_tracking = (flags & IPC_PORT_INIT_TG_BLOCK_TRACKING) != 0;
-       port->ip_specialreply = (flags & IPC_PORT_INIT_SPECIAL_REPLY) != 0;
-       port->ip_sync_link_state = PORT_SYNC_LINK_ANY;
-       port->ip_sync_bootstrap_checkin = 0;
 
-       ipc_special_reply_port_bits_reset(port);
+       if (flags & IPC_PORT_INIT_SPECIAL_REPLY) {
+               port->ip_specialreply = true;
+               port->ip_immovable_receive = true;
+       }
 
-       port->ip_send_turnstile = TURNSTILE_NULL;
+       port->ip_sync_link_state = PORT_SYNC_LINK_ANY;
 
        ipc_mqueue_kind_t kind = IPC_MQUEUE_KIND_NONE;
        if (flags & IPC_PORT_INIT_MESSAGE_QUEUE) {
@@ -967,6 +947,15 @@ ipc_port_destroy(ipc_port_t port)
        /* check for a backup port */
        pdrequest = port->ip_pdrequest;
 
+       /*
+        * Panic if a special reply has ip_pdrequest or ip_tempowner
+        * set, as this causes a type confusion while accessing the
+        * kdata union.
+        */
+       if (special_reply && (pdrequest || port->ip_tempowner)) {
+               panic("ipc_port_destroy: invalid state");
+       }
+
 #if IMPORTANCE_INHERITANCE
        /* determine how many assertions to drop and from whom */
        if (port->ip_tempowner != 0) {
@@ -1528,7 +1517,7 @@ ipc_port_send_update_inheritor(
        struct knote *kn;
        turnstile_update_flags_t inheritor_flags = TURNSTILE_INHERITOR_TURNSTILE;
 
-       assert(imq_held(mqueue));
+       imq_held(mqueue);
 
        if (!ip_active(port)) {
                /* this port is no longer active, it should not push anywhere */
@@ -2316,6 +2305,42 @@ ipc_port_get_watchport_inheritor(
        return ipc_port_watchport_elem(port)->twe_task->watchports->tw_thread;
 }
 
+/*
+ *     Routine:        ipc_port_get_receiver_task
+ *     Purpose:
+ *             Returns receiver task pointer and its pid (if any) for port.
+ *
+ *     Conditions:
+ *             Nothing locked.
+ */
+pid_t
+ipc_port_get_receiver_task(ipc_port_t port, uintptr_t *task)
+{
+       task_t receiver = TASK_NULL;
+       pid_t pid = -1;
+
+       if (!port) {
+               goto out;
+       }
+
+       ip_lock(port);
+       if (ip_active(port) &&
+           MACH_PORT_VALID(port->ip_receiver_name) &&
+           port->ip_receiver &&
+           port->ip_receiver != ipc_space_kernel &&
+           port->ip_receiver != ipc_space_reply) {
+               receiver = port->ip_receiver->is_task;
+               pid = task_pid(receiver);
+       }
+       ip_unlock(port);
+
+out:
+       if (task) {
+               *task = (uintptr_t)receiver;
+       }
+       return pid;
+}
+
 /*
  *     Routine:        ipc_port_impcount_delta
  *     Purpose:
@@ -2679,10 +2704,11 @@ ipc_port_copy_send(
  *             Nothing locked.
  */
 
-mach_port_name_t
-ipc_port_copyout_send(
+static mach_port_name_t
+ipc_port_copyout_send_internal(
        ipc_port_t      sright,
-       ipc_space_t     space)
+       ipc_space_t     space,
+       ipc_object_copyout_flags_t flags)
 {
        mach_port_name_t name;
 
@@ -2690,10 +2716,8 @@ ipc_port_copyout_send(
                kern_return_t kr;
 
                kr = ipc_object_copyout(space, ip_to_object(sright),
-                   MACH_MSG_TYPE_PORT_SEND, NULL, NULL, &name);
+                   MACH_MSG_TYPE_PORT_SEND, flags, NULL, NULL, &name);
                if (kr != KERN_SUCCESS) {
-                       ipc_port_release_send(sright);
-
                        if (kr == KERN_INVALID_CAPABILITY) {
                                name = MACH_PORT_DEAD;
                        } else {
@@ -2707,28 +2731,38 @@ ipc_port_copyout_send(
        return name;
 }
 
+mach_port_name_t
+ipc_port_copyout_send(
+       ipc_port_t      sright,
+       ipc_space_t     space)
+{
+       return ipc_port_copyout_send_internal(sright, space, IPC_OBJECT_COPYOUT_FLAGS_NONE);
+}
+
+mach_port_name_t
+ipc_port_copyout_send_pinned(
+       ipc_port_t      sright,
+       ipc_space_t     space)
+{
+       return ipc_port_copyout_send_internal(sright, space, IPC_OBJECT_COPYOUT_FLAGS_PINNED);
+}
+
 /*
- *     Routine:        ipc_port_release_send
+ *     Routine:        ipc_port_release_send_and_unlock
  *     Purpose:
  *             Release a naked send right.
  *             Consumes a ref for the port.
  *     Conditions:
- *             Nothing locked.
+ *             Port is valid and locked on entry
+ *             Port is unlocked on exit.
  */
-
 void
-ipc_port_release_send(
+ipc_port_release_send_and_unlock(
        ipc_port_t      port)
 {
        ipc_port_t nsrequest = IP_NULL;
        mach_port_mscount_t mscount;
 
-       if (!IP_VALID(port)) {
-               return;
-       }
-
-       ip_lock(port);
-
        assert(port->ip_srights > 0);
        if (port->ip_srights == 0) {
                panic("Over-release of port %p send right!", port);
@@ -2756,6 +2790,25 @@ ipc_port_release_send(
        }
 }
 
+/*
+ *     Routine:        ipc_port_release_send
+ *     Purpose:
+ *             Release a naked send right.
+ *             Consumes a ref for the port.
+ *     Conditions:
+ *             Nothing locked.
+ */
+
+void
+ipc_port_release_send(
+       ipc_port_t      port)
+{
+       if (IP_VALID(port)) {
+               ip_lock(port);
+               ipc_port_release_send_and_unlock(port);
+       }
+}
+
 /*
  *     Routine:        ipc_port_make_sonce_locked
  *     Purpose:
@@ -2886,17 +2939,16 @@ ipc_port_alloc_special(
 {
        ipc_port_t port;
 
-       port = ip_object_to_port(io_alloc(IOT_PORT));
+       port = ip_object_to_port(io_alloc(IOT_PORT, Z_WAITOK | Z_ZERO));
        if (port == IP_NULL) {
                return IP_NULL;
        }
 
-#if     MACH_ASSERT
+#if MACH_ASSERT
        uintptr_t buf[IP_CALLSTACK_MAX];
        ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX);
 #endif /* MACH_ASSERT */
 
-       bzero((char *)port, sizeof(*port));
        io_lock_init(ip_to_object(port));
        port->ip_references = 1;
        port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);