Skip to content

Commit 4bcb0c7

Browse files
rickywu0421Vudentz
authored andcommitted
Bluetooth: btusb: use skb_pull to avoid unsafe access in QCA dump handling
Use skb_pull() and skb_pull_data() to safely parse QCA dump packets. This avoids direct pointer math on skb->data, which could lead to invalid access if the packet is shorter than expected. Fixes: 20981ce ("Bluetooth: btusb: Add WCN6855 devcoredump support") Signed-off-by: En-Wei Wu <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 7af8479 commit 4bcb0c7

File tree

1 file changed

+40
-58
lines changed

1 file changed

+40
-58
lines changed

drivers/bluetooth/btusb.c

Lines changed: 40 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3014,9 +3014,8 @@ static void btusb_coredump_qca(struct hci_dev *hdev)
30143014
static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30153015
{
30163016
int ret = 0;
3017+
unsigned int skip = 0;
30173018
u8 pkt_type;
3018-
u8 *sk_ptr;
3019-
unsigned int sk_len;
30203019
u16 seqno;
30213020
u32 dump_size;
30223021

@@ -3025,18 +3024,13 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30253024
struct usb_device *udev = btdata->udev;
30263025

30273026
pkt_type = hci_skb_pkt_type(skb);
3028-
sk_ptr = skb->data;
3029-
sk_len = skb->len;
3027+
skip = sizeof(struct hci_event_hdr);
3028+
if (pkt_type == HCI_ACLDATA_PKT)
3029+
skip += sizeof(struct hci_acl_hdr);
30303030

3031-
if (pkt_type == HCI_ACLDATA_PKT) {
3032-
sk_ptr += HCI_ACL_HDR_SIZE;
3033-
sk_len -= HCI_ACL_HDR_SIZE;
3034-
}
3035-
3036-
sk_ptr += HCI_EVENT_HDR_SIZE;
3037-
sk_len -= HCI_EVENT_HDR_SIZE;
3031+
skb_pull(skb, skip);
3032+
dump_hdr = (struct qca_dump_hdr *)skb->data;
30383033

3039-
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
30403034
seqno = le16_to_cpu(dump_hdr->seqno);
30413035
if (seqno == 0) {
30423036
set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
@@ -3056,16 +3050,15 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30563050

30573051
btdata->qca_dump.ram_dump_size = dump_size;
30583052
btdata->qca_dump.ram_dump_seqno = 0;
3059-
sk_ptr += offsetof(struct qca_dump_hdr, data0);
3060-
sk_len -= offsetof(struct qca_dump_hdr, data0);
3053+
3054+
skb_pull(skb, offsetof(struct qca_dump_hdr, data0));
30613055

30623056
usb_disable_autosuspend(udev);
30633057
bt_dev_info(hdev, "%s memdump size(%u)\n",
30643058
(pkt_type == HCI_ACLDATA_PKT) ? "ACL" : "event",
30653059
dump_size);
30663060
} else {
3067-
sk_ptr += offsetof(struct qca_dump_hdr, data);
3068-
sk_len -= offsetof(struct qca_dump_hdr, data);
3061+
skb_pull(skb, offsetof(struct qca_dump_hdr, data));
30693062
}
30703063

30713064
if (!btdata->qca_dump.ram_dump_size) {
@@ -3085,7 +3078,6 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30853078
return ret;
30863079
}
30873080

3088-
skb_pull(skb, skb->len - sk_len);
30893081
hci_devcd_append(hdev, skb);
30903082
btdata->qca_dump.ram_dump_seqno++;
30913083
if (seqno == QCA_LAST_SEQUENCE_NUM) {
@@ -3113,68 +3105,58 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
31133105
/* Return: true if the ACL packet is a dump packet, false otherwise. */
31143106
static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
31153107
{
3116-
u8 *sk_ptr;
3117-
unsigned int sk_len;
3118-
31193108
struct hci_event_hdr *event_hdr;
31203109
struct hci_acl_hdr *acl_hdr;
31213110
struct qca_dump_hdr *dump_hdr;
3111+
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
3112+
bool is_dump = false;
31223113

3123-
sk_ptr = skb->data;
3124-
sk_len = skb->len;
3125-
3126-
acl_hdr = hci_acl_hdr(skb);
3127-
if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
3114+
if (!clone)
31283115
return false;
31293116

3130-
sk_ptr += HCI_ACL_HDR_SIZE;
3131-
sk_len -= HCI_ACL_HDR_SIZE;
3132-
event_hdr = (struct hci_event_hdr *)sk_ptr;
3133-
3134-
if ((event_hdr->evt != HCI_VENDOR_PKT) ||
3135-
(event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
3136-
return false;
3117+
acl_hdr = skb_pull_data(clone, sizeof(*acl_hdr));
3118+
if (!acl_hdr || (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE))
3119+
goto out;
31373120

3138-
sk_ptr += HCI_EVENT_HDR_SIZE;
3139-
sk_len -= HCI_EVENT_HDR_SIZE;
3121+
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
3122+
if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
3123+
goto out;
31403124

3141-
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
3142-
if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
3143-
(dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
3144-
(dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3145-
return false;
3125+
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
3126+
if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
3127+
(dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3128+
goto out;
31463129

3147-
return true;
3130+
is_dump = true;
3131+
out:
3132+
consume_skb(clone);
3133+
return is_dump;
31483134
}
31493135

31503136
/* Return: true if the event packet is a dump packet, false otherwise. */
31513137
static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
31523138
{
3153-
u8 *sk_ptr;
3154-
unsigned int sk_len;
3155-
31563139
struct hci_event_hdr *event_hdr;
31573140
struct qca_dump_hdr *dump_hdr;
3141+
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
3142+
bool is_dump = false;
31583143

3159-
sk_ptr = skb->data;
3160-
sk_len = skb->len;
3161-
3162-
event_hdr = hci_event_hdr(skb);
3163-
3164-
if ((event_hdr->evt != HCI_VENDOR_PKT)
3165-
|| (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
3144+
if (!clone)
31663145
return false;
31673146

3168-
sk_ptr += HCI_EVENT_HDR_SIZE;
3169-
sk_len -= HCI_EVENT_HDR_SIZE;
3147+
event_hdr = skb_pull_data(clone, sizeof(*event_hdr));
3148+
if (!event_hdr || (event_hdr->evt != HCI_VENDOR_PKT))
3149+
goto out;
31703150

3171-
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
3172-
if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
3173-
(dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
3174-
(dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3175-
return false;
3151+
dump_hdr = skb_pull_data(clone, sizeof(*dump_hdr));
3152+
if (!dump_hdr || (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
3153+
(dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3154+
goto out;
31763155

3177-
return true;
3156+
is_dump = true;
3157+
out:
3158+
consume_skb(clone);
3159+
return is_dump;
31783160
}
31793161

31803162
static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb)

0 commit comments

Comments
 (0)