lkml.org 
[lkml]   [2021]   [Jul]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.13 398/800] rtnetlink: avoid RCU read lock when holding RTNL
    Date
    From: Cong Wang <cong.wang@bytedance.com>

    [ Upstream commit a100243d95a60d74ae9bb9df1f5f2192e9aed6a7 ]

    When we call af_ops->set_link_af() we hold a RCU read lock
    as we retrieve af_ops from the RCU protected list, but this
    is unnecessary because we already hold RTNL lock, which is
    the writer lock for protecting rtnl_af_ops, so it is safer
    than RCU read lock. Similar for af_ops->validate_link_af().

    This was not a problem until we begin to take mutex lock
    down the path of ->set_link_af() in __ipv6_dev_mc_dec()
    recently. We can just drop the RCU read lock there and
    assert RTNL lock.

    Reported-and-tested-by: syzbot+7d941e89dd48bcf42573@syzkaller.appspotmail.com
    Fixes: 63ed8de4be81 ("mld: add mc_lock for protecting per-interface mld data")
    Tested-by: Taehee Yoo <ap420073@gmail.com>
    Signed-off-by: Cong Wang <cong.wang@bytedance.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/core/rtnetlink.c | 26 +++++++-------------------
    net/ipv4/devinet.c | 4 ++--
    2 files changed, 9 insertions(+), 21 deletions(-)

    diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
    index ec931b080156..c6e75bd0035d 100644
    --- a/net/core/rtnetlink.c
    +++ b/net/core/rtnetlink.c
    @@ -543,7 +543,9 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family)
    {
    const struct rtnl_af_ops *ops;

    - list_for_each_entry_rcu(ops, &rtnl_af_ops, list) {
    + ASSERT_RTNL();
    +
    + list_for_each_entry(ops, &rtnl_af_ops, list) {
    if (ops->family == family)
    return ops;
    }
    @@ -2274,27 +2276,18 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
    nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
    const struct rtnl_af_ops *af_ops;

    - rcu_read_lock();
    af_ops = rtnl_af_lookup(nla_type(af));
    - if (!af_ops) {
    - rcu_read_unlock();
    + if (!af_ops)
    return -EAFNOSUPPORT;
    - }

    - if (!af_ops->set_link_af) {
    - rcu_read_unlock();
    + if (!af_ops->set_link_af)
    return -EOPNOTSUPP;
    - }

    if (af_ops->validate_link_af) {
    err = af_ops->validate_link_af(dev, af);
    - if (err < 0) {
    - rcu_read_unlock();
    + if (err < 0)
    return err;
    - }
    }
    -
    - rcu_read_unlock();
    }
    }

    @@ -2868,17 +2861,12 @@ static int do_setlink(const struct sk_buff *skb,
    nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
    const struct rtnl_af_ops *af_ops;

    - rcu_read_lock();
    -
    BUG_ON(!(af_ops = rtnl_af_lookup(nla_type(af))));

    err = af_ops->set_link_af(dev, af, extack);
    - if (err < 0) {
    - rcu_read_unlock();
    + if (err < 0)
    goto errout;
    - }

    - rcu_read_unlock();
    status |= DO_SETLINK_NOTIFY;
    }
    }
    diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
    index 1c6429c353a9..73721a4448bd 100644
    --- a/net/ipv4/devinet.c
    +++ b/net/ipv4/devinet.c
    @@ -1955,7 +1955,7 @@ static int inet_validate_link_af(const struct net_device *dev,
    struct nlattr *a, *tb[IFLA_INET_MAX+1];
    int err, rem;

    - if (dev && !__in_dev_get_rcu(dev))
    + if (dev && !__in_dev_get_rtnl(dev))
    return -EAFNOSUPPORT;

    err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla,
    @@ -1981,7 +1981,7 @@ static int inet_validate_link_af(const struct net_device *dev,
    static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
    struct netlink_ext_ack *extack)
    {
    - struct in_device *in_dev = __in_dev_get_rcu(dev);
    + struct in_device *in_dev = __in_dev_get_rtnl(dev);
    struct nlattr *a, *tb[IFLA_INET_MAX+1];
    int rem;

    --
    2.30.2


    \
     
     \ /
      Last update: 2021-07-12 11:09    [W:2.412 / U:0.144 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site