Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e20dd1b0 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Greg Kroah-Hartman
Browse files

igmp: Fix data-races around sysctl_igmp_qrv.



[ Upstream commit 8ebcc62c738f68688ee7c6fec2efe5bc6d3d7e60 ]

While reading sysctl_igmp_qrv, it can be changed concurrently.
Thus, we need to add READ_ONCE() to its readers.

This test can be packed into a helper, so such changes will be in the
follow-up series after net is merged into net-next.

  qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);

Fixes: a9fe8e29 ("ipv4: implement igmp_qrv sysctl to tune igmp robustness variable")
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 73e5a0b5
Loading
Loading
Loading
Loading
+13 −11
Original line number Diff line number Diff line
@@ -829,7 +829,7 @@ static void igmp_ifc_event(struct in_device *in_dev)
	struct net *net = dev_net(in_dev->dev);
	if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
		return;
	WRITE_ONCE(in_dev->mr_ifc_count, in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv);
	WRITE_ONCE(in_dev->mr_ifc_count, in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv));
	igmp_ifc_start_timer(in_dev, 1);
}

@@ -1011,7 +1011,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
		 * received value was zero, use the default or statically
		 * configured value.
		 */
		in_dev->mr_qrv = ih3->qrv ?: net->ipv4.sysctl_igmp_qrv;
		in_dev->mr_qrv = ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
		in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;

		/* RFC3376, 8.3. Query Response Interval:
@@ -1191,7 +1191,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
	pmc->interface = im->interface;
	in_dev_hold(in_dev);
	pmc->multiaddr = im->multiaddr;
	pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
	pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
	pmc->sfmode = im->sfmode;
	if (pmc->sfmode == MCAST_INCLUDE) {
		struct ip_sf_list *psf;
@@ -1242,9 +1242,11 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
			swap(im->tomb, pmc->tomb);
			swap(im->sources, pmc->sources);
			for (psf = im->sources; psf; psf = psf->sf_next)
				psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
				psf->sf_crcount = in_dev->mr_qrv ?:
					READ_ONCE(net->ipv4.sysctl_igmp_qrv);
		} else {
			im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
			im->crcount = in_dev->mr_qrv ?:
				READ_ONCE(net->ipv4.sysctl_igmp_qrv);
		}
		in_dev_put(pmc->interface);
		kfree_pmc(pmc);
@@ -1351,7 +1353,7 @@ static void igmp_group_added(struct ip_mc_list *im)
	if (in_dev->dead)
		return;

	im->unsolicit_count = net->ipv4.sysctl_igmp_qrv;
	im->unsolicit_count = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
	if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
		spin_lock_bh(&im->lock);
		igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
@@ -1365,7 +1367,7 @@ static void igmp_group_added(struct ip_mc_list *im)
	 * IN() to IN(A).
	 */
	if (im->sfmode == MCAST_EXCLUDE)
		im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
		im->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);

	igmp_ifc_event(in_dev);
#endif
@@ -1756,7 +1758,7 @@ static void ip_mc_reset(struct in_device *in_dev)

	in_dev->mr_qi = IGMP_QUERY_INTERVAL;
	in_dev->mr_qri = IGMP_QUERY_RESPONSE_INTERVAL;
	in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
	in_dev->mr_qrv = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
}
#else
static void ip_mc_reset(struct in_device *in_dev)
@@ -1890,7 +1892,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
#ifdef CONFIG_IP_MULTICAST
		if (psf->sf_oldin &&
		    !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
			psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
			psf->sf_crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
			psf->sf_next = pmc->tomb;
			pmc->tomb = psf;
			rv = 1;
@@ -1954,7 +1956,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
		/* filter mode change */
		pmc->sfmode = MCAST_INCLUDE;
#ifdef CONFIG_IP_MULTICAST
		pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
		pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
		WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
		for (psf = pmc->sources; psf; psf = psf->sf_next)
			psf->sf_crcount = 0;
@@ -2133,7 +2135,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
#ifdef CONFIG_IP_MULTICAST
		/* else no filters; keep old mode for reports */

		pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
		pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
		WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
		for (psf = pmc->sources; psf; psf = psf->sf_next)
			psf->sf_crcount = 0;