* [PATCH 1/2] Bluetooth: validate retained LE Create CIS command length
2026-11-02 11:58 [PATCH 0/2] Bluetooth: validate retained LE ISO command lengths Yifan Zhang
@ 2026-11-02 11:58 ` Yifan Zhang
2026-11-02 11:58 ` [PATCH 2/2] Bluetooth: validate retained LE Set CIG Parameters " Yifan Zhang
2026-11-02 22:20 ` [PATCH 0/2] Bluetooth: validate retained LE ISO command lengths patchwork-bot+bluetooth
2 siblings, 0 replies; 4+ messages in thread
From: Yifan Zhang @ 2026-11-02 11:58 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, linux-bluetooth
Cc: Pauli Virtanen, linux-kernel
hci_cs_le_create_cis() retrieves the parameters of the previously sent
command without their length. It then trusts num_cis and walks the
flexible cis[] array when a controller reports a failed command.
A five-byte HCI command containing only num_cis can therefore make the
handler read beyond the command skb. KASAN reports:
BUG: KASAN: slab-out-of-bounds in hci_cs_le_create_cis
Read of size 2
hci_cs_le_create_cis
hci_cmd_status_evt
hci_event_packet
Add a length-returning saved-command helper and require the fixed header
and complete CIS array before walking it.
The reproducer no longer triggers a KASAN report with this change.
Fixes: 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections")
Closes: https://lore.kernel.org/linux-bluetooth/179317462624.87574.6271582002629080499@stu.pku.edu.cn/
Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn>
---
include/net/bluetooth/hci_core.h | 2 ++
net/bluetooth/hci_core.c | 18 ++++++++++++++----
net/bluetooth/hci_event.c | 7 ++++++-
3 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index aa04dec451534..dfeae27250ea9 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -2426,6 +2426,8 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb);
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
+void *hci_sent_cmd_data_len(struct hci_dev *hdev, __u16 opcode,
+ size_t *len);
void *hci_recv_event_data(struct hci_dev *hdev, __u8 event);
u32 hci_conn_get_phy(struct hci_conn *conn);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 209244fd93918..25ab26dab5cca 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3159,7 +3159,8 @@ int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
EXPORT_SYMBOL(__hci_cmd_send);
/* Get data from the previously sent command */
-static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode)
+static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode,
+ size_t *len)
{
struct hci_command_hdr *hdr;
@@ -3171,23 +3172,32 @@ static void *hci_cmd_data(struct sk_buff *skb, __u16 opcode)
if (hdr->opcode != cpu_to_le16(opcode))
return NULL;
+ if (len)
+ *len = skb->len - HCI_COMMAND_HDR_SIZE;
+
return skb->data + HCI_COMMAND_HDR_SIZE;
}
/* Get data from the previously sent command */
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
+void *hci_sent_cmd_data_len(struct hci_dev *hdev, __u16 opcode, size_t *len)
{
void *data;
/* Check if opcode matches last sent command */
- data = hci_cmd_data(hdev->sent_cmd, opcode);
+ data = hci_cmd_data(hdev->sent_cmd, opcode, len);
if (!data)
/* Check if opcode matches last request */
- data = hci_cmd_data(hdev->req_skb, opcode);
+ data = hci_cmd_data(hdev->req_skb, opcode, len);
return data;
}
+/* Get data from the previously sent command */
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
+{
+ return hci_sent_cmd_data_len(hdev, opcode, NULL);
+}
+
/* Get data from last received event */
void *hci_recv_event_data(struct hci_dev *hdev, __u8 event)
{
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1f80f2cf6b2c8..8dc632329aeb5 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4481,6 +4481,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
{
struct hci_cp_le_create_cis *cp;
bool pending = false;
+ size_t len;
int i;
bt_dev_dbg(hdev, "status 0x%2.2x", status);
@@ -4488,10 +4489,14 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
if (!status)
return;
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CIS);
+ cp = hci_sent_cmd_data_len(hdev, HCI_OP_LE_CREATE_CIS, &len);
if (!cp)
return;
+ if (len < sizeof(*cp) ||
+ len < struct_size(cp, cis, cp->num_cis))
+ return;
+
hci_dev_lock(hdev);
/* Remove connection if command failed */
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 2/2] Bluetooth: validate retained LE Set CIG Parameters command length
2026-11-02 11:58 [PATCH 0/2] Bluetooth: validate retained LE ISO command lengths Yifan Zhang
2026-11-02 11:58 ` [PATCH 1/2] Bluetooth: validate retained LE Create CIS command length Yifan Zhang
@ 2026-11-02 11:58 ` Yifan Zhang
2026-11-02 22:20 ` [PATCH 0/2] Bluetooth: validate retained LE ISO command lengths patchwork-bot+bluetooth
2 siblings, 0 replies; 4+ messages in thread
From: Yifan Zhang @ 2026-11-02 11:58 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, linux-bluetooth
Cc: Pauli Virtanen, linux-kernel
hci_cc_le_set_cig_params() validates the controller response but not the
parameters of the previously sent command. A short command can claim a
large num_cis without containing the corresponding cis[] array. A
complete successful response then makes the handler read beyond the
command skb while looking up each CIS ID.
KASAN reports:
BUG: KASAN: slab-out-of-bounds in hci_cc_le_set_cig_params
Read of size 1
hci_cc_le_set_cig_params
hci_cmd_complete_evt
hci_event_packet
Obtain the retained parameter length and require both the fixed header and
the complete CIS array before using the command data.
The reproducer no longer triggers a KASAN report with this change.
Fixes: 71e9588435c3 ("Bluetooth: ISO: use correct CIS order in Set CIG Parameters event")
Closes: https://lore.kernel.org/linux-bluetooth/179317463153.87610.8996555110609321376@stu.pku.edu.cn/
Signed-off-by: Yifan Zhang <yfzhang23@stu.pku.edu.cn>
---
net/bluetooth/hci_event.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 8dc632329aeb5..62229d3b0b33f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3975,13 +3975,16 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
struct hci_conn *conn;
u8 status = rp->status;
bool pending = false;
+ size_t len;
int i;
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
- cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS);
+ cp = hci_sent_cmd_data_len(hdev, HCI_OP_LE_SET_CIG_PARAMS, &len);
if (!rp->status &&
- (!cp || rp->num_handles != cp->num_cis ||
+ (!cp || len < sizeof(*cp) ||
+ len < struct_size(cp, cis, cp->num_cis) ||
+ rp->num_handles != cp->num_cis ||
rp->cig_id != cp->cig_id ||
skb->len < array_size(rp->num_handles, sizeof(*rp->handle)))) {
bt_dev_err(hdev, "unexpected Set CIG Parameters response data");
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 4+ messages in thread