DragonFlyBSD Kernel Audit
DF-0436 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netgraph7/bluetooth/socket/ng_btsocket_hci_raw.c b/sys/netgraph7/bluetooth/socket/ng_btsocket_hci_raw.c
--- a/sys/netgraph7/bluetooth/socket/ng_btsocket_hci_raw.c
+++ b/sys/netgraph7/bluetooth/socket/ng_btsocket_hci_raw.c
@@ -676,11 +676,25 @@
 	switch ((type = *mtod(m, u_int8_t *))) {
 	case NG_HCI_CMD_PKT:
 		if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)) {
+			int	ogf, ocf;
+
 			opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode);
+			ogf = NG_HCI_OGF(opcode);
+			ocf = NG_HCI_OCF(opcode);
 
-			if (!bit_test(
-ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF(opcode) - 1],
-NG_HCI_OCF(opcode) - 1))
+			/*
+			 * DF-0436: OGF==0 makes commands[ogf-1] = commands[-1],
+			 * an OOB read 128 bytes before commands[0] (96 bytes
+			 * before the struct allocation).  OCF==0 makes
+			 * bit_test(..,-1) read 1 byte before the array.  Both
+			 * also turn the security filter into a heap-byte-defined
+			 * allow/deny decision (security bypass).  Reject opcode
+			 * 0/0 and any other zero field outright.
+			 */
+			if (ogf == 0 || ocf == 0 ||
+			    !bit_test(
+ng_btsocket_hci_raw_sec_filter->commands[ogf - 1],
+ocf - 1))
 				return (EPERM);
 		}
 
@@ -700,7 +714,17 @@
 		if (!d)
 			return (EINVAL);
 
-		event = mtod(m, ng_hci_event_pkt_t *)->event - 1;
+		event = mtod(m, ng_hci_event_pkt_t *)->event;
+
+		/*
+		 * DF-0436: event==0 yields event-1=-1 below, which makes
+		 * bit_test(events,-1) read events[-1] (1 byte before the
+		 * events array, i.e. before the struct).  Reject event 0
+		 * outright; legitimate HCI event codes are >= 1.
+		 */
+		if (event == 0)
+			return (EINVAL);
+		event--;
 
 		if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED))
 			if (!bit_test(ng_btsocket_hci_raw_sec_filter->events, event))