Skip to content

Commit b70b415

Browse files
rickywu0421gregkh
authored andcommitted
Bluetooth: btusb: avoid NULL pointer dereference in skb_dequeue()
[ Upstream commit 0317b03 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent c7bd5c9 commit b70b415

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
@@ -2975,22 +2975,16 @@ static void btusb_coredump_qca(struct hci_dev *hdev)
29752975
bt_dev_err(hdev, "%s: triggle crash failed (%d)", __func__, err);
29762976
}
29772977

2978-
/*
2979-
* ==0: not a dump pkt.
2980-
* < 0: fails to handle a dump pkt
2981-
* > 0: otherwise.
2982-
*/
2978+
/* Return: 0 on success, negative errno on failure. */
29832979
static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
29842980
{
2985-
int ret = 1;
2981+
int ret = 0;
29862982
u8 pkt_type;
29872983
u8 *sk_ptr;
29882984
unsigned int sk_len;
29892985
u16 seqno;
29902986
u32 dump_size;
29912987

2992-
struct hci_event_hdr *event_hdr;
2993-
struct hci_acl_hdr *acl_hdr;
29942988
struct qca_dump_hdr *dump_hdr;
29952989
struct btusb_data *btdata = hci_get_drvdata(hdev);
29962990
struct usb_device *udev = btdata->udev;
@@ -3000,30 +2994,14 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30002994
sk_len = skb->len;
30012995

30022996
if (pkt_type == HCI_ACLDATA_PKT) {
3003-
acl_hdr = hci_acl_hdr(skb);
3004-
if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
3005-
return 0;
30062997
sk_ptr += HCI_ACL_HDR_SIZE;
30072998
sk_len -= HCI_ACL_HDR_SIZE;
3008-
event_hdr = (struct hci_event_hdr *)sk_ptr;
3009-
} else {
3010-
event_hdr = hci_event_hdr(skb);
30112999
}
30123000

3013-
if ((event_hdr->evt != HCI_VENDOR_PKT)
3014-
|| (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
3015-
return 0;
3016-
30173001
sk_ptr += HCI_EVENT_HDR_SIZE;
30183002
sk_len -= HCI_EVENT_HDR_SIZE;
30193003

30203004
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
3021-
if ((sk_len < offsetof(struct qca_dump_hdr, data))
3022-
|| (dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS)
3023-
|| (dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3024-
return 0;
3025-
3026-
/*it is dump pkt now*/
30273005
seqno = le16_to_cpu(dump_hdr->seqno);
30283006
if (seqno == 0) {
30293007
set_bit(BTUSB_HW_SSR_ACTIVE, &btdata->flags);
@@ -3097,17 +3075,84 @@ static int handle_dump_pkt_qca(struct hci_dev *hdev, struct sk_buff *skb)
30973075
return ret;
30983076
}
30993077

3078+
/* Return: true if the ACL packet is a dump packet, false otherwise. */
3079+
static bool acl_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
3080+
{
3081+
u8 *sk_ptr;
3082+
unsigned int sk_len;
3083+
3084+
struct hci_event_hdr *event_hdr;
3085+
struct hci_acl_hdr *acl_hdr;
3086+
struct qca_dump_hdr *dump_hdr;
3087+
3088+
sk_ptr = skb->data;
3089+
sk_len = skb->len;
3090+
3091+
acl_hdr = hci_acl_hdr(skb);
3092+
if (le16_to_cpu(acl_hdr->handle) != QCA_MEMDUMP_ACL_HANDLE)
3093+
return false;
3094+
3095+
sk_ptr += HCI_ACL_HDR_SIZE;
3096+
sk_len -= HCI_ACL_HDR_SIZE;
3097+
event_hdr = (struct hci_event_hdr *)sk_ptr;
3098+
3099+
if ((event_hdr->evt != HCI_VENDOR_PKT) ||
3100+
(event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
3101+
return false;
3102+
3103+
sk_ptr += HCI_EVENT_HDR_SIZE;
3104+
sk_len -= HCI_EVENT_HDR_SIZE;
3105+
3106+
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
3107+
if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
3108+
(dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
3109+
(dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3110+
return false;
3111+
3112+
return true;
3113+
}
3114+
3115+
/* Return: true if the event packet is a dump packet, false otherwise. */
3116+
static bool evt_pkt_is_dump_qca(struct hci_dev *hdev, struct sk_buff *skb)
3117+
{
3118+
u8 *sk_ptr;
3119+
unsigned int sk_len;
3120+
3121+
struct hci_event_hdr *event_hdr;
3122+
struct qca_dump_hdr *dump_hdr;
3123+
3124+
sk_ptr = skb->data;
3125+
sk_len = skb->len;
3126+
3127+
event_hdr = hci_event_hdr(skb);
3128+
3129+
if ((event_hdr->evt != HCI_VENDOR_PKT)
3130+
|| (event_hdr->plen != (sk_len - HCI_EVENT_HDR_SIZE)))
3131+
return false;
3132+
3133+
sk_ptr += HCI_EVENT_HDR_SIZE;
3134+
sk_len -= HCI_EVENT_HDR_SIZE;
3135+
3136+
dump_hdr = (struct qca_dump_hdr *)sk_ptr;
3137+
if ((sk_len < offsetof(struct qca_dump_hdr, data)) ||
3138+
(dump_hdr->vse_class != QCA_MEMDUMP_VSE_CLASS) ||
3139+
(dump_hdr->msg_type != QCA_MEMDUMP_MSG_TYPE))
3140+
return false;
3141+
3142+
return true;
3143+
}
3144+
31003145
static int btusb_recv_acl_qca(struct hci_dev *hdev, struct sk_buff *skb)
31013146
{
3102-
if (handle_dump_pkt_qca(hdev, skb))
3103-
return 0;
3147+
if (acl_pkt_is_dump_qca(hdev, skb))
3148+
return handle_dump_pkt_qca(hdev, skb);
31043149
return hci_recv_frame(hdev, skb);
31053150
}
31063151

31073152
static int btusb_recv_evt_qca(struct hci_dev *hdev, struct sk_buff *skb)
31083153
{
3109-
if (handle_dump_pkt_qca(hdev, skb))
3110-
return 0;
3154+
if (evt_pkt_is_dump_qca(hdev, skb))
3155+
return handle_dump_pkt_qca(hdev, skb);
31113156
return hci_recv_frame(hdev, skb);
31123157
}
31133158

0 commit comments

Comments
 (0)