Commit a100243d authored by Cong Wang's avatar Cong Wang Committed by David S. Miller

rtnetlink: avoid RCU read lock when holding RTNL

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: 63ed8de4 ("mld: add mc_lock for protecting per-interface mld data")
Tested-by: default avatarTaehee Yoo <ap420073@gmail.com>
Signed-off-by: default avatarCong Wang <cong.wang@bytedance.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3f8fca5d
...@@ -543,7 +543,9 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family) ...@@ -543,7 +543,9 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family)
{ {
const struct rtnl_af_ops *ops; 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) if (ops->family == family)
return ops; return ops;
} }
...@@ -2274,27 +2276,18 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) ...@@ -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) { nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
const struct rtnl_af_ops *af_ops; const struct rtnl_af_ops *af_ops;
rcu_read_lock();
af_ops = rtnl_af_lookup(nla_type(af)); af_ops = rtnl_af_lookup(nla_type(af));
if (!af_ops) { if (!af_ops)
rcu_read_unlock();
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
}
if (!af_ops->set_link_af) { if (!af_ops->set_link_af)
rcu_read_unlock();
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
if (af_ops->validate_link_af) { if (af_ops->validate_link_af) {
err = af_ops->validate_link_af(dev, af); err = af_ops->validate_link_af(dev, af);
if (err < 0) { if (err < 0)
rcu_read_unlock();
return err; return err;
}
} }
rcu_read_unlock();
} }
} }
...@@ -2868,17 +2861,12 @@ static int do_setlink(const struct sk_buff *skb, ...@@ -2868,17 +2861,12 @@ static int do_setlink(const struct sk_buff *skb,
nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) {
const struct rtnl_af_ops *af_ops; const struct rtnl_af_ops *af_ops;
rcu_read_lock();
BUG_ON(!(af_ops = rtnl_af_lookup(nla_type(af)))); BUG_ON(!(af_ops = rtnl_af_lookup(nla_type(af))));
err = af_ops->set_link_af(dev, af, extack); err = af_ops->set_link_af(dev, af, extack);
if (err < 0) { if (err < 0)
rcu_read_unlock();
goto errout; goto errout;
}
rcu_read_unlock();
status |= DO_SETLINK_NOTIFY; status |= DO_SETLINK_NOTIFY;
} }
} }
......
...@@ -1955,7 +1955,7 @@ static int inet_validate_link_af(const struct net_device *dev, ...@@ -1955,7 +1955,7 @@ static int inet_validate_link_af(const struct net_device *dev,
struct nlattr *a, *tb[IFLA_INET_MAX+1]; struct nlattr *a, *tb[IFLA_INET_MAX+1];
int err, rem; int err, rem;
if (dev && !__in_dev_get_rcu(dev)) if (dev && !__in_dev_get_rtnl(dev))
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, 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, ...@@ -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, static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla,
struct netlink_ext_ack *extack) 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]; struct nlattr *a, *tb[IFLA_INET_MAX+1];
int rem; int rem;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment