Skip to content

Commit fc9c273

Browse files
author
Paolo Abeni
committed
ipmr: fix tables suspicious RCU usage
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>
1 parent f1553c9 commit fc9c273

File tree

1 file changed

+29
-13
lines changed

1 file changed

+29
-13
lines changed

net/ipv4/ipmr.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ static struct mr_table *ipmr_mr_table_iter(struct net *net,
142142
return ret;
143143
}
144144

145-
static struct mr_table *ipmr_get_table(struct net *net, u32 id)
145+
static struct mr_table *__ipmr_get_table(struct net *net, u32 id)
146146
{
147147
struct mr_table *mrt;
148148

@@ -153,6 +153,16 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
153153
return NULL;
154154
}
155155

156+
static struct mr_table *ipmr_get_table(struct net *net, u32 id)
157+
{
158+
struct mr_table *mrt;
159+
160+
rcu_read_lock();
161+
mrt = __ipmr_get_table(net, id);
162+
rcu_read_unlock();
163+
return mrt;
164+
}
165+
156166
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
157167
struct mr_table **mrt)
158168
{
@@ -194,7 +204,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,
194204

195205
arg->table = fib_rule_get_table(rule, arg);
196206

197-
mrt = ipmr_get_table(rule->fr_net, arg->table);
207+
mrt = __ipmr_get_table(rule->fr_net, arg->table);
198208
if (!mrt)
199209
return -EAGAIN;
200210
res->mrt = mrt;
@@ -325,6 +335,8 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
325335
return net->ipv4.mrt;
326336
}
327337

338+
#define __ipmr_get_table ipmr_get_table
339+
328340
static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
329341
struct mr_table **mrt)
330342
{
@@ -413,7 +425,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
413425
if (id != RT_TABLE_DEFAULT && id >= 1000000000)
414426
return ERR_PTR(-EINVAL);
415427

416-
mrt = ipmr_get_table(net, id);
428+
mrt = __ipmr_get_table(net, id);
417429
if (mrt)
418430
return mrt;
419431

@@ -1388,7 +1400,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
13881400
goto out_unlock;
13891401
}
13901402

1391-
mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
1403+
mrt = __ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
13921404
if (!mrt) {
13931405
ret = -ENOENT;
13941406
goto out_unlock;
@@ -2276,11 +2288,13 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
22762288
struct mr_table *mrt;
22772289
int err;
22782290

2279-
mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
2280-
if (!mrt)
2291+
rcu_read_lock();
2292+
mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
2293+
if (!mrt) {
2294+
rcu_read_unlock();
22812295
return -ENOENT;
2296+
}
22822297

2283-
rcu_read_lock();
22842298
cache = ipmr_cache_find(mrt, saddr, daddr);
22852299
if (!cache && skb->dev) {
22862300
int vif = ipmr_find_vif(mrt, skb->dev);
@@ -2564,7 +2578,7 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
25642578
grp = nla_get_in_addr_default(tb[RTA_DST], 0);
25652579
tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
25662580

2567-
mrt = ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT);
2581+
mrt = __ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT);
25682582
if (!mrt) {
25692583
err = -ENOENT;
25702584
goto errout_free;
@@ -2618,7 +2632,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
26182632
if (filter.table_id) {
26192633
struct mr_table *mrt;
26202634

2621-
mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id);
2635+
mrt = __ipmr_get_table(sock_net(skb->sk), filter.table_id);
26222636
if (!mrt) {
26232637
if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR)
26242638
return skb->len;
@@ -2726,7 +2740,7 @@ static int rtm_to_ipmr_mfcc(struct net *net, struct nlmsghdr *nlh,
27262740
break;
27272741
}
27282742
}
2729-
mrt = ipmr_get_table(net, tblid);
2743+
mrt = __ipmr_get_table(net, tblid);
27302744
if (!mrt) {
27312745
ret = -ENOENT;
27322746
goto out;
@@ -2934,13 +2948,15 @@ static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
29342948
struct net *net = seq_file_net(seq);
29352949
struct mr_table *mrt;
29362950

2937-
mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
2938-
if (!mrt)
2951+
rcu_read_lock();
2952+
mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
2953+
if (!mrt) {
2954+
rcu_read_unlock();
29392955
return ERR_PTR(-ENOENT);
2956+
}
29402957

29412958
iter->mrt = mrt;
29422959

2943-
rcu_read_lock();
29442960
return mr_vif_seq_start(seq, pos);
29452961
}
29462962

0 commit comments

Comments
 (0)