DragonFlyBSD Kernel Audit
DF-2737 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -1377,6 +1377,15 @@
 		if (oid == NULL)
 			return (ENOENT);
 
+		/*
+		 * A DYING oid is being torn down and its handler may
+		 * vanish at any moment (the remover drops the xlock
+		 * while draining running handlers).  Report it as gone
+		 * instead of dispatching into it.
+		 */
+		if (oid->oid_kind & CTLFLAG_DYING)
+			return (ENOENT);
+
 		indx++;
 		if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 			if (oid->oid_handler != NULL || indx == namelen) {
@@ -1473,6 +1482,16 @@
 #endif
 	}
 
+	/*
+	 * Count in-flight handler executions so that
+	 * sysctl_remove_oid_locked() can drain them before freeing a
+	 * dynamic oid during module teardown.  Without this counter
+	 * the CTLFLAG_DYING drain in sysctl_remove_oid_locked() is
+	 * dead code: nothing else in the kernel ever touches
+	 * oid_running.
+	 */
+	atomic_add_int(&oid->oid_running, 1);
+
 	if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE)
 		error = oid->oid_handler(oid, (int *)arg1 + indx, arg2 - indx,
 					 req);
@@ -1480,6 +1499,9 @@
 		error = oid->oid_handler(oid, oid->oid_arg1, oid->oid_arg2,
 					 req);
 
+	if (atomic_fetchadd_int(&oid->oid_running, -1) == 1)
+		wakeup(&oid->oid_running);
+
 	if ((oid->oid_kind & CTLFLAG_NOLOCK) == 0)
 		lockmgr(&oid->oid_lock, LK_RELEASE);
 	return (error);