[PATCH 1/5] Bluetooth: bfusb: validate received block boundaries
From: Li Qiang
Date: Thu Jul 16 2026 - 04:51:13 EST
The USB receive path trusts the block header to contain the required
number of bytes and passes it to the reassembly routine. The routine
also trusts a malformed HCI packet type and can append more data than
the skb allocated from the advertised packet length. A malformed USB
transfer can therefore cause out-of-bounds reads or an skb tail
overwrite.
Validate block header availability, declared block size, packet type,
and reassembly tailroom. Drop the partial frame on an invalid block.
Signed-off-by: Li Qiang <liqiang01@xxxxxxxxxx>
---
drivers/bluetooth/bfusb.c | 37 ++++++++++++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 8df310983bf6..d31d797639b5 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -301,6 +301,11 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
return -EILSEQ;
}
break;
+
+ default:
+ bt_dev_err(data->hdev, "unknown packet type 0x%02x",
+ pkt_type);
+ return -EILSEQ;
}
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
@@ -319,6 +324,13 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
}
}
+ if (len > skb_tailroom(data->reassembly)) {
+ bt_dev_err(data->hdev, "block exceeds packet length");
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
+ return -EILSEQ;
+ }
+
if (len > 0)
skb_put_data(data->reassembly, buf, len);
@@ -353,6 +365,13 @@ static void bfusb_rx_complete(struct urb *urb)
skb_put(skb, count);
while (count) {
+ if (count < 2) {
+ bt_dev_err(data->hdev, "short block header");
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
+ break;
+ }
+
hdr = buf[0] | (buf[1] << 8);
if (hdr & 0x4000) {
@@ -360,16 +379,28 @@ static void bfusb_rx_complete(struct urb *urb)
count -= 2;
buf += 2;
} else {
+ if (count < 3) {
+ bt_dev_err(data->hdev, "short block header");
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
+ break;
+ }
+
len = (buf[2] == 0) ? 256 : buf[2];
count -= 3;
buf += 3;
}
- if (count < len)
+ if (count < len) {
bt_dev_err(data->hdev, "block extends over URB buffer ranges");
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
+ break;
+ }
- if ((hdr & 0xe1) == 0xc1)
- bfusb_recv_block(data, hdr, buf, len);
+ if ((hdr & 0xe1) == 0xc1 &&
+ bfusb_recv_block(data, hdr, buf, len) < 0)
+ data->hdev->stat.err_rx++;
count -= len;
buf += len;
--
2.43.0