Skip to content

Commit 3485c72

Browse files
mjbommargregkh
authored andcommitted
Bluetooth: virtio_bt: validate rx pkt_type header length
commit daf2301 upstream. 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: 160fbcf ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent b40cdd1 commit 3485c72

1 file changed

Lines changed: 20 additions & 3 deletions

File tree

drivers/bluetooth/virtio_bt.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,23 +198,40 @@ static int virtbt_shutdown_generic(struct hci_dev *hdev)
198198

199199
static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
200200
{
201+
size_t min_hdr;
201202
__u8 pkt_type;
202203

203204
pkt_type = *((__u8 *) skb->data);
204205
skb_pull(skb, 1);
205206

206207
switch (pkt_type) {
207208
case HCI_EVENT_PKT:
209+
min_hdr = sizeof(struct hci_event_hdr);
210+
break;
208211
case HCI_ACLDATA_PKT:
212+
min_hdr = sizeof(struct hci_acl_hdr);
213+
break;
209214
case HCI_SCODATA_PKT:
215+
min_hdr = sizeof(struct hci_sco_hdr);
216+
break;
210217
case HCI_ISODATA_PKT:
211-
hci_skb_pkt_type(skb) = pkt_type;
212-
hci_recv_frame(vbt->hdev, skb);
218+
min_hdr = sizeof(struct hci_iso_hdr);
213219
break;
214220
default:
215221
kfree_skb(skb);
216-
break;
222+
return;
217223
}
224+
225+
if (skb->len < min_hdr) {
226+
bt_dev_err_ratelimited(vbt->hdev,
227+
"rx pkt_type 0x%02x payload %u < hdr %zu\n",
228+
pkt_type, skb->len, min_hdr);
229+
kfree_skb(skb);
230+
return;
231+
}
232+
233+
hci_skb_pkt_type(skb) = pkt_type;
234+
hci_recv_frame(vbt->hdev, skb);
218235
}
219236

220237
static void virtbt_rx_work(struct work_struct *work)

0 commit comments

Comments
 (0)