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);