|
| 1 | +From 5bfcfb00e0bd7314a9b86b55e1c7e009aa70111e Mon Sep 17 00:00:00 2001 |
| 2 | +From: Jesper Dangaard Brouer <hawk@kernel.org> |
| 3 | +Date: Wed, 11 Jun 2025 14:40:04 +0200 |
| 4 | +Subject: [PATCH] veth: prevent NULL pointer dereference in veth_xdp_rcv |
| 5 | + |
| 6 | +The veth peer device is RCU protected, but when the peer device gets |
| 7 | +deleted (veth_dellink) then the pointer is assigned NULL (via |
| 8 | +RCU_INIT_POINTER). |
| 9 | + |
| 10 | +This patch adds a necessary NULL check in veth_xdp_rcv when accessing |
| 11 | +the veth peer net_device. |
| 12 | + |
| 13 | +This fixes a bug introduced in commit dc82a33297fc ("veth: apply qdisc |
| 14 | +backpressure on full ptr_ring to reduce TX drops"). The bug is a race |
| 15 | +and only triggers when having inflight packets on a veth that is being |
| 16 | +deleted. |
| 17 | + |
| 18 | +Reported-by: Ihor Solodrai <ihor.solodrai@linux.dev> |
| 19 | +Closes: https://lore.kernel.org/all/fecfcad0-7a16-42b8-bff2-66ee83a6e5c4@linux.dev/ |
| 20 | +Reported-by: syzbot+c4c7bf27f6b0c4bd97fe@syzkaller.appspotmail.com |
| 21 | +Closes: https://lore.kernel.org/all/683da55e.a00a0220.d8eae.0052.GAE@google.com/ |
| 22 | +Fixes: dc82a33297fc ("veth: apply qdisc backpressure on full ptr_ring to reduce TX drops") |
| 23 | +Signed-off-by: Jesper Dangaard Brouer <hawk@kernel.org> |
| 24 | +--- |
| 25 | + drivers/net/veth.c | 4 ++-- |
| 26 | + 1 file changed, 2 insertions(+), 2 deletions(-) |
| 27 | + |
| 28 | +diff --git a/drivers/net/veth.c b/drivers/net/veth.c |
| 29 | +index e58a0f1b5c5b..a3046142cb8e 100644 |
| 30 | +--- a/drivers/net/veth.c |
| 31 | ++++ b/drivers/net/veth.c |
| 32 | +@@ -909,7 +909,7 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget, |
| 33 | + |
| 34 | + /* NAPI functions as RCU section */ |
| 35 | + peer_dev = rcu_dereference_check(priv->peer, rcu_read_lock_bh_held()); |
| 36 | +- peer_txq = netdev_get_tx_queue(peer_dev, queue_idx); |
| 37 | ++ peer_txq = peer_dev ? netdev_get_tx_queue(peer_dev, queue_idx) : NULL; |
| 38 | + |
| 39 | + for (i = 0; i < budget; i++) { |
| 40 | + void *ptr = __ptr_ring_consume(&rq->xdp_ring); |
| 41 | +@@ -959,7 +959,7 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget, |
| 42 | + rq->stats.vs.xdp_packets += done; |
| 43 | + u64_stats_update_end(&rq->stats.syncp); |
| 44 | + |
| 45 | +- if (unlikely(netif_tx_queue_stopped(peer_txq))) |
| 46 | ++ if (peer_txq && unlikely(netif_tx_queue_stopped(peer_txq))) |
| 47 | + netif_tx_wake_queue(peer_txq); |
| 48 | + |
| 49 | + return done; |
| 50 | +-- |
| 51 | +2.49.0 |
| 52 | + |
0 commit comments