DragonFlyBSD Kernel Audit
DF-0055 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/kern_udev.c b/sys/kern/kern_udev.c
--- a/sys/kern/kern_udev.c
+++ b/sys/kern/kern_udev.c
@@ -538,6 +538,13 @@
 
 	while ((ev = TAILQ_FIRST(&udev_evq)) &&
 	       ev->ev.ev_dict != NULL) {
+		/* DF-0055: release the shared dict exactly once, here, when the
+		 * event is reaped (all readers have advanced past it). Previously
+		 * udev_event_externalize() released the dict on the FIRST reader's
+		 * externalize, freeing it while the event remained on udev_evq and
+		 * its non-NULL ev_dict field dangled -- a UAF for subsequent readers. */
+		prop_object_release(ev->ev.ev_dict);
+		ev->ev.ev_dict = NULL;
 		TAILQ_REMOVE(&udev_evq, ev, link);
 		objcache_put(udev_event_kernel_cache, ev);
 		--udev_evqlen;
@@ -568,7 +575,10 @@
 		return NULL;
 	}
 
-	prop_object_release(ev->ev.ev_dict);
+	/* DF-0055: do NOT release ev->ev.ev_dict here -- it is shared by every
+	 * reader and is now properly released once in udev_clean_events_locked()
+	 * when the event is reaped. The temp `dict` above holds the only extra
+	 * reference and is released below. */
 
 	xml = prop_dictionary_externalize(dict);