mach_port_set_ktype attempts to lock the referenced port twice. This is
resolved by adding ipc_kobject_set_locked() that permits altering the
kernel type of a port which has already been locked by the caller.
---
 ipc/mach_port.c    |  8 ++++----
 kern/ipc_kobject.c | 18 +++++++++++++++++-
 kern/ipc_kobject.h |  7 +++++++
 3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/ipc/mach_port.c b/ipc/mach_port.c
index eed3e725..2783c46e 100644
--- a/ipc/mach_port.c
+++ b/ipc/mach_port.c
@@ -1594,10 +1594,10 @@ mach_port_set_ktype(
 
        /* port is locked and active */
        if (ip_kotype(port) == IKOT_NONE || ip_kotype(port) == IKOT_USER_DEVICE)
-         ipc_kobject_set(port, IKO_NULL,
-                         ktype == MACH_PORT_KTYPE_NONE
-                         ? IKOT_NONE
-                         : IKOT_USER_DEVICE);
+         ipc_kobject_set_locked(port, IKO_NULL,
+                                ktype == MACH_PORT_KTYPE_NONE
+                                ? IKOT_NONE
+                                : IKOT_USER_DEVICE);
        else
          kr = KERN_INVALID_ARGUMENT;
 
diff --git a/kern/ipc_kobject.c b/kern/ipc_kobject.c
index 0a815953..2e727aee 100644
--- a/kern/ipc_kobject.c
+++ b/kern/ipc_kobject.c
@@ -285,10 +285,26 @@ void
 ipc_kobject_set(ipc_port_t port, ipc_kobject_t kobject, ipc_kobject_type_t 
type)
 {
        ip_lock(port);
+       ipc_kobject_set_locked(port, kobject, type);
+       ip_unlock(port);
+}
+
+/*
+ *     Routine:        ipc_kobject_set_locked
+ *     Purpose:
+ *             As per ipc_kobject_set but see Conditions.
+ *     Conditions:
+ *             Port must be locked by the caller and remains locked after
+ *              return.  The port must be active.
+ */
+
+void
+ipc_kobject_set_locked(ipc_port_t port, ipc_kobject_t kobject,
+                      ipc_kobject_type_t type)
+{
        assert(ip_active(port));
        port->ip_bits = (port->ip_bits &~ IO_BITS_KOTYPE) | type;
        port->ip_kobject = kobject;
-       ip_unlock(port);
 }
 
 /*
diff --git a/kern/ipc_kobject.h b/kern/ipc_kobject.h
index 63ad87c5..649f8e61 100644
--- a/kern/ipc_kobject.h
+++ b/kern/ipc_kobject.h
@@ -112,6 +112,13 @@ extern void ipc_kobject_set(
        ipc_kobject_t           kobject,
        ipc_kobject_type_t      type);
 
+/* As ipc_kobject_set but with the condition that 'port' is
+ already locked by the caller. */
+extern void ipc_kobject_set_locked(
+       ipc_port_t              port,
+       ipc_kobject_t           kobject,
+       ipc_kobject_type_t      type);
+
 /* Release any kernel object resources associated with a port */
 extern void ipc_kobject_destroy(
        ipc_port_t              port);
-- 
2.51.0


Reply via email to