DragonFlyBSD Kernel Audit
DF-0683 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netbt/hci_unit.c b/sys/netbt/hci_unit.c
--- a/sys/netbt/hci_unit.c
+++ b/sys/netbt/hci_unit.c
@@ -232,6 +232,16 @@
 	unit->hci_flags &= ~BTF_RUNNING;
 
 	/*
+	 * Acquire hci_devlock: hci_intr is netisr-driven (via btintr in
+	 * bt_input.c) and may be running concurrently on another CPU,
+	 * iterating hci_links / dequeuing from the rx queues / touching
+	 * the *rxqlen counters. Without this lock our teardown races
+	 * hci_intr and can panic in its KASSERT(m != NULL) or use a link
+	 * after hci_link_free() freed it.
+	 */
+	lockmgr(&unit->hci_devlock, LK_EXCLUSIVE);
+
+	/*
 	 * close down any links, take care to close SCO first since
 	 * they may depend on ACL links.
 	 */
@@ -247,8 +257,6 @@
 	while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
 		hci_memo_free(memo);
 
-	/* (no need to hold hci_devlock, the driver is disabled) */
-
 	IF_DRAIN(&unit->hci_eventq);
 	unit->hci_eventqlen = 0;
 
@@ -260,6 +268,8 @@
 
 	IF_DRAIN(&unit->hci_cmdwait);
 	IF_DRAIN(&unit->hci_scodone);
+
+	lockmgr(&unit->hci_devlock, LK_RELEASE);
 }
 
 struct hci_unit *
@@ -339,6 +349,8 @@
 		unit->hci_eventqlen--;
 		lockmgr(&unit->hci_devlock, LK_RELEASE);
 
+		if (m == NULL)
+			goto another;
 		KKASSERT(m != NULL);
 
 		DPRINTFN(10, "(%s) recv event, len = %d\n",