Re: [PATCH net-next] tun: no longer rely on RTNL in tun_fill_info()
From: Kuniyuki Iwashima <kuniyu@google.com>
Date: 2026-07-02 03:09:34
On Wed, Jul 1, 2026 at 5:51 AM Eric Dumazet [off-list ref] wrote:
Update tun_fill_info() to read device configuration fields (flags, owner, group, numqueues, numdisabled) locklessly using READ_ONCE(). Annotate all writes to these fields in the control paths with WRITE_ONCE() to prevent data races, as these fields can be modified concurrently via ioctls (TUNSETPERSIST, TUNSETOWNER, TUNSETGROUP, TUNSETIFF) or queue attaching/detaching. Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> I left comments but maybe it's just my preference, not sure if it's worth a respin :)
quoted hunk ↗ jump to hunk
@@ -943,8 +943,8 @@ static int tun_net_init(struct net_device *dev) NETIF_F_HW_VLAN_STAG_TX); dev->lltx = true; - tun->flags = (tun->flags & ~TUN_FEATURES) | - (ifr->ifr_flags & TUN_FEATURES); + WRITE_ONCE(tun->flags, (tun->flags & ~TUN_FEATURES) | + (ifr->ifr_flags & TUN_FEATURES));
WRITE_ONCE() is not needed here as the dev is not yet published. [...]
quoted hunk ↗ jump to hunk
@@ -2814,8 +2818,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) return 0; } - tun->flags = (tun->flags & ~TUN_FEATURES) | - (ifr->ifr_flags & TUN_FEATURES); + WRITE_ONCE(tun->flags, (READ_ONCE(tun->flags) & ~TUN_FEATURES) | + (ifr->ifr_flags & TUN_FEATURES));
READ_ONCE() is not a must here and __tun_chr_ioctl() as all writers are under RTNL.
quoted hunk ↗ jump to hunk
@@ -3213,13 +3217,13 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, /* Disable/Enable persist mode. Keep an extra reference to the * module to prevent the module being unprobed. */ - if (arg && !(tun->flags & IFF_PERSIST)) { - tun->flags |= IFF_PERSIST; + if (arg && !(READ_ONCE(tun->flags) & IFF_PERSIST)) { + WRITE_ONCE(tun->flags, READ_ONCE(tun->flags) | IFF_PERSIST); __module_get(THIS_MODULE); do_notify = true; } - if (!arg && (tun->flags & IFF_PERSIST)) { - tun->flags &= ~IFF_PERSIST; + if (!arg && (READ_ONCE(tun->flags) & IFF_PERSIST)) { + WRITE_ONCE(tun->flags, READ_ONCE(tun->flags) & ~IFF_PERSIST); module_put(THIS_MODULE); do_notify = true; }