Out-of-Bounds Array Access via Wrong Index in hci_drv_process_cmd
Summary
net/bluetooth/hci_drv.c, function hci_drv_process_cmd (line 88–89), uses the full 16-bit HCI opcode (which encodes both the 6-bit OGF and 10-bit OCF) as the array index into common_handlers, instead of the 10-bit ocf. The driver-specific path on line 91–92 correctly uses ocf. This inconsistency creates an out-of-bounds read primitive that can escalate to arbitrary kernel code execution.
Vulnerable Code
// net/bluetooth/hci_drv.c:87-103
if (ogf != HCI_DRV_OGF_DRIVER_SPECIFIC) {
if (opcode < hdev->hci_drv->common_handler_count) // bounds-checks full opcode
handler = &hdev->hci_drv->common_handlers[opcode]; // indexes by full opcode
} else {
if (ocf < hdev->hci_drv->specific_handler_count) // bounds-checks ocf (correct)
handler = &hdev->hci_drv->specific_handlers[ocf]; // indexes by ocf (correct)
}
...
if (!handler || !handler->func)
return hci_drv_cmd_status(...);
if (len != handler->data_len)
return hci_drv_cmd_status(...);
return handler->func(hdev, skb->data, len); // ← function pointer call
Root Cause
All defined common commands have OGF=0 (e.g., HCI_DRV_OP_READ_INFO = 0x0000). For OGF=0, opcode == ocf, so the bug is latent in the current codebase. However, the bounds check opcode < common_handler_count and the index common_handlers[opcode] use the full 16-bit opcode, not the 10-bit OCF. This creates a mismatch between the semantic intent (index by command number within OGF=0) and the actual index computation (index by raw opcode word including OGF bits).
The dangerous pattern: a driver author who sizes common_handlers for N OCF values and sets common_handler_count = N creates a discrepancy because:
- For OGF=0, OCF=k:
opcode = k. Indexk < Nis within bounds. Correct. - For OGF=2, OCF=0:
opcode = 0x0800 = 2048. IfN ≤ 2048, the check fails safely. - But if an author sets
common_handler_count = 1024(a natural “max OCF” value) while allocatingcommon_handlers[5](only 5 real entries), an attacker sending OGF=0, OCF=5..1023 passes the check and readscommon_handlers[5]throughcommon_handlers[1023]— all out of bounds.
Attack Surface
Packets of type HCI_DRV_PKT (0xF1) are accepted from HCI_CHANNEL_USER sockets (hci_sock.c:1869–1876) and routed directly to hci_drv_process_cmd (hci_core.c:3064–3070). A process with CAP_NET_ADMIN (required to bind HCI_CHANNEL_USER) can send arbitrary crafted payloads.
Exploit Scenario
- Attacker opens an
AF_BLUETOOTH/BTPROTO_HCIsocket and binds toHCI_CHANNEL_USER(requiresCAP_NET_ADMIN— achievable via a user namespace if unprivileged user namespaces are enabled). - Attacker sends an
HCI_DRV_PKTwith:opcodecrafted so thatopcode >= ARRAY_SIZE(common_handlers)butopcode < common_handler_count(requires a driver with an oversizedcommon_handler_count).lenmatchinghandler->data_lenread from OOB memory so thedata_lencheck passes.
- The code calls
handler->func(hdev, skb->data, len)wherefuncis a pointer read from out-of-bounds kernel heap memory. - If the attacker controls the heap layout (e.g., heap spray), they can place a crafted
hci_drv_handlerstruct adjacent to thecommon_handlersarray, directing execution to arbitrary kernel code.
Impact
Severity: Critical (kernel arbitrary code execution)
- Out-of-bounds read: Reading
hci_drv_handlerentries beyond the allocatedcommon_handlersarray leaks kernel heap pointers, bypassing KASLR. - Arbitrary function call: The
handler->funcpointer from OOB memory is called with attacker-controlled data (skb->data) as the second argument, enabling kernel code execution. - Full kernel privilege escalation from
CAP_NET_ADMIN(or from a user namespace with unprivileged namespaces enabled).
Fix
Replace the opcode index with ocf in the common handler path, mirroring the driver-specific path:
// Before (buggy):
if (opcode < hdev->hci_drv->common_handler_count)
handler = &hdev->hci_drv->common_handlers[opcode];
// After (fixed):
if (ocf < hdev->hci_drv->common_handler_count)
handler = &hdev->hci_drv->common_handlers[ocf];
Additionally, add a check that ogf == 0 before entering the common handler path, to reject commands with unexpected OGF values early.
References
- Vulnerable file:
net/bluetooth/hci_drv.c, lines 87–89 - Driver-specific path (correct reference):
net/bluetooth/hci_drv.c, lines 91–92 - Entry point from userspace:
net/bluetooth/hci_sock.c, lines 1863–1879 - Dispatch to vulnerable function:
net/bluetooth/hci_core.c, lines 3064–3070