git: 93eafd4479da - stable/12 - bhyve e1000: Sanitize transmit ring indices.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 11 Nov 2022 01:24:34 UTC
The branch stable/12 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=93eafd4479da09eabbd447490a8661fb7616ba29

commit 93eafd4479da09eabbd447490a8661fb7616ba29
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-08-29 22:35:15 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-11-11 01:10:45 +0000

    bhyve e1000: Sanitize transmit ring indices.
    
    When preparing to transmit pending packets, ensure that the head (TDH)
    and tail (TDT) indices are in bounds.  Note that validating values
    when they are written is not sufficient along as the transmit length
    (TDLEN) could be changed turning a value that was valid when written
    into an out of bounds value.
    
    While here, add further restrictions to the head register (TDH).  The
    manual states that writing to this value while transmit is enabled can
    cause unexpected behavior and that it should only be written after a
    reset.  As such, ignore attempts to write while transmit is active,
    and also ignore writes of non-zero values.  Later e1000 chipsets have
    this register as read-only.
    
    Also ignore any attempts to transmit packets if the transmit ring's
    size is zero.
    
    PR:             264567
    Reported by:    Robert Morris <rtm@lcs.mit.edu>
    Reviewed by:    emaste
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D36269
    
    (cherry picked from commit 7afe342dcb38b624488009bb6bdfa5337e628ffc)
---
 usr.sbin/bhyve/pci_e82545.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/usr.sbin/bhyve/pci_e82545.c b/usr.sbin/bhyve/pci_e82545.c
index 0b46ea5dced7..0e73c779f574 100644
--- a/usr.sbin/bhyve/pci_e82545.c
+++ b/usr.sbin/bhyve/pci_e82545.c
@@ -1463,9 +1463,12 @@ e82545_tx_run(struct e82545_softc *sc)
 	uint16_t head, rhead, tail, size;
 	int lim, tdwb, sent;
 
-	head = sc->esc_TDH;
-	tail = sc->esc_TDT;
 	size = sc->esc_TDLEN / 16;
+	if (size == 0)
+		return;
+
+	head = sc->esc_TDH % size;
+	tail = sc->esc_TDT % size;
 	DPRINTF("tx_run: head %x, rhead %x, tail %x",
 	    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);
 
@@ -1731,12 +1734,17 @@ e82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)
 			e82545_tx_update_tdba(sc);
 		break;
 	case E1000_TDH(0):
-		//assert(!sc->esc_tx_enabled);
-		/* XXX should only ever be zero ? Range check ? */
+		if (sc->esc_tx_enabled) {
+			WPRINTF("ignoring write to TDH while transmit enabled");
+			break;
+		}
+		if (value != 0) {
+			WPRINTF("ignoring non-zero value written to TDH");
+			break;
+		}
 		sc->esc_TDHr = sc->esc_TDH = value;
 		break;
 	case E1000_TDT(0):
-		/* XXX range check ? */
 		sc->esc_TDT = value;
 		if (sc->esc_tx_enabled)
 			e82545_tx_start(sc);