mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 08:08:03 +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)
|
||||
{
|
||||
size_t min_hdr;
|
||||
__u8 pkt_type;
|
||||
|
||||
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) {
|
||||
case HCI_EVENT_PKT:
|
||||
min_hdr = sizeof(struct hci_event_hdr);
|
||||
break;
|
||||
case HCI_ACLDATA_PKT:
|
||||
min_hdr = sizeof(struct hci_acl_hdr);
|
||||
break;
|
||||
case HCI_SCODATA_PKT:
|
||||
min_hdr = sizeof(struct hci_sco_hdr);
|
||||
break;
|
||||
case HCI_ISODATA_PKT:
|
||||
hci_skb_pkt_type(skb) = pkt_type;
|
||||
hci_recv_frame(vbt->hdev, skb);
|
||||
min_hdr = sizeof(struct hci_iso_hdr);
|
||||
break;
|
||||
default:
|
||||
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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user