lkml.org 
[lkml]   [2022]   [Aug]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 16/34] igmp: Fix data-races around sysctl_igmp_qrv.
    Date
    From: Kuniyuki Iwashima <kuniyu@amazon.com>

    [ 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: a9fe8e29945d ("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>
    ---
    net/ipv4/igmp.c | 24 +++++++++++++-----------
    1 file changed, 13 insertions(+), 11 deletions(-)

    diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
    index 660b41040c77..1023f881091e 100644
    --- a/net/ipv4/igmp.c
    +++ b/net/ipv4/igmp.c
    @@ -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;
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-08-01 13:49    [W:4.294 / U:25.184 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site