DragonFlyBSD Kernel Audit
DF-2973 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/subr_eventhandler.c
+++ b/sys/kern/subr_eventhandler.c
@@ -121,6 +121,28 @@
     /* XXX insert diagnostic check here? */
 
     if (ep != NULL) {
+	/*
+	 * DF-2973: never trust the tag.  A tag from another list (or a
+	 * stale / double-deregistered tag) makes TAILQ_REMOVE unlink and
+	 * kfree() an entry that is not on <list>, corrupting both lists'
+	 * tail sentinels (dangling tqh_last -> write-after-free on the
+	 * next registration).  Verify membership first.
+	 */
+	struct eventhandler_entry *it;
+	int found = 0;
+
+	TAILQ_FOREACH(it, &list->el_entries, ee_link) {
+	    if (it == ep) {
+		found = 1;
+		break;
+	    }
+	}
+	if (!found) {
+	    kprintf("eventhandler_deregister: tag %p not in list \"%s\""
+		    " -- deregistration ignored\n", ep, list->el_name);
+	    lwkt_reltoken(&evlist_token);
+	    return;
+	}
 	/* remove just this entry */
 	TAILQ_REMOVE(&list->el_entries, ep, ee_link);
 	kfree(ep, M_EVENTHANDLER);