Skip to content

Commit 74841b1

Browse files
author
CKI Backport Bot
committed
ip6mr: fix tables suspicious RCU usage
JIRA: https://issues.redhat.com/browse/RHEL-74037 commit f1553c9 Author: Paolo Abeni <pabeni@redhat.com> Date: Sun Nov 24 16:40:57 2024 +0100 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> Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
1 parent 96643f4 commit 74841b1

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

@@ -2289,11 +2303,13 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
22892303
struct mfc6_cache *cache;
22902304
struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
22912305

2292-
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
2293-
if (!mrt)
2306+
rcu_read_lock();
2307+
mrt = __ip6mr_get_table(net, RT6_TABLE_DFLT);
2308+
if (!mrt) {
2309+
rcu_read_unlock();
22942310
return -ENOENT;
2311+
}
22952312

2296-
rcu_read_lock();
22972313
cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
22982314
if (!cache && skb->dev) {
22992315
int vif = ip6mr_find_vif(mrt, skb->dev);
@@ -2573,7 +2589,7 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
25732589
grp = nla_get_in6_addr(tb[RTA_DST]);
25742590
tableid = tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : 0;
25752591

2576-
mrt = ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
2592+
mrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
25772593
if (!mrt) {
25782594
NL_SET_ERR_MSG_MOD(extack, "MR table does not exist");
25792595
return -ENOENT;
@@ -2620,7 +2636,7 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
26202636
if (filter.table_id) {
26212637
struct mr_table *mrt;
26222638

2623-
mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id);
2639+
mrt = __ip6mr_get_table(sock_net(skb->sk), filter.table_id);
26242640
if (!mrt) {
26252641
if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR)
26262642
return skb->len;

0 commit comments

Comments
 (0)