mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Bluetooth: ISO: fix malformed ISO_END/CONT handling
Core specification (Part C vol 4 sec 5.4.5) does not exclude empty
ISO_CONT, ISO_END packets. We currently reject them if they are last.
If controller sends malformed sequence
ISO_START -> rx_len = 4, ISO_CONT skb->len 4, ISO_START
that ends payload in ISO_CONT, we leak conn->rx_skb. If controller sends
too long ISO_END, we panic on skb_put. If controller sends too short
ISO_END we accept it.
Fix by marking unfinished ISO_START via conn->rx_skb != NULL. Check
skb->len properly before skb_put. Combine the ISO_CONT/END code paths
as they require the same initial checks. Reject too short ISO_END
packets.
Fixes: 84c24fb151 ("Bluetooth: ISO: drop ISO_END frames received without prior ISO_START")
Fixes: ccf74f2390 ("Bluetooth: Add BTPROTO_ISO socket type")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
committed by
Luiz Augusto von Dentz
parent
9c36951474
commit
e054c1a6ae
@@ -2540,7 +2540,7 @@ int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb, u16 flags)
|
||||
switch (pb) {
|
||||
case ISO_START:
|
||||
case ISO_SINGLE:
|
||||
if (conn->rx_len) {
|
||||
if (conn->rx_skb || conn->rx_len) {
|
||||
BT_ERR("Unexpected start frame (len %d)", skb->len);
|
||||
kfree_skb(conn->rx_skb);
|
||||
conn->rx_skb = NULL;
|
||||
@@ -2621,12 +2621,14 @@ int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb, u16 flags)
|
||||
break;
|
||||
|
||||
case ISO_CONT:
|
||||
BT_DBG("Cont: frag len %d (expecting %d)", skb->len,
|
||||
case ISO_END:
|
||||
BT_DBG("%s: frag len %d (expecting %d)",
|
||||
(pb == ISO_END) ? "End" : "Cont", skb->len,
|
||||
conn->rx_len);
|
||||
|
||||
if (!conn->rx_len) {
|
||||
BT_ERR("Unexpected continuation frame (len %d)",
|
||||
skb->len);
|
||||
if (!conn->rx_skb) {
|
||||
BT_ERR("Unexpected ISO %s frame (len %d)",
|
||||
(pb == ISO_END) ? "End" : "Cont", skb->len);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
@@ -2642,17 +2644,9 @@ int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb, u16 flags)
|
||||
skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
|
||||
skb->len);
|
||||
conn->rx_len -= skb->len;
|
||||
break;
|
||||
|
||||
case ISO_END:
|
||||
if (!conn->rx_len) {
|
||||
BT_ERR("Unexpected end frame (len %d)", skb->len);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
|
||||
skb->len);
|
||||
conn->rx_len -= skb->len;
|
||||
if (pb == ISO_CONT)
|
||||
break;
|
||||
|
||||
if (!conn->rx_len) {
|
||||
struct sk_buff *rx_skb = conn->rx_skb;
|
||||
@@ -2663,6 +2657,13 @@ int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb, u16 flags)
|
||||
*/
|
||||
conn->rx_skb = NULL;
|
||||
iso_recv_frame(conn, rx_skb);
|
||||
} else {
|
||||
BT_ERR("ISO fragment incomplete (len %d, expected %d)",
|
||||
skb->len, conn->rx_len);
|
||||
kfree_skb(conn->rx_skb);
|
||||
conn->rx_skb = NULL;
|
||||
conn->rx_len = 0;
|
||||
goto drop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user