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. Index k < N is within bounds. Correct.
  • For OGF=2, OCF=0: opcode = 0x0800 = 2048. If N ≤ 2048, the check fails safely.
  • But if an author sets common_handler_count = 1024 (a natural “max OCF” value) while allocating common_handlers[5] (only 5 real entries), an attacker sending OGF=0, OCF=5..1023 passes the check and reads common_handlers[5] through common_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

  1. Attacker opens an AF_BLUETOOTH / BTPROTO_HCI socket and binds to HCI_CHANNEL_USER (requires CAP_NET_ADMIN — achievable via a user namespace if unprivileged user namespaces are enabled).
  2. Attacker sends an HCI_DRV_PKT with:
    • opcode crafted so that opcode >= ARRAY_SIZE(common_handlers) but opcode < common_handler_count (requires a driver with an oversized common_handler_count).
    • len matching handler->data_len read from OOB memory so the data_len check passes.
  3. The code calls handler->func(hdev, skb->data, len) where func is a pointer read from out-of-bounds kernel heap memory.
  4. If the attacker controls the heap layout (e.g., heap spray), they can place a crafted hci_drv_handler struct adjacent to the common_handlers array, directing execution to arbitrary kernel code.

Impact

Severity: Critical (kernel arbitrary code execution)

  • Out-of-bounds read: Reading hci_drv_handler entries beyond the allocated common_handlers array leaks kernel heap pointers, bypassing KASLR.
  • Arbitrary function call: The handler->func pointer 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