git: 15198bfd7437 - main - virtio: Validate host-supplied used lengths

From: Faraz Vahedi <kfv_at_FreeBSD.org>
Date: Sat, 03 Oct 2026 12:41:59 UTC
The branch main has been updated by kfv:

URL: https://cgit.FreeBSD.org/src/commit/?id=15198bfd7437a616e66342be3c672da0b523e710

commit 15198bfd7437a616e66342be3c672da0b523e710
Author:     Faraz Vahedi <kfv@FreeBSD.org>
AuthorDate: 2026-10-03 12:39:36 +0000
Commit:     Faraz Vahedi <kfv@FreeBSD.org>
CommitDate: 2026-10-03 12:39:36 +0000

    virtio: Validate host-supplied used lengths
    
    virtio_console used the host-supplied used lengths without
    validation, so a host could report a length larger than
    the buffer, causing the receive and control paths to read
    past the end of it.  Clamp to the buffer size.
    
    vtnet already rejected used lengths larger than the buffer,
    but performed the check after converting the length to an
    int, so a length larger than INT_MAX would become negative
    and bypass the check.  Reject such frames early before the
    conversion, and count them in ierrors and rx_frame_too_large.
    
    Reviewed by:    markj
    Approved by:    fuz (mentor)
    Differential Revision:  https://reviews.freebsd.org/D60092
---
 sys/dev/virtio/console/virtio_console.c | 2 ++
 sys/dev/virtio/network/if_vtnet.c       | 5 ++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/sys/dev/virtio/console/virtio_console.c b/sys/dev/virtio/console/virtio_console.c
index 81ffd7058f06..7dc6b531ea0e 100644
--- a/sys/dev/virtio/console/virtio_console.c
+++ b/sys/dev/virtio/console/virtio_console.c
@@ -922,6 +922,7 @@ vtcon_ctrl_task_cb(void *xsc, int pending)
 		if (control == NULL)
 			break;
 
+		len = min(len, VTCON_CTRL_BUFSZ);
 		if (len > sizeof(struct virtio_console_control)) {
 			data = (void *) &control[1];
 			data_len = len - sizeof(struct virtio_console_control);
@@ -1320,6 +1321,7 @@ again:
 	deq = 0;
 
 	while ((buf = virtqueue_dequeue(vq, &len)) != NULL) {
+		len = min(len, VTCON_BULK_BUFSZ);
 		for (i = 0; i < len; i++) {
 #if defined(KDB)
 			if (port->vtcport_flags & VTCON_PORT_FLAG_CONSOLE)
diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c
index 15dd50e7df77..f85b02fe18aa 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -2190,7 +2190,10 @@ vtnet_rxq_eof(struct vtnet_rxq *rxq)
 			mp = mp->m_next;
 		}
 
-		if (len < sc->vtnet_hdr_size + ETHER_HDR_LEN) {
+		if (synced < len ||
+		    len < sc->vtnet_hdr_size + ETHER_HDR_LEN) {
+			if (synced < len)
+				sc->vtnet_stats.rx_frame_too_large++;
 			rxq->vtnrx_stats.vrxs_ierrors++;
 			vtnet_rxq_discard_buf(rxq, m);
 			continue;