DF-0436 / fix.diff
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)) |