Skip to content

Commit 9c0a7fd

Browse files
committed
ip6mr: fix tables suspicious RCU usage
jira LE-2522 Rebuild_History Non-Buildable kernel-5.14.0-503.29.1.el9_5 commit-author Paolo Abeni <[email protected]> commit f1553c9 Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-5.14.0-503.29.1.el9_5/f1553c98.failed 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 <[email protected]> Signed-off-by: Paolo Abeni <[email protected]> (cherry picked from commit f1553c9) Signed-off-by: Jonathan Maple <[email protected]> # Conflicts: # net/ipv6/ip6mr.c
1 parent 9e5aa28 commit 9c0a7fd

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
ip6mr: fix tables suspicious RCU usage
2+
3+
jira LE-2522
4+
Rebuild_History Non-Buildable kernel-5.14.0-503.29.1.el9_5
5+
commit-author Paolo Abeni <[email protected]>
6+
commit f1553c9894b4dbeb10a2ab15ab1aa113b3b4047c
7+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
8+
Will be included in final tarball splat. Ref for failed cherry-pick at:
9+
ciq/ciq_backports/kernel-5.14.0-503.29.1.el9_5/f1553c98.failed
10+
11+
Several places call ip6mr_get_table() with no RCU nor RTNL lock.
12+
Add RCU protection inside such helper and provide a lockless variant
13+
for the few callers that already acquired the relevant lock.
14+
15+
Note that some users additionally reference the table outside the RCU
16+
lock. That is actually safe as the table deletion can happen only
17+
after all table accesses are completed.
18+
19+
Fixes: e2d57766e674 ("net: Provide compat support for SIOCGETMIFCNT_IN6 and SIOCGETSGCNT_IN6.")
20+
Fixes: d7c31cbde4bc ("net: ip6mr: add RTM_GETROUTE netlink op")
21+
Reviewed-by: David Ahern <[email protected]>
22+
Signed-off-by: Paolo Abeni <[email protected]>
23+
(cherry picked from commit f1553c9894b4dbeb10a2ab15ab1aa113b3b4047c)
24+
Signed-off-by: Jonathan Maple <[email protected]>
25+
26+
# Conflicts:
27+
# net/ipv6/ip6mr.c
28+
diff --cc net/ipv6/ip6mr.c
29+
index d690d9627206,4147890fe98f..000000000000
30+
--- a/net/ipv6/ip6mr.c
31+
+++ b/net/ipv6/ip6mr.c
32+
@@@ -429,7 -446,6 +444,10 @@@ static void *ip6mr_vif_seq_start(struc
33+
34+
iter->mrt = mrt;
35+
36+
++<<<<<<< HEAD
37+
+ read_lock(&mrt_lock);
38+
++=======
39+
++>>>>>>> f1553c9894b4 (ip6mr: fix tables suspicious RCU usage)
40+
return mr_vif_seq_start(seq, pos);
41+
}
42+
43+
@@@ -2275,13 -2304,15 +2293,23 @@@ int ip6mr_get_route(struct net *net, st
44+
int err;
45+
struct mr_table *mrt;
46+
struct mfc6_cache *cache;
47+
- struct rt6_info *rt = dst_rt6_info(skb_dst(skb));
48+
+ struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
49+
50+
++<<<<<<< HEAD
51+
+ mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
52+
+ if (!mrt)
53+
+ return -ENOENT;
54+
+
55+
+ read_lock(&mrt_lock);
56+
++=======
57+
+ rcu_read_lock();
58+
+ mrt = __ip6mr_get_table(net, RT6_TABLE_DFLT);
59+
+ if (!mrt) {
60+
+ rcu_read_unlock();
61+
+ return -ENOENT;
62+
+ }
63+
+
64+
++>>>>>>> f1553c9894b4 (ip6mr: fix tables suspicious RCU usage)
65+
cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
66+
if (!cache && skb->dev) {
67+
int vif = ip6mr_find_vif(mrt, skb->dev);
68+
@@@ -2502,6 -2532,95 +2530,98 @@@ errout
69+
rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS);
70+
}
71+
72+
++<<<<<<< HEAD
73+
++=======
74+
+ static const struct nla_policy ip6mr_getroute_policy[RTA_MAX + 1] = {
75+
+ [RTA_SRC] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
76+
+ [RTA_DST] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
77+
+ [RTA_TABLE] = { .type = NLA_U32 },
78+
+ };
79+
+
80+
+ static int ip6mr_rtm_valid_getroute_req(struct sk_buff *skb,
81+
+ const struct nlmsghdr *nlh,
82+
+ struct nlattr **tb,
83+
+ struct netlink_ext_ack *extack)
84+
+ {
85+
+ struct rtmsg *rtm;
86+
+ int err;
87+
+
88+
+ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, ip6mr_getroute_policy,
89+
+ extack);
90+
+ if (err)
91+
+ return err;
92+
+
93+
+ rtm = nlmsg_data(nlh);
94+
+ if ((rtm->rtm_src_len && rtm->rtm_src_len != 128) ||
95+
+ (rtm->rtm_dst_len && rtm->rtm_dst_len != 128) ||
96+
+ rtm->rtm_tos || rtm->rtm_table || rtm->rtm_protocol ||
97+
+ rtm->rtm_scope || rtm->rtm_type || rtm->rtm_flags) {
98+
+ NL_SET_ERR_MSG_MOD(extack,
99+
+ "Invalid values in header for multicast route get request");
100+
+ return -EINVAL;
101+
+ }
102+
+
103+
+ if ((tb[RTA_SRC] && !rtm->rtm_src_len) ||
104+
+ (tb[RTA_DST] && !rtm->rtm_dst_len)) {
105+
+ NL_SET_ERR_MSG_MOD(extack, "rtm_src_len and rtm_dst_len must be 128 for IPv6");
106+
+ return -EINVAL;
107+
+ }
108+
+
109+
+ return 0;
110+
+ }
111+
+
112+
+ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
113+
+ struct netlink_ext_ack *extack)
114+
+ {
115+
+ struct net *net = sock_net(in_skb->sk);
116+
+ struct in6_addr src = {}, grp = {};
117+
+ struct nlattr *tb[RTA_MAX + 1];
118+
+ struct mfc6_cache *cache;
119+
+ struct mr_table *mrt;
120+
+ struct sk_buff *skb;
121+
+ u32 tableid;
122+
+ int err;
123+
+
124+
+ err = ip6mr_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
125+
+ if (err < 0)
126+
+ return err;
127+
+
128+
+ if (tb[RTA_SRC])
129+
+ src = nla_get_in6_addr(tb[RTA_SRC]);
130+
+ if (tb[RTA_DST])
131+
+ grp = nla_get_in6_addr(tb[RTA_DST]);
132+
+ tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
133+
+
134+
+ mrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
135+
+ if (!mrt) {
136+
+ NL_SET_ERR_MSG_MOD(extack, "MR table does not exist");
137+
+ return -ENOENT;
138+
+ }
139+
+
140+
+ /* entries are added/deleted only under RTNL */
141+
+ rcu_read_lock();
142+
+ cache = ip6mr_cache_find(mrt, &src, &grp);
143+
+ rcu_read_unlock();
144+
+ if (!cache) {
145+
+ NL_SET_ERR_MSG_MOD(extack, "MR cache entry not found");
146+
+ return -ENOENT;
147+
+ }
148+
+
149+
+ skb = nlmsg_new(mr6_msgsize(false, mrt->maxvif), GFP_KERNEL);
150+
+ if (!skb)
151+
+ return -ENOBUFS;
152+
+
153+
+ err = ip6mr_fill_mroute(mrt, skb, NETLINK_CB(in_skb).portid,
154+
+ nlh->nlmsg_seq, cache, RTM_NEWROUTE, 0);
155+
+ if (err < 0) {
156+
+ kfree_skb(skb);
157+
+ return err;
158+
+ }
159+
+
160+
+ return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
161+
+ }
162+
+
163+
++>>>>>>> f1553c9894b4 (ip6mr: fix tables suspicious RCU usage)
164+
static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
165+
{
166+
const struct nlmsghdr *nlh = cb->nlh;
167+
* Unmerged path net/ipv6/ip6mr.c

0 commit comments

Comments
 (0)