[PATCH] Bluetooth: validate retained LE Set Ext Adv Enable command length

From: Noah Weinberger

Date: Sun Nov 08 2026 - 17:30:30 EST


Hello,

hci_cc_le_set_ext_adv_enable() reads the retained LE Set Extended
Advertising Enable command with hci_sent_cmd_data() and dereferences
set->handle from cp->data whenever cp->num_of_sets != 0, without
checking the retained command's length - the same retained-command
class that was fixed this window for LE Set CIG Parameters
(ed4d302af7) and LE Create CIS (1eb52f35fc).

An injected short command via a raw HCI socket (CAP_NET_RAW) with a
matching Command Complete reads one byte past the retained skb; the
value only selects an advertising instance handle, so the impact is
state confusion rather than memory corruption. The sibling handlers
with the same shape and small fixed-field reads (pin code reply, read
clock, set privacy mode, set per adv params) may deserve the same
treatment.

The patch mirrors the hci_sent_cmd_data_len() + struct_size() pattern
of the two merged fixes.

Affected version/commit: mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07), net/bluetooth/hci_event.c:1669-1735 (hci_cc_le_set_ext_adv_enable).
Handler is longstanding; the fix class was established this window by ed4d302af7 (CIG params) and 1eb52f35fc (Create CIS).

This was found during an assisted (AI-supported) static source review of
mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07); every code path cited below was re-verified by the
reporter against that tree. The patch below has NOT been compiled and has
NOT been runtime tested, and no reproducer was produced - the triggering
conditions are described above instead. Please treat this as a report for
verification rather than a battle-tested fix.

Reported-by: Noah Weinberger <noahweinberger2003@xxxxxxxxx>
---
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index a525740..7206f3e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1673,14 +1673,17 @@ static u8 hci_cc_le_set_ext_adv_enable(struct hci_dev *hdev, void *data,
struct hci_cp_ext_adv_set *set;
struct adv_info *adv = NULL, *n;
struct hci_ev_status *rp = data;
+ size_t len;

bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);

if (rp->status)
return rp->status;

- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE);
- if (!cp)
+ cp = hci_sent_cmd_data_len(hdev, HCI_OP_LE_SET_EXT_ADV_ENABLE, &len);
+ if (!cp || len < sizeof(*cp) ||
+ (cp->num_of_sets &&
+ len < struct_size(cp, data, cp->num_of_sets)))
return rp->status;

set = (void *)cp->data;