Skip to content

Commit

Permalink
ipmr: fix tables suspicious RCU usage
Browse files Browse the repository at this point in the history
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: 709b46e ("net: Add compat ioctl support for the ipv4 multicast ioctl SIOCGETSGCNT")
Fixes: f0ad086 ("ipv4: ipmr: support multiple tables")
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni committed Nov 28, 2024
1 parent f1553c9 commit fc9c273
Showing 1 changed file with 29 additions and 13 deletions.
42 changes: 29 additions & 13 deletions net/ipv4/ipmr.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static struct mr_table *ipmr_mr_table_iter(struct net *net,
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;

Expand All @@ -153,6 +153,16 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
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,
struct mr_table **mrt)
{
Expand Down Expand Up @@ -194,7 +204,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,

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)
return -EAGAIN;
res->mrt = mrt;
Expand Down Expand Up @@ -325,6 +335,8 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
return net->ipv4.mrt;
}

#define __ipmr_get_table ipmr_get_table

static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
struct mr_table **mrt)
{
Expand Down Expand Up @@ -413,7 +425,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
if (id != RT_TABLE_DEFAULT && id >= 1000000000)
return ERR_PTR(-EINVAL);

mrt = ipmr_get_table(net, id);
mrt = __ipmr_get_table(net, id);
if (mrt)
return mrt;

Expand Down Expand Up @@ -1388,7 +1400,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
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) {
ret = -ENOENT;
goto out_unlock;
Expand Down Expand Up @@ -2276,11 +2288,13 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
struct mr_table *mrt;
int err;

mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
if (!mrt)
rcu_read_lock();
mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
if (!mrt) {
rcu_read_unlock();
return -ENOENT;
}

rcu_read_lock();
cache = ipmr_cache_find(mrt, saddr, daddr);
if (!cache && skb->dev) {
int vif = ipmr_find_vif(mrt, skb->dev);
Expand Down Expand Up @@ -2564,7 +2578,7 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
grp = nla_get_in_addr_default(tb[RTA_DST], 0);
tableid = nla_get_u32_default(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) {
err = -ENOENT;
goto errout_free;
Expand Down Expand Up @@ -2618,7 +2632,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
if (filter.table_id) {
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 (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR)
return skb->len;
Expand Down Expand Up @@ -2726,7 +2740,7 @@ static int rtm_to_ipmr_mfcc(struct net *net, struct nlmsghdr *nlh,
break;
}
}
mrt = ipmr_get_table(net, tblid);
mrt = __ipmr_get_table(net, tblid);
if (!mrt) {
ret = -ENOENT;
goto out;
Expand Down Expand Up @@ -2934,13 +2948,15 @@ static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
struct net *net = seq_file_net(seq);
struct mr_table *mrt;

mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
if (!mrt)
rcu_read_lock();
mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
if (!mrt) {
rcu_read_unlock();
return ERR_PTR(-ENOENT);
}

iter->mrt = mrt;

rcu_read_lock();
return mr_vif_seq_start(seq, pos);
}

Expand Down

0 comments on commit fc9c273

Please sign in to comment.