/proc/net/igmp walks IPv4 multicast memberships under RCU and prints im->users without holding RTNL, while multicast join and leave paths update the field while holding RTNL. Annotate this intentional lockless snapshot with READ_ONCE() and the matching writers with WRITE_ONCE(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Yuyang Huang --- Changes in v2: - Added Fixes: tag net/ipv4/igmp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 27d120183779..f2aca659b29c 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1541,7 +1541,7 @@ static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr, } if (im) { - im->users++; + WRITE_ONCE(im->users, im->users + 1); ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0); goto out; } @@ -1550,7 +1550,7 @@ static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr, if (!im) goto out; - im->users = 1; + WRITE_ONCE(im->users, 1); im->interface = in_dev; in_dev_hold(in_dev); im->multiaddr = addr; @@ -1784,7 +1784,10 @@ void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp) (i = rtnl_dereference(*ip)) != NULL; ip = &i->next_rcu) { if (i->multiaddr == addr) { - if (--i->users == 0) { + int new_users = i->users - 1; + + WRITE_ONCE(i->users, new_users); + if (new_users == 0) { ip_mc_hash_remove(in_dev, i); *ip = i->next_rcu; in_dev->mc_count--; @@ -2977,7 +2980,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v) delta = im->timer.expires - jiffies; seq_printf(seq, "\t\t\t\t%08X %5d %d:%08lX\t\t%d\n", - im->multiaddr, im->users, + im->multiaddr, READ_ONCE(im->users), im->tm_running, im->tm_running ? jiffies_delta_to_clock_t(delta) : 0, im->reporter); -- 2.43.0