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