Skip to content

Commit 0317b03

Browse files
rickywu0421Vudentz
authored andcommitted
Bluetooth: btusb: avoid NULL pointer dereference in skb_dequeue()
A NULL pointer dereference can occur in skb_dequeue() when processing a QCA firmware crash dump on WCN7851 (0489:e0f3). [ 93.672166] Bluetooth: hci0: ACL memdump size(589824) [ 93.672475] BUG: kernel NULL pointer dereference, address: 0000000000000008 [ 93.672517] Workqueue: hci0 hci_devcd_rx [bluetooth] [ 93.672598] RIP: 0010:skb_dequeue+0x50/0x80 The issue stems from handle_dump_pkt_qca() returning 0 even when a dump packet is successfully processed. This is because it incorrectly forwards the return value of hci_devcd_init() (which returns 0 on success). As a result, the caller (btusb_recv_acl_qca() or btusb_recv_evt_qca()) assumes the packet was not handled and passes it to hci_recv_frame(), leading to premature kfree() of the skb. Later, hci_devcd_rx() attempts to dequeue the same skb from the dump queue, resulting in a NULL pointer dereference. Fix this by: 1. Making handle_dump_pkt_qca() return 0 on success and negative errno on failure, consistent with kernel conventions. 2. Splitting dump packet detection into separate functions for ACL and event packets for better structure and readability. This ensures dump packets are properly identified and consumed, avoiding double handling and preventing NULL pointer access. Fixes: 20981ce ("Bluetooth: btusb: Add WCN6855 devcoredump support") Signed-off-by: En-Wei Wu <en-wei.wu@canonical.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
1 parent d1af1f0 commit 0317b03

File tree

1 file changed

+73
-28
lines changed

1 file changed

+73
-28
lines changed

drivers/bluetooth/btusb.c

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3010,22 +3010,16 @@ static void btusb_coredump_qca(struct hci_dev *hdev)
30103010
bt_dev_err(hdev, "%s: triggle crash failed (%d)", __func__, err);
30113011
}
30123012

3013-
/*
3014-
* ==0: not a dump pkt.
3015-
* < 0: fails to handle a dump pkt
3016-
* > 0: otherwise.
3017-
*/
3013+
/* Return: 0 on success, negative errno on failure. */
30183014
static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30193015
{
3020-
int ret = 1;
3016+
int ret = 0;
30213017
u8 pkt_type;
30223018
u8 *sk_ptr;
30233019
unsigned int sk_len;
30243020
u16 seqno;
30253021
u32 dump_size;
30263022

3027-
struct hci_event_hdr *event_hdr;
3028-
struct hci_acl_hdr *acl_hdr;
30293023
struct qca_dump_hdr *dump_hdr;
30303024
struct btusb_data *btdata = hci_get_drvdata(hdev);
30313025
struct usb_device *udev = btdata->udev;
@@ -3035,30 +3029,14 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30353029
sk_len = skb->len;
30363030

30373031
if (pkt_type == HCI_ACLDATA_PKT) {
3038-
acl_hdr = hci_acl_hdr(skb);
3039-
if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
3040-
return 0;
30413032
sk_ptr += HCI_ACL_HDR_SIZE;
30423033
sk_len -= HCI_ACL_HDR_SIZE;
3043-
event_hdr = (struct hci_event_hdr *)sk_ptr;
3044-
} else {
3045-
event_hdr = hci_event_hdr(skb);
30463034
}
30473035

3048-
if ((event_hdr->evt != HCI_VENDOR_PKT)
3049-
|| (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
3050-
return 0;
3051-
30523036
sk_ptr += HCI_EVENT_HDR_SIZE;
30533037
sk_len -= HCI_EVENT_HDR_SIZE;
30543038

30553039
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
3056-
if ((sk_len < offsetof(struct qca_dump_hdr, data))
3057-
|| (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS)
3058-
|| (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3059-
return 0;
3060-
3061-
/*it is dump pkt now*/
30623040
seqno = le16_to_cpu(dump_hdr->seqno);
30633041
if (seqno == 0) {
30643042
set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
@@ -3132,17 +3110,84 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
31323110
return ret;
31333111
}
31343112

3113+
/* Return: true if the ACL packet is a dump packet, false otherwise. */
3114+
static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
3115+
{
3116+
u8 *sk_ptr;
3117+
unsigned int sk_len;
3118+
3119+
struct hci_event_hdr *event_hdr;
3120+
struct hci_acl_hdr *acl_hdr;
3121+
struct qca_dump_hdr *dump_hdr;
3122+
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)
3128+
return false;
3129+
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;
3137+
3138+
sk_ptr += HCI_EVENT_HDR_SIZE;
3139+
sk_len -= HCI_EVENT_HDR_SIZE;
3140+
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;
3146+
3147+
return true;
3148+
}
3149+
3150+
/* Return: true if the event packet is a dump packet, false otherwise. */
3151+
static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
3152+
{
3153+
u8 *sk_ptr;
3154+
unsigned int sk_len;
3155+
3156+
struct hci_event_hdr *event_hdr;
3157+
struct qca_dump_hdr *dump_hdr;
3158+
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)))
3166+
return false;
3167+
3168+
sk_ptr += HCI_EVENT_HDR_SIZE;
3169+
sk_len -= HCI_EVENT_HDR_SIZE;
3170+
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;
3176+
3177+
return true;
3178+
}
3179+
31353180
static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb)
31363181
{
3137-
if (handle_dump_pkt_qca(hdev, skb))
3138-
return 0;
3182+
if (acl_pkt_is_dump_qca(hdev, skb))
3183+
return handle_dump_pkt_qca(hdev, skb);
31393184
return hci_recv_frame(hdev, skb);
31403185
}
31413186

31423187
static int btusb_recv_evt_qca(struct hci_dev *hdev, struct sk_buff *skb)
31433188
{
3144-
if (handle_dump_pkt_qca(hdev, skb))
3145-
return 0;
3189+
if (evt_pkt_is_dump_qca(hdev, skb))
3190+
return handle_dump_pkt_qca(hdev, skb);
31463191
return hci_recv_frame(hdev, skb);
31473192
}
31483193

0 commit comments

Comments
 (0)