mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Bluetooth: validate retained LE Create CIS command length
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: 26afbd826e ("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>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
a7c5c18b7c
commit
1eb52f35fc
|
|
@ -2428,6 +2428,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);
|
||||
|
|
|
|||
|
|
@ -3175,7 +3175,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;
|
||||
|
||||
|
|
@ -3187,21 +3188,30 @@ 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_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, len);
|
||||
if (!data)
|
||||
/* Check if opcode matches last request */
|
||||
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)
|
||||
{
|
||||
void *data;
|
||||
|
||||
/* Check if opcode matches last sent command */
|
||||
data = hci_cmd_data(hdev->sent_cmd, opcode);
|
||||
if (!data)
|
||||
/* Check if opcode matches last request */
|
||||
data = hci_cmd_data(hdev->req_skb, opcode);
|
||||
|
||||
return data;
|
||||
return hci_sent_cmd_data_len(hdev, opcode, NULL);
|
||||
}
|
||||
|
||||
/* Get data from last received event */
|
||||
|
|
|
|||
|
|
@ -4491,6 +4491,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);
|
||||
|
|
@ -4498,10 +4499,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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user