DORMANTno replies

[PATCH net] net: tun: fix race condition between tun_attach and tun_get_user with XDP

From: xietangxin <hidden>
Date: 2026-09-17 07:31:36
Also in: lkml
Subsystem: networking drivers, the rest, tun/tap driver · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Willem de Bruijn, Jason Wang

Concurrent TUNSETIFF ioctls and write() operations on the same
file descriptor can trigger a WARN_ONCE in netif_get_rxqueue():

  virt_tun0 received packet on queue 2, but number of RX queues is 2
  WARNING: CPU: 2 PID: 5989 at net/core/dev.c:5494
  Call trace:
   bpf_prog_run_generic_xdp
   netif_receive_generic_xdp
   do_xdp_generic
   tun_get_user
   tun_chr_write_iter

Because tfile->tun is published before tun_set_real_num_queues()
updates dev->real_num_rx_queues. Concurrent tun_get_user() can
observe the newly attached tun file and process packets with
the new queue_index before dev->real_num_rx_queues is updated.

CPU 0 (tun_attach)         CPU 1 (tun_get_user)
tfile->queue_index = 2
rcu_assign_pointer(tfile->tun)
                           skb_record_rx_queue(skb,tfile->queue_index)
                             do_xdp_generic()
                               netif_receive_generic_xdp()
                               bpf_prog_run_generic_xdp()
                               netif_get_rxqueue()
                               // index(2) >= real_num_rx_queues(2)
                                 WARN_ONCE
tun_set_real_num_queues()
  dev->real_num_rx_queues = 3

Fix this by increase tun->numqueues and call tun_set_real_num_queues()
prior to publishing tfile->tun. This ensures dev->real_num_rx_queues
is updated before any concurrent packet processing path can observe
the attached tun file.

Fixes: 3fe260e00cd0 ("net: tun: record RX queue in skb before do_xdp_generic()")
Cc: stable@vger.kernel.org
Signed-off-by: xietangxin <redacted>
---
 drivers/net/tun.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 5a302709a68a..2fb8df036d8c 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -807,15 +807,16 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
 	 * refcnt.
 	 */
 
+	WRITE_ONCE(tun->numqueues, tun->numqueues + 1);
+	tun_set_real_num_queues(tun);
+
 	/* Publish tfile->tun and tun->tfiles only after we've fully
 	 * initialized tfile; otherwise we risk using half-initialized
 	 * object.
 	 */
 	if (publish_tun)
 		rcu_assign_pointer(tfile->tun, tun);
-	rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
-	WRITE_ONCE(tun->numqueues, tun->numqueues + 1);
-	tun_set_real_num_queues(tun);
+	rcu_assign_pointer(tun->tfiles[tun->numqueues - 1], tfile);
 out:
 	return err;
 }
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help