mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
Bluetooth: virtio_bt: validate rx pkt_type header length
virtbt_rx_handle() reads the leading pkt_type byte from the RX skb
and forwards the remainder to hci_recv_frame() for every
event/ACL/SCO/ISO type, without checking that the remaining payload
is at least the fixed HCI header for that type.
After the preceding patch bounds the backend-supplied used.len to
[1, VIRTBT_RX_BUF_SIZE], a one-byte completion still reaches
hci_recv_frame() with skb->len already pulled to 0. If the byte
happened to be HCI_ACLDATA_PKT, the ACL-vs-ISO classification
fast-path in hci_dev_classify_pkt_type() dereferences
hci_acl_hdr(skb)->handle whenever the HCI device has an active
CIS_LINK, BIS_LINK, or PA_LINK connection, reading two bytes of
uninitialized RX-buffer data. The same hazard exists for every
packet type the driver accepts because none of the switch cases in
virtbt_rx_handle() check skb->len against the per-type minimum HCI
header size before handing the frame to the core.
After stripping pkt_type, require skb->len to cover the fixed
header size for the selected type (event 2, ACL 4, SCO 3, ISO 4)
before calling hci_recv_frame(); drop ratelimited otherwise.
Unknown pkt_type values still take the original kfree_skb() default
path.
Use bt_dev_err_ratelimited() because both the length and pkt_type
values come from an untrusted backend that can otherwise flood the
kernel log.
Fixes: 160fbcf3bf ("Bluetooth: virtio_bt: Use skb_put to set length")
Cc: stable@vger.kernel.org
Cc: Soenke Huster <soenke.huster@eknoes.de>
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
21bd244b6d
commit
daf23014e5
|
|
@ -198,6 +198,7 @@ static int virtbt_shutdown_generic(struct hci_dev *hdev)
|
||||||
|
|
||||||
static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
|
static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
size_t min_hdr;
|
||||||
__u8 pkt_type;
|
__u8 pkt_type;
|
||||||
|
|
||||||
pkt_type = *((__u8 *) skb->data);
|
pkt_type = *((__u8 *) skb->data);
|
||||||
|
|
@ -205,16 +206,32 @@ static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
|
||||||
|
|
||||||
switch (pkt_type) {
|
switch (pkt_type) {
|
||||||
case HCI_EVENT_PKT:
|
case HCI_EVENT_PKT:
|
||||||
|
min_hdr = sizeof(struct hci_event_hdr);
|
||||||
|
break;
|
||||||
case HCI_ACLDATA_PKT:
|
case HCI_ACLDATA_PKT:
|
||||||
|
min_hdr = sizeof(struct hci_acl_hdr);
|
||||||
|
break;
|
||||||
case HCI_SCODATA_PKT:
|
case HCI_SCODATA_PKT:
|
||||||
|
min_hdr = sizeof(struct hci_sco_hdr);
|
||||||
|
break;
|
||||||
case HCI_ISODATA_PKT:
|
case HCI_ISODATA_PKT:
|
||||||
hci_skb_pkt_type(skb) = pkt_type;
|
min_hdr = sizeof(struct hci_iso_hdr);
|
||||||
hci_recv_frame(vbt->hdev, skb);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skb->len < min_hdr) {
|
||||||
|
bt_dev_err_ratelimited(vbt->hdev,
|
||||||
|
"rx pkt_type 0x%02x payload %u < hdr %zu\n",
|
||||||
|
pkt_type, skb->len, min_hdr);
|
||||||
|
kfree_skb(skb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hci_skb_pkt_type(skb) = pkt_type;
|
||||||
|
hci_recv_frame(vbt->hdev, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtbt_rx_work(struct work_struct *work)
|
static void virtbt_rx_work(struct work_struct *work)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user