[PATCH v4 2/3] Bluetooth: btmtk: bound the ISO payload length by the controller's MTU

From: Chris Lu

Date: Wed Oct 21 2026 - 23:27:21 EST


btmtk_recv_isopkt() bounds the Data_Total_Length reported by the
controller with skb_tailroom(skb) < hci_skb_expect(skb). That keeps the
reassembly inside the skb, but it enforces no protocol limit: the head
allocation is rounded up to the next kmalloc bucket and skb_tailroom()
reports what the bucket can hold rather than what was requested, which is
several hundred bytes more. An oversized length therefore passes, and the
parser keeps pulling bytes out of the following transfers to fill it,
swallowing the real ISO packets they carry until the frame is handed to
hci_recv_frame().

The controller reports the largest ISO_Data_Packet_Length it will send in
LE Read Buffer Size [v2], which hci_cc_le_read_buffer_size_v2() keeps in
hdev->iso_mtu. Once that is available, bound the length by it and size the
receive skb to hold that much plus the 4-byte header. HCI_MAX_ISO_SIZE is
kept only as a fallback for the window before the command completes.

Keep the skb_tailroom() test as well, because a fragment started before
hdev->iso_mtu was populated sits in an skb sized for the fallback.

Fixes: ceac1cb0259d ("Bluetooth: btusb: mediatek: add ISO data transmission functions")
Co-developed-by: Hao Qin <hao.qin@xxxxxxxxxxxx>
Signed-off-by: Hao Qin <hao.qin@xxxxxxxxxxxx>
Co-developed-by: Wenlong Tian <ot_wenlong.tian@xxxxxxxxxxxx>
Signed-off-by: Wenlong Tian <ot_wenlong.tian@xxxxxxxxxxxx>
Signed-off-by: Chris Lu <chris.lu@xxxxxxxxxxxx>
---
drivers/bluetooth/btmtk.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 01d5ad2479f4..f2224eb0bf6b 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -1557,8 +1557,15 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
struct btmtk_data *btmtk_data = hci_get_priv(hdev);
struct sk_buff *skb;
unsigned long flags;
+ unsigned int iso_mtu;
int err = 0;

+ /* The controller reports the largest Data_Total_Length it will send in
+ * LE Read Buffer Size [v2]. Fall back to HCI_MAX_ISO_SIZE while that
+ * command has not completed yet.
+ */
+ iso_mtu = hdev->iso_mtu ? hdev->iso_mtu : HCI_MAX_ISO_SIZE;
+
spin_lock_irqsave(&btmtk_data->isorxlock, flags);
skb = btmtk_data->isopkt_skb;

@@ -1574,7 +1581,8 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
if (mem_is_zero(buffer, count))
break;

- skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC);
+ skb = bt_skb_alloc(HCI_ISO_HDR_SIZE + iso_mtu,
+ GFP_ATOMIC);
if (!skb) {
err = -ENOMEM;
break;
@@ -1608,7 +1616,13 @@ static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
break;
}

- if (skb_tailroom(skb) < hci_skb_expect(skb)) {
+ /* Reject a length the controller said it would never
+ * send. The skb_tailroom() test is kept because a
+ * fragment started before hdev->iso_mtu was populated
+ * sits in a smaller skb than iso_mtu now allows.
+ */
+ if (hci_skb_expect(skb) > iso_mtu ||
+ skb_tailroom(skb) < hci_skb_expect(skb)) {
kfree_skb(skb);
skb = NULL;

--
2.45.2