[PATCH] um: vector: fix NULL pointer derefs in queue-less transports

Michael Bommarito <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.uml.devel,gmane.linux.kernel.stable
Message-ID <[email protected]>
TAP transport sets neither VECTOR_RX nor VECTOR_TX, so
vector_net_open() never allocates rx_queue or tx_queue.  HYBRID sets
VECTOR_RX but not VECTOR_TX, so tx_queue is NULL there too.

vector_reset_stats(), vector_poll(), vector_get_ethtool_stats(), and
vector_get_ringparam() unconditionally deref these queue pointers,
causing a NULL pointer crash on SMP or with any lock debugging option.

Guard all queue pointer accesses with NULL checks.

Fixes: 49da7e64f33e ("High Performance UML Vector Network Driver")
Cc: [email protected]
Cc: Anton Ivanov <[email protected]>
Assisted-by: Claude:claude-opus-4-6
Assisted-by: Codex:gpt-5-4
Signed-off-by: Michael Bommarito <[email protected]>
---
Found while enabling KCOV and lockdep on UML for a network-stack
test lab.  Tested boot with SMP=y + PROVE_LOCKING + DEBUG_SPINLOCK +
DEBUG_LOCK_ALLOC + LOCKDEP + KCOV, all with vec0:transport=tap.

Without the fix, the same config panics at addr 0x18 (SMP, no debug),
0x1c (DEBUG_SPINLOCK), or 0x30 (lockdep) -- all offsets into a NULL
vector_queue pointer.

 arch/um/drivers/vector_kern.c | 48 +++++++++++++++++------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c
index 2cc90055499a5..6134c376e57be 100644
--- a/arch/um/drivers/vector_kern.c
+++ b/arch/um/drivers/vector_kern.c
@@ -105,25 +105,18 @@ static const struct {
 
 static void vector_reset_stats(struct vector_private *vp)
 {
-	/* We reuse the existing queue locks for stats */
-
-	/* RX stats are modified with RX head_lock held
-	 * in vector_poll.
-	 */
-
-	spin_lock(&vp->rx_queue->head_lock);
+	if (vp->rx_queue)
+		spin_lock(&vp->rx_queue->head_lock);
 	vp->estats.rx_queue_max = 0;
 	vp->estats.rx_queue_running_average = 0;
 	vp->estats.rx_encaps_errors = 0;
 	vp->estats.sg_ok = 0;
 	vp->estats.sg_linearized = 0;
-	spin_unlock(&vp->rx_queue->head_lock);
-
-	/* TX stats are modified with TX head_lock held
-	 * in vector_send.
-	 */
+	if (vp->rx_queue)
+		spin_unlock(&vp->rx_queue->head_lock);
 
-	spin_lock(&vp->tx_queue->head_lock);
+	if (vp->tx_queue)
+		spin_lock(&vp->tx_queue->head_lock);
 	vp->estats.tx_timeout_count = 0;
 	vp->estats.tx_restart_queue = 0;
 	vp->estats.tx_kicks = 0;
@@ -131,7 +124,8 @@ static void vector_reset_stats(struct vector_private *vp)
 	vp->estats.tx_flow_control_xoff = 0;
 	vp->estats.tx_queue_max = 0;
 	vp->estats.tx_queue_running_average = 0;
-	spin_unlock(&vp->tx_queue->head_lock);
+	if (vp->tx_queue)
+		spin_unlock(&vp->tx_queue->head_lock);
 }
 
 static int get_mtu(struct arglist *def)
@@ -1163,7 +1157,8 @@ static int vector_poll(struct napi_struct *napi, int budget)
 
 	if ((vp->options & VECTOR_TX) != 0)
 		tx_enqueued = (vector_send(vp->tx_queue) > 0);
-	spin_lock(&vp->rx_queue->head_lock);
+	if (vp->rx_queue)
+		spin_lock(&vp->rx_queue->head_lock);
 	if ((vp->options & VECTOR_RX) > 0)
 		err = vector_mmsg_rx(vp, budget);
 	else {
@@ -1171,7 +1166,8 @@ static int vector_poll(struct napi_struct *napi, int budget)
 		if (err > 0)
 			err = 1;
 	}
-	spin_unlock(&vp->rx_queue->head_lock);
+	if (vp->rx_queue)
+		spin_unlock(&vp->rx_queue->head_lock);
 	if (err > 0)
 		work_done += err;
 
@@ -1421,10 +1417,10 @@ static void vector_get_ringparam(struct net_device *netdev,
 {
 	struct vector_private *vp = netdev_priv(netdev);
 
-	ring->rx_max_pending = vp->rx_queue->max_depth;
-	ring->tx_max_pending = vp->tx_queue->max_depth;
-	ring->rx_pending = vp->rx_queue->max_depth;
-	ring->tx_pending = vp->tx_queue->max_depth;
+	ring->rx_max_pending = vp->rx_queue ? vp->rx_queue->max_depth : 0;
+	ring->tx_max_pending = vp->tx_queue ? vp->tx_queue->max_depth : 0;
+	ring->rx_pending = ring->rx_max_pending;
+	ring->tx_pending = ring->tx_max_pending;
 }
 
 static void vector_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -1466,11 +1462,15 @@ static void vector_get_ethtool_stats(struct net_device *dev,
 	 * to date.
 	 */
 
-	spin_lock(&vp->tx_queue->head_lock);
-	spin_lock(&vp->rx_queue->head_lock);
+	if (vp->tx_queue)
+		spin_lock(&vp->tx_queue->head_lock);
+	if (vp->rx_queue)
+		spin_lock(&vp->rx_queue->head_lock);
 	memcpy(tmp_stats, &vp->estats, sizeof(struct vector_estats));
-	spin_unlock(&vp->rx_queue->head_lock);
-	spin_unlock(&vp->tx_queue->head_lock);
+	if (vp->rx_queue)
+		spin_unlock(&vp->rx_queue->head_lock);
+	if (vp->tx_queue)
+		spin_unlock(&vp->tx_queue->head_lock);
 }
 
 static int vector_get_coalesce(struct net_device *netdev,
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.