Skip to content

Commit f1553c9

Browse files
author
Paolo Abeni
committed
ip6mr: fix tables suspicious RCU usage
Several places call ip6mr_get_table() with no RCU nor RTNL lock. Add RCU protection inside such helper and provide a lockless variant for the few callers that already acquired the relevant lock. Note that some users additionally reference the table outside the RCU lock. That is actually safe as the table deletion can happen only after all table accesses are completed. Fixes: e2d5776 ("net: Provide compat support for SIOCGETMIFCNT_IN6 and SIOCGETSGCNT_IN6.") Fixes: d7c31cb ("net: ip6mr: add RTM_GETROUTE netlink op") Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 11b6e70 commit f1553c9

File tree

1 file changed

+27
-11
lines changed

1 file changed

+27
-11
lines changed

net/ipv6/ip6mr.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ static struct mr_table *ip6mr_mr_table_iter(struct net *net,
130130
return ret;
131131
}
132132

133-
static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
133+
static struct mr_table *__ip6mr_get_table(struct net *net, u32 id)
134134
{
135135
struct mr_table *mrt;
136136

@@ -141,6 +141,16 @@ static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
141141
return NULL;
142142
}
143143

144+
static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
145+
{
146+
struct mr_table *mrt;
147+
148+
rcu_read_lock();
149+
mrt = __ip6mr_get_table(net, id);
150+
rcu_read_unlock();
151+
return mrt;
152+
}
153+
144154
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
145155
struct mr_table **mrt)
146156
{
@@ -182,7 +192,7 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
182192

183193
arg->table = fib_rule_get_table(rule, arg);
184194

185-
mrt = ip6mr_get_table(rule->fr_net, arg->table);
195+
mrt = __ip6mr_get_table(rule->fr_net, arg->table);
186196
if (!mrt)
187197
return -EAGAIN;
188198
res->mrt = mrt;
@@ -314,6 +324,8 @@ static struct mr_table *ip6mr_get_table(struct net *net, u32 id)
314324
return net->ipv6.mrt6;
315325
}
316326

327+
#define __ip6mr_get_table ip6mr_get_table
328+
317329
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
318330
struct mr_table **mrt)
319331
{
@@ -392,7 +404,7 @@ static struct mr_table *ip6mr_new_table(struct net *net, u32 id)
392404
{
393405
struct mr_table *mrt;
394406

395-
mrt = ip6mr_get_table(net, id);
407+
mrt = __ip6mr_get_table(net, id);
396408
if (mrt)
397409
return mrt;
398410

@@ -425,13 +437,15 @@ static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
425437
struct net *net = seq_file_net(seq);
426438
struct mr_table *mrt;
427439

428-
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
429-
if (!mrt)
440+
rcu_read_lock();
441+
mrt = __ip6mr_get_table(net, RT6_TABLE_DFLT);
442+
if (!mrt) {
443+
rcu_read_unlock();
430444
return ERR_PTR(-ENOENT);
445+
}
431446

432447
iter->mrt = mrt;
433448

434-
rcu_read_lock();
435449
return mr_vif_seq_start(seq, pos);
436450
}
437451

@@ -2292,11 +2306,13 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
22922306
struct mfc6_cache *cache;
22932307
struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
22942308

2295-
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
2296-
if (!mrt)
2309+
rcu_read_lock();
2310+
mrt = __ip6mr_get_table(net, RT6_TABLE_DFLT);
2311+
if (!mrt) {
2312+
rcu_read_unlock();
22972313
return -ENOENT;
2314+
}
22982315

2299-
rcu_read_lock();
23002316
cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
23012317
if (!cache && skb->dev) {
23022318
int vif = ip6mr_find_vif(mrt, skb->dev);
@@ -2576,7 +2592,7 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
25762592
grp = nla_get_in6_addr(tb[RTA_DST]);
25772593
tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
25782594

2579-
mrt = ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
2595+
mrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
25802596
if (!mrt) {
25812597
NL_SET_ERR_MSG_MOD(extack, "MR table does not exist");
25822598
return -ENOENT;
@@ -2623,7 +2639,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
26232639
if (filter.table_id) {
26242640
struct mr_table *mrt;
26252641

2626-
mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id);
2642+
mrt = __ip6mr_get_table(sock_net(skb->sk), filter.table_id);
26272643
if (!mrt) {
26282644
if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR)
26292645
return skb->len;

0 commit comments

Comments
 (0)