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: 63ed8de4be ("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>
This commit is contained in:
committed by
David S. Miller
parent
3f8fca5d43
commit
a100243d95
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user