The 'missed' bitmap in struct udp_tunnel_nic can be accessed concurrently: - Writes (__set_bit) happen in the port add path (add_port), which holds the RTNL lock. - Reads (checking if missed is non-zero) happen in the reset path (reset_ntf) via __udp_tunnel_nic_device_sync(), which holds utn->lock but does not hold RTNL after the blamed commit. This setup creates a data race between concurrent writes and reads on different CPUs. Fix this by using atomic set_bit() for writes, READ_ONCE() for the fast-path read, and WRITE_ONCE() for clearing the bitmap. Fixes: 1ead7501094c ("udp_tunnel: remove rtnl_lock dependency") Signed-off-by: Eric Dumazet --- net/ipv4/udp_tunnel_nic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/udp_tunnel_nic.c b/net/ipv4/udp_tunnel_nic.c index 840be5d79fc0ac3142049dcb9f1105a5844da9ae..9a567a87635caaf76f5b88029a7f28a65c795efc 100644 --- a/net/ipv4/udp_tunnel_nic.c +++ b/net/ipv4/udp_tunnel_nic.c @@ -147,7 +147,7 @@ udp_tunnel_nic_should_replay(struct net_device *dev, struct udp_tunnel_nic *utn) const struct udp_tunnel_nic_table_info *table; unsigned int i, j; - if (!utn->missed) + if (!READ_ONCE(utn->missed)) return false; for (i = 0; i < utn->n_tables; i++) { @@ -353,7 +353,7 @@ udp_tunnel_nic_has_collision(struct net_device *dev, struct udp_tunnel_nic *utn, if (!udp_tunnel_nic_entry_is_free(entry) && entry->port == ti->port && entry->type != ti->type) { - __set_bit(i, &utn->missed); + set_bit(i, &utn->missed); return true; } } @@ -488,7 +488,7 @@ udp_tunnel_nic_add_new(struct net_device *dev, struct udp_tunnel_nic *utn, * are no devices currently which have multiple tables accepting * the same tunnel type, and false positives are okay. */ - __set_bit(i, &utn->missed); + set_bit(i, &utn->missed); } return false; @@ -718,7 +718,7 @@ udp_tunnel_nic_replay(struct net_device *dev, struct udp_tunnel_nic *utn) for (i = 0; i < utn->n_tables; i++) for (j = 0; j < info->tables[i].n_entries; j++) udp_tunnel_nic_entry_freeze_used(&utn->entries[i][j]); - utn->missed = 0; + WRITE_ONCE(utn->missed, 0); clear_bit(UDP_TUNNEL_NIC_NEED_REPLAY, &utn->flags); if (!info->shared) { -- 2.55.0.rc0.799.gd6f94ed593-goog