提交 3c1c238e 编写于 作者: K Kuniyuki Iwashima 提交者: Yongqiang Liu

igmp: Fix data-races around sysctl_igmp_qrv.

stable inclusion
from stable-v4.19.255
commit 9eeb3a7702998bdccbfcc37997b5dd9215b9a7f7
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I5Q0SQ
CVE: NA

--------------------------------

[ Upstream commit 8ebcc62c ]

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: NKuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NYongqiang Liu <liuyongqiang13@huawei.com>
上级 1e41a05d
...@@ -831,7 +831,7 @@ static void igmp_ifc_event(struct in_device *in_dev) ...@@ -831,7 +831,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);
} }
...@@ -1013,7 +1013,7 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, ...@@ -1013,7 +1013,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:
...@@ -1192,7 +1192,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) ...@@ -1192,7 +1192,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;
...@@ -1243,9 +1243,11 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im) ...@@ -1243,9 +1243,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);
...@@ -1347,7 +1349,7 @@ static void igmp_group_added(struct ip_mc_list *im) ...@@ -1347,7 +1349,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);
...@@ -1361,7 +1363,7 @@ static void igmp_group_added(struct ip_mc_list *im) ...@@ -1361,7 +1363,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
...@@ -1769,7 +1771,7 @@ static void ip_mc_reset(struct in_device *in_dev) ...@@ -1769,7 +1771,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)
...@@ -1903,7 +1905,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, ...@@ -1903,7 +1905,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;
...@@ -1967,7 +1969,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode, ...@@ -1967,7 +1969,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;
...@@ -2146,7 +2148,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, ...@@ -2146,7 +2148,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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册