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: a9fe8e2994
("ipv4: implement igmp_qrv sysctl to tune igmp robustness variable")
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
4c1318dabe
commit
b399ffafff
@@ -827,7 +827,7 @@ static void igmp_ifc_event(struct in_device *in_dev)
|
|||||||
struct net *net = dev_net(in_dev->dev);
|
struct net *net = dev_net(in_dev->dev);
|
||||||
if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
|
if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
|
||||||
return;
|
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);
|
igmp_ifc_start_timer(in_dev, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1009,7 +1009,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
|
|||||||
* received value was zero, use the default or statically
|
* received value was zero, use the default or statically
|
||||||
* configured value.
|
* 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;
|
in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;
|
||||||
|
|
||||||
/* RFC3376, 8.3. Query Response Interval:
|
/* RFC3376, 8.3. Query Response Interval:
|
||||||
@@ -1189,7 +1189,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
|
|||||||
pmc->interface = im->interface;
|
pmc->interface = im->interface;
|
||||||
in_dev_hold(in_dev);
|
in_dev_hold(in_dev);
|
||||||
pmc->multiaddr = im->multiaddr;
|
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;
|
pmc->sfmode = im->sfmode;
|
||||||
if (pmc->sfmode == MCAST_INCLUDE) {
|
if (pmc->sfmode == MCAST_INCLUDE) {
|
||||||
struct ip_sf_list *psf;
|
struct ip_sf_list *psf;
|
||||||
@@ -1240,9 +1240,11 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
|
|||||||
swap(im->tomb, pmc->tomb);
|
swap(im->tomb, pmc->tomb);
|
||||||
swap(im->sources, pmc->sources);
|
swap(im->sources, pmc->sources);
|
||||||
for (psf = im->sources; psf; psf = psf->sf_next)
|
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 {
|
} 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);
|
in_dev_put(pmc->interface);
|
||||||
kfree_pmc(pmc);
|
kfree_pmc(pmc);
|
||||||
@@ -1349,7 +1351,7 @@ static void igmp_group_added(struct ip_mc_list *im)
|
|||||||
if (in_dev->dead)
|
if (in_dev->dead)
|
||||||
return;
|
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)) {
|
if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
|
||||||
spin_lock_bh(&im->lock);
|
spin_lock_bh(&im->lock);
|
||||||
igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
|
igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
|
||||||
@@ -1363,7 +1365,7 @@ static void igmp_group_added(struct ip_mc_list *im)
|
|||||||
* IN() to IN(A).
|
* IN() to IN(A).
|
||||||
*/
|
*/
|
||||||
if (im->sfmode == MCAST_EXCLUDE)
|
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);
|
igmp_ifc_event(in_dev);
|
||||||
#endif
|
#endif
|
||||||
@@ -1754,7 +1756,7 @@ static void ip_mc_reset(struct in_device *in_dev)
|
|||||||
|
|
||||||
in_dev->mr_qi = IGMP_QUERY_INTERVAL;
|
in_dev->mr_qi = IGMP_QUERY_INTERVAL;
|
||||||
in_dev->mr_qri = IGMP_QUERY_RESPONSE_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
|
#else
|
||||||
static void ip_mc_reset(struct in_device *in_dev)
|
static void ip_mc_reset(struct in_device *in_dev)
|
||||||
@@ -1888,7 +1890,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
|
|||||||
#ifdef CONFIG_IP_MULTICAST
|
#ifdef CONFIG_IP_MULTICAST
|
||||||
if (psf->sf_oldin &&
|
if (psf->sf_oldin &&
|
||||||
!IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
|
!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;
|
psf->sf_next = pmc->tomb;
|
||||||
pmc->tomb = psf;
|
pmc->tomb = psf;
|
||||||
rv = 1;
|
rv = 1;
|
||||||
@@ -1952,7 +1954,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
|
|||||||
/* filter mode change */
|
/* filter mode change */
|
||||||
pmc->sfmode = MCAST_INCLUDE;
|
pmc->sfmode = MCAST_INCLUDE;
|
||||||
#ifdef CONFIG_IP_MULTICAST
|
#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);
|
WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
|
||||||
for (psf = pmc->sources; psf; psf = psf->sf_next)
|
for (psf = pmc->sources; psf; psf = psf->sf_next)
|
||||||
psf->sf_crcount = 0;
|
psf->sf_crcount = 0;
|
||||||
@@ -2131,7 +2133,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
|
|||||||
#ifdef CONFIG_IP_MULTICAST
|
#ifdef CONFIG_IP_MULTICAST
|
||||||
/* else no filters; keep old mode for reports */
|
/* 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);
|
WRITE_ONCE(in_dev->mr_ifc_count, pmc->crcount);
|
||||||
for (psf = pmc->sources; psf; psf = psf->sf_next)
|
for (psf = pmc->sources; psf; psf = psf->sf_next)
|
||||||
psf->sf_crcount = 0;
|
psf->sf_crcount = 0;
|
||||||
|
Reference in New Issue
Block a user