ipmr: fix tables suspicious RCU usage
[ Upstream commit fc9c273d6daaa9866f349bbe8cae25c67764c456 ] Similar to the previous patch, plumb the RCU lock inside the ipmr_get_table(), provided a lockless variant and apply the latter in the few spots were the lock is already held. Fixes:709b46e8d9
("net: Add compat ioctl support for the ipv4 multicast ioctl SIOCGETSGCNT") Fixes:f0ad0860d0
("ipv4: ipmr: support multiple tables") Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
5e656d0565
commit
7d338cee86
@ -136,7 +136,7 @@ static struct mr_table *ipmr_mr_table_iter(struct net *net,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mr_table *ipmr_get_table(struct net *net, u32 id)
|
static struct mr_table *__ipmr_get_table(struct net *net, u32 id)
|
||||||
{
|
{
|
||||||
struct mr_table *mrt;
|
struct mr_table *mrt;
|
||||||
|
|
||||||
@ -147,6 +147,16 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct mr_table *ipmr_get_table(struct net *net, u32 id)
|
||||||
|
{
|
||||||
|
struct mr_table *mrt;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
mrt = __ipmr_get_table(net, id);
|
||||||
|
rcu_read_unlock();
|
||||||
|
return mrt;
|
||||||
|
}
|
||||||
|
|
||||||
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
|
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
|
||||||
struct mr_table **mrt)
|
struct mr_table **mrt)
|
||||||
{
|
{
|
||||||
@ -188,7 +198,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,
|
|||||||
|
|
||||||
arg->table = fib_rule_get_table(rule, arg);
|
arg->table = fib_rule_get_table(rule, arg);
|
||||||
|
|
||||||
mrt = ipmr_get_table(rule->fr_net, arg->table);
|
mrt = __ipmr_get_table(rule->fr_net, arg->table);
|
||||||
if (!mrt)
|
if (!mrt)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
res->mrt = mrt;
|
res->mrt = mrt;
|
||||||
@ -314,6 +324,8 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
|
|||||||
return net->ipv4.mrt;
|
return net->ipv4.mrt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define __ipmr_get_table ipmr_get_table
|
||||||
|
|
||||||
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
|
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
|
||||||
struct mr_table **mrt)
|
struct mr_table **mrt)
|
||||||
{
|
{
|
||||||
@ -402,7 +414,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
|
|||||||
if (id != RT_TABLE_DEFAULT && id >= 1000000000)
|
if (id != RT_TABLE_DEFAULT && id >= 1000000000)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
mrt = ipmr_get_table(net, id);
|
mrt = __ipmr_get_table(net, id);
|
||||||
if (mrt)
|
if (mrt)
|
||||||
return mrt;
|
return mrt;
|
||||||
|
|
||||||
@ -1373,7 +1385,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
|
|||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
|
mrt = __ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
|
||||||
if (!mrt) {
|
if (!mrt) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
@ -2247,11 +2259,13 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
|
|||||||
struct mr_table *mrt;
|
struct mr_table *mrt;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
|
|
||||||
if (!mrt)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
|
||||||
|
if (!mrt) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
cache = ipmr_cache_find(mrt, saddr, daddr);
|
cache = ipmr_cache_find(mrt, saddr, daddr);
|
||||||
if (!cache && skb->dev) {
|
if (!cache && skb->dev) {
|
||||||
int vif = ipmr_find_vif(mrt, skb->dev);
|
int vif = ipmr_find_vif(mrt, skb->dev);
|
||||||
@ -2536,7 +2550,7 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|||||||
grp = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0;
|
grp = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0;
|
||||||
tableid = tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : 0;
|
tableid = tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : 0;
|
||||||
|
|
||||||
mrt = ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT);
|
mrt = __ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT);
|
||||||
if (!mrt) {
|
if (!mrt) {
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
goto errout_free;
|
goto errout_free;
|
||||||
@ -2588,7 +2602,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
if (filter.table_id) {
|
if (filter.table_id) {
|
||||||
struct mr_table *mrt;
|
struct mr_table *mrt;
|
||||||
|
|
||||||
mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id);
|
mrt = __ipmr_get_table(sock_net(skb->sk), filter.table_id);
|
||||||
if (!mrt) {
|
if (!mrt) {
|
||||||
if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR)
|
if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR)
|
||||||
return skb->len;
|
return skb->len;
|
||||||
@ -2696,7 +2710,7 @@ static int rtm_to_ipmr_mfcc(struct net *net, struct nlmsghdr *nlh,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mrt = ipmr_get_table(net, tblid);
|
mrt = __ipmr_get_table(net, tblid);
|
||||||
if (!mrt) {
|
if (!mrt) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
@ -2904,13 +2918,15 @@ static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
|
|||||||
struct net *net = seq_file_net(seq);
|
struct net *net = seq_file_net(seq);
|
||||||
struct mr_table *mrt;
|
struct mr_table *mrt;
|
||||||
|
|
||||||
mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
|
rcu_read_lock();
|
||||||
if (!mrt)
|
mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
|
||||||
|
if (!mrt) {
|
||||||
|
rcu_read_unlock();
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
}
|
||||||
|
|
||||||
iter->mrt = mrt;
|
iter->mrt = mrt;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
return mr_vif_seq_start(seq, pos);
|
return mr_vif_seq_start(seq, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user