git: d45b063c06d4 - main - gve: fix kernel panic on attach failure

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Wed, 07 Oct 2026 14:05:08 UTC
The branch main has been updated by markj:

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

commit d45b063c06d46d0f43489708e226821cddbad53b
Author:     Jasper Tran O'Leary <jtranoleary@google.com>
AuthorDate: 2026-10-07 13:29:28 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-10-07 13:29:40 +0000

    gve: fix kernel panic on attach failure
    
    When device initialization fails during attach (for instance, if device
    resource configuration or firmware negotiation fails), the driver aborts
    and unrolls partial state via its detach routine. However, the teardown
    path assumes transmit and receive queues have already been created. If
    attach aborts before queue allocation, tearing down the uninitialized
    queues triggers a NULL pointer dereference and panics the kernel during
    boot.
    
    Guard queue teardown against uninitialized queue state so that early
    attach failures unwind safely, allowing the driver to report the failure
    gracefully without crashing the operating system.
    
    Signed-off-by: Jasper Tran O'Leary <jtranoleary@google.com>
    
    Reviewed by:    adrian, markj
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D60385
---
 sys/dev/gve/gve_main.c | 16 ++++++++++------
 sys/dev/gve/gve_rx.c   |  3 +++
 sys/dev/gve/gve_tx.c   |  3 +++
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/sys/dev/gve/gve_main.c b/sys/dev/gve/gve_main.c
index 10197a8e15f8..fc88b3dfd014 100644
--- a/sys/dev/gve/gve_main.c
+++ b/sys/dev/gve/gve_main.c
@@ -694,13 +694,17 @@ gve_free_rings(struct gve_priv *priv)
 {
 	gve_free_irqs(priv);
 
-	gve_free_tx_rings(priv, 0, priv->tx_cfg.num_queues);
-	free(priv->tx, M_GVE);
-	priv->tx = NULL;
+	if (priv->tx != NULL) {
+		gve_free_tx_rings(priv, 0, priv->tx_cfg.num_queues);
+		free(priv->tx, M_GVE);
+		priv->tx = NULL;
+	}
 
-	gve_free_rx_rings(priv, 0, priv->rx_cfg.num_queues);
-	free(priv->rx, M_GVE);
-	priv->rx = NULL;
+	if (priv->rx != NULL) {
+		gve_free_rx_rings(priv, 0, priv->rx_cfg.num_queues);
+		free(priv->rx, M_GVE);
+		priv->rx = NULL;
+	}
 }
 
 static int
diff --git a/sys/dev/gve/gve_rx.c b/sys/dev/gve/gve_rx.c
index de64375ac4f3..8d3f1e2a68d9 100644
--- a/sys/dev/gve/gve_rx.c
+++ b/sys/dev/gve/gve_rx.c
@@ -209,6 +209,9 @@ gve_free_rx_rings(struct gve_priv *priv, uint16_t start_idx, uint16_t stop_idx)
 {
 	int i;
 
+	if (priv->rx == NULL)
+		return;
+
 	for (i = start_idx; i < stop_idx; i++)
 		gve_rx_free_ring(priv, i);
 }
diff --git a/sys/dev/gve/gve_tx.c b/sys/dev/gve/gve_tx.c
index 5e0611e1d6e4..53451acc1934 100644
--- a/sys/dev/gve/gve_tx.c
+++ b/sys/dev/gve/gve_tx.c
@@ -207,6 +207,9 @@ gve_free_tx_rings(struct gve_priv *priv, uint16_t start_idx, uint16_t stop_idx)
 {
 	int i;
 
+	if (priv->tx == NULL)
+		return;
+
 	for (i = start_idx; i < stop_idx; i++)
 		gve_tx_free_ring(priv, i);
 }