hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/net/mpls/af_mpls.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 #include <linux/types.h>
23 #include <linux/skbuff.h>
34 #include <linux/socket.h>
....@@ -22,8 +23,8 @@
2223 #if IS_ENABLED(CONFIG_IPV6)
2324 #include <net/ipv6.h>
2425 #endif
25
-#include <net/addrconf.h>
26
-#include <net/nexthop.h>
26
+#include <net/ipv6_stubs.h>
27
+#include <net/rtnh.h>
2728 #include "internal.h"
2829
2930 /* max memory we will use for mpls_route */
....@@ -36,8 +37,6 @@
3637
3738 #define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
3839
39
-static int zero = 0;
40
-static int one = 1;
4140 static int label_limit = (1 << 20) - 1;
4241 static int ttl_max = 255;
4342
....@@ -1079,9 +1078,9 @@
10791078
10801079 p = per_cpu_ptr(mdev->stats, i);
10811080 do {
1082
- start = u64_stats_fetch_begin(&p->syncp);
1081
+ start = u64_stats_fetch_begin_irq(&p->syncp);
10831082 local = p->stats;
1084
- } while (u64_stats_fetch_retry(&p->syncp, start));
1083
+ } while (u64_stats_fetch_retry_irq(&p->syncp, start));
10851084
10861085 stats->rx_packets += local.rx_packets;
10871086 stats->rx_bytes += local.rx_bytes;
....@@ -1208,21 +1207,59 @@
12081207 [NETCONFA_IFINDEX] = { .len = sizeof(int) },
12091208 };
12101209
1210
+static int mpls_netconf_valid_get_req(struct sk_buff *skb,
1211
+ const struct nlmsghdr *nlh,
1212
+ struct nlattr **tb,
1213
+ struct netlink_ext_ack *extack)
1214
+{
1215
+ int i, err;
1216
+
1217
+ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
1218
+ NL_SET_ERR_MSG_MOD(extack,
1219
+ "Invalid header for netconf get request");
1220
+ return -EINVAL;
1221
+ }
1222
+
1223
+ if (!netlink_strict_get_check(skb))
1224
+ return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg),
1225
+ tb, NETCONFA_MAX,
1226
+ devconf_mpls_policy, extack);
1227
+
1228
+ err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg),
1229
+ tb, NETCONFA_MAX,
1230
+ devconf_mpls_policy, extack);
1231
+ if (err)
1232
+ return err;
1233
+
1234
+ for (i = 0; i <= NETCONFA_MAX; i++) {
1235
+ if (!tb[i])
1236
+ continue;
1237
+
1238
+ switch (i) {
1239
+ case NETCONFA_IFINDEX:
1240
+ break;
1241
+ default:
1242
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in netconf get request");
1243
+ return -EINVAL;
1244
+ }
1245
+ }
1246
+
1247
+ return 0;
1248
+}
1249
+
12111250 static int mpls_netconf_get_devconf(struct sk_buff *in_skb,
12121251 struct nlmsghdr *nlh,
12131252 struct netlink_ext_ack *extack)
12141253 {
12151254 struct net *net = sock_net(in_skb->sk);
12161255 struct nlattr *tb[NETCONFA_MAX + 1];
1217
- struct netconfmsg *ncm;
12181256 struct net_device *dev;
12191257 struct mpls_dev *mdev;
12201258 struct sk_buff *skb;
12211259 int ifindex;
12221260 int err;
12231261
1224
- err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
1225
- devconf_mpls_policy, NULL);
1262
+ err = mpls_netconf_valid_get_req(in_skb, nlh, tb, extack);
12261263 if (err < 0)
12271264 goto errout;
12281265
....@@ -1262,12 +1299,28 @@
12621299 static int mpls_netconf_dump_devconf(struct sk_buff *skb,
12631300 struct netlink_callback *cb)
12641301 {
1302
+ const struct nlmsghdr *nlh = cb->nlh;
12651303 struct net *net = sock_net(skb->sk);
12661304 struct hlist_head *head;
12671305 struct net_device *dev;
12681306 struct mpls_dev *mdev;
12691307 int idx, s_idx;
12701308 int h, s_h;
1309
+
1310
+ if (cb->strict_check) {
1311
+ struct netlink_ext_ack *extack = cb->extack;
1312
+ struct netconfmsg *ncm;
1313
+
1314
+ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) {
1315
+ NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf dump request");
1316
+ return -EINVAL;
1317
+ }
1318
+
1319
+ if (nlmsg_attrlen(nlh, sizeof(*ncm))) {
1320
+ NL_SET_ERR_MSG_MOD(extack, "Invalid data after header in netconf dump request");
1321
+ return -EINVAL;
1322
+ }
1323
+ }
12711324
12721325 s_h = cb->args[0];
12731326 s_idx = idx = cb->args[1];
....@@ -1285,7 +1338,7 @@
12851338 goto cont;
12861339 if (mpls_netconf_fill_devconf(skb, mdev,
12871340 NETLINK_CB(cb->skb).portid,
1288
- cb->nlh->nlmsg_seq,
1341
+ nlh->nlmsg_seq,
12891342 RTM_NEWNETCONF,
12901343 NLM_F_MULTI,
12911344 NETCONFA_ALL) < 0) {
....@@ -1309,8 +1362,7 @@
13091362 (&((struct mpls_dev *)0)->field)
13101363
13111364 static int mpls_conf_proc(struct ctl_table *ctl, int write,
1312
- void __user *buffer,
1313
- size_t *lenp, loff_t *ppos)
1365
+ void *buffer, size_t *lenp, loff_t *ppos)
13141366 {
13151367 int oval = *(int *)ctl->data;
13161368 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
....@@ -1375,6 +1427,7 @@
13751427 free:
13761428 kfree(table);
13771429 out:
1430
+ mdev->sysctl = NULL;
13781431 return -ENOBUFS;
13791432 }
13801433
....@@ -1383,6 +1436,9 @@
13831436 {
13841437 struct net *net = dev_net(dev);
13851438 struct ctl_table *table;
1439
+
1440
+ if (!mdev->sysctl)
1441
+ return;
13861442
13871443 table = mdev->sysctl->ctl_table_arg;
13881444 unregister_net_sysctl_table(mdev->sysctl);
....@@ -1494,7 +1550,7 @@
14941550 case NETDEV_DOWN:
14951551 case NETDEV_UNREGISTER:
14961552 nh_flags |= RTNH_F_DEAD;
1497
- /* fall through */
1553
+ fallthrough;
14981554 case NETDEV_CHANGE:
14991555 nh_flags |= RTNH_F_LINKDOWN;
15001556 break;
....@@ -1561,20 +1617,10 @@
15611617 unsigned int flags;
15621618
15631619 if (event == NETDEV_REGISTER) {
1620
+ mdev = mpls_add_dev(dev);
1621
+ if (IS_ERR(mdev))
1622
+ return notifier_from_errno(PTR_ERR(mdev));
15641623
1565
- /* For now just support Ethernet, IPGRE, IP6GRE, SIT and
1566
- * IPIP devices
1567
- */
1568
- if (dev->type == ARPHRD_ETHER ||
1569
- dev->type == ARPHRD_LOOPBACK ||
1570
- dev->type == ARPHRD_IPGRE ||
1571
- dev->type == ARPHRD_IP6GRE ||
1572
- dev->type == ARPHRD_SIT ||
1573
- dev->type == ARPHRD_TUNNEL) {
1574
- mdev = mpls_add_dev(dev);
1575
- if (IS_ERR(mdev))
1576
- return notifier_from_errno(PTR_ERR(mdev));
1577
- }
15781624 return NOTIFY_OK;
15791625 }
15801626
....@@ -1771,8 +1817,8 @@
17711817 int index;
17721818 int err;
17731819
1774
- err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy,
1775
- extack);
1820
+ err = nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
1821
+ rtm_mpls_policy, extack);
17761822 if (err < 0)
17771823 goto errout;
17781824
....@@ -2000,7 +2046,7 @@
20002046 u8 linkdown = 0;
20012047 u8 dead = 0;
20022048
2003
- mp = nla_nest_start(skb, RTA_MULTIPATH);
2049
+ mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
20042050 if (!mp)
20052051 goto nla_put_failure;
20062052
....@@ -2053,14 +2099,115 @@
20532099 return -EMSGSIZE;
20542100 }
20552101
2102
+#if IS_ENABLED(CONFIG_INET)
2103
+static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
2104
+ struct fib_dump_filter *filter,
2105
+ struct netlink_callback *cb)
2106
+{
2107
+ return ip_valid_fib_dump_req(net, nlh, filter, cb);
2108
+}
2109
+#else
2110
+static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
2111
+ struct fib_dump_filter *filter,
2112
+ struct netlink_callback *cb)
2113
+{
2114
+ struct netlink_ext_ack *extack = cb->extack;
2115
+ struct nlattr *tb[RTA_MAX + 1];
2116
+ struct rtmsg *rtm;
2117
+ int err, i;
2118
+
2119
+ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
2120
+ NL_SET_ERR_MSG_MOD(extack, "Invalid header for FIB dump request");
2121
+ return -EINVAL;
2122
+ }
2123
+
2124
+ rtm = nlmsg_data(nlh);
2125
+ if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos ||
2126
+ rtm->rtm_table || rtm->rtm_scope || rtm->rtm_type ||
2127
+ rtm->rtm_flags) {
2128
+ NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for FIB dump request");
2129
+ return -EINVAL;
2130
+ }
2131
+
2132
+ if (rtm->rtm_protocol) {
2133
+ filter->protocol = rtm->rtm_protocol;
2134
+ filter->filter_set = 1;
2135
+ cb->answer_flags = NLM_F_DUMP_FILTERED;
2136
+ }
2137
+
2138
+ err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
2139
+ rtm_mpls_policy, extack);
2140
+ if (err < 0)
2141
+ return err;
2142
+
2143
+ for (i = 0; i <= RTA_MAX; ++i) {
2144
+ int ifindex;
2145
+
2146
+ if (i == RTA_OIF) {
2147
+ ifindex = nla_get_u32(tb[i]);
2148
+ filter->dev = __dev_get_by_index(net, ifindex);
2149
+ if (!filter->dev)
2150
+ return -ENODEV;
2151
+ filter->filter_set = 1;
2152
+ } else if (tb[i]) {
2153
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in dump request");
2154
+ return -EINVAL;
2155
+ }
2156
+ }
2157
+
2158
+ return 0;
2159
+}
2160
+#endif
2161
+
2162
+static bool mpls_rt_uses_dev(struct mpls_route *rt,
2163
+ const struct net_device *dev)
2164
+{
2165
+ struct net_device *nh_dev;
2166
+
2167
+ if (rt->rt_nhn == 1) {
2168
+ struct mpls_nh *nh = rt->rt_nh;
2169
+
2170
+ nh_dev = rtnl_dereference(nh->nh_dev);
2171
+ if (dev == nh_dev)
2172
+ return true;
2173
+ } else {
2174
+ for_nexthops(rt) {
2175
+ nh_dev = rtnl_dereference(nh->nh_dev);
2176
+ if (nh_dev == dev)
2177
+ return true;
2178
+ } endfor_nexthops(rt);
2179
+ }
2180
+
2181
+ return false;
2182
+}
2183
+
20562184 static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
20572185 {
2186
+ const struct nlmsghdr *nlh = cb->nlh;
20582187 struct net *net = sock_net(skb->sk);
20592188 struct mpls_route __rcu **platform_label;
2189
+ struct fib_dump_filter filter = {};
2190
+ unsigned int flags = NLM_F_MULTI;
20602191 size_t platform_labels;
20612192 unsigned int index;
20622193
20632194 ASSERT_RTNL();
2195
+
2196
+ if (cb->strict_check) {
2197
+ int err;
2198
+
2199
+ err = mpls_valid_fib_dump_req(net, nlh, &filter, cb);
2200
+ if (err < 0)
2201
+ return err;
2202
+
2203
+ /* for MPLS, there is only 1 table with fixed type and flags.
2204
+ * If either are set in the filter then return nothing.
2205
+ */
2206
+ if ((filter.table_id && filter.table_id != RT_TABLE_MAIN) ||
2207
+ (filter.rt_type && filter.rt_type != RTN_UNICAST) ||
2208
+ filter.flags)
2209
+ return skb->len;
2210
+ }
20642211
20652212 index = cb->args[0];
20662213 if (index < MPLS_LABEL_FIRST_UNRESERVED)
....@@ -2068,15 +2215,24 @@
20682215
20692216 platform_label = rtnl_dereference(net->mpls.platform_label);
20702217 platform_labels = net->mpls.platform_labels;
2218
+
2219
+ if (filter.filter_set)
2220
+ flags |= NLM_F_DUMP_FILTERED;
2221
+
20712222 for (; index < platform_labels; index++) {
20722223 struct mpls_route *rt;
2224
+
20732225 rt = rtnl_dereference(platform_label[index]);
20742226 if (!rt)
20752227 continue;
20762228
2229
+ if ((filter.dev && !mpls_rt_uses_dev(rt, filter.dev)) ||
2230
+ (filter.protocol && rt->rt_protocol != filter.protocol))
2231
+ continue;
2232
+
20772233 if (mpls_dump_route(skb, NETLINK_CB(cb->skb).portid,
20782234 cb->nlh->nlmsg_seq, RTM_NEWROUTE,
2079
- index, rt, NLM_F_MULTI) < 0)
2235
+ index, rt, flags) < 0)
20802236 break;
20812237 }
20822238 cb->args[0] = index;
....@@ -2148,6 +2304,64 @@
21482304 rtnl_set_sk_err(net, RTNLGRP_MPLS_ROUTE, err);
21492305 }
21502306
2307
+static int mpls_valid_getroute_req(struct sk_buff *skb,
2308
+ const struct nlmsghdr *nlh,
2309
+ struct nlattr **tb,
2310
+ struct netlink_ext_ack *extack)
2311
+{
2312
+ struct rtmsg *rtm;
2313
+ int i, err;
2314
+
2315
+ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
2316
+ NL_SET_ERR_MSG_MOD(extack,
2317
+ "Invalid header for get route request");
2318
+ return -EINVAL;
2319
+ }
2320
+
2321
+ if (!netlink_strict_get_check(skb))
2322
+ return nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
2323
+ rtm_mpls_policy, extack);
2324
+
2325
+ rtm = nlmsg_data(nlh);
2326
+ if ((rtm->rtm_dst_len && rtm->rtm_dst_len != 20) ||
2327
+ rtm->rtm_src_len || rtm->rtm_tos || rtm->rtm_table ||
2328
+ rtm->rtm_protocol || rtm->rtm_scope || rtm->rtm_type) {
2329
+ NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
2330
+ return -EINVAL;
2331
+ }
2332
+ if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
2333
+ NL_SET_ERR_MSG_MOD(extack,
2334
+ "Invalid flags for get route request");
2335
+ return -EINVAL;
2336
+ }
2337
+
2338
+ err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
2339
+ rtm_mpls_policy, extack);
2340
+ if (err)
2341
+ return err;
2342
+
2343
+ if ((tb[RTA_DST] || tb[RTA_NEWDST]) && !rtm->rtm_dst_len) {
2344
+ NL_SET_ERR_MSG_MOD(extack, "rtm_dst_len must be 20 for MPLS");
2345
+ return -EINVAL;
2346
+ }
2347
+
2348
+ for (i = 0; i <= RTA_MAX; i++) {
2349
+ if (!tb[i])
2350
+ continue;
2351
+
2352
+ switch (i) {
2353
+ case RTA_DST:
2354
+ case RTA_NEWDST:
2355
+ break;
2356
+ default:
2357
+ NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
2358
+ return -EINVAL;
2359
+ }
2360
+ }
2361
+
2362
+ return 0;
2363
+}
2364
+
21512365 static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
21522366 struct netlink_ext_ack *extack)
21532367 {
....@@ -2167,8 +2381,7 @@
21672381 u8 n_labels;
21682382 int err;
21692383
2170
- err = nlmsg_parse(in_nlh, sizeof(*rtm), tb, RTA_MAX,
2171
- rtm_mpls_policy, extack);
2384
+ err = mpls_valid_getroute_req(in_skb, in_nlh, tb, extack);
21722385 if (err < 0)
21732386 goto errout;
21742387
....@@ -2410,7 +2623,7 @@
24102623 }
24112624
24122625 static int mpls_platform_labels(struct ctl_table *table, int write,
2413
- void __user *buffer, size_t *lenp, loff_t *ppos)
2626
+ void *buffer, size_t *lenp, loff_t *ppos)
24142627 {
24152628 struct net *net = table->data;
24162629 int platform_labels = net->mpls.platform_labels;
....@@ -2420,7 +2633,7 @@
24202633 .data = &platform_labels,
24212634 .maxlen = sizeof(int),
24222635 .mode = table->mode,
2423
- .extra1 = &zero,
2636
+ .extra1 = SYSCTL_ZERO,
24242637 .extra2 = &label_limit,
24252638 };
24262639
....@@ -2449,8 +2662,8 @@
24492662 .maxlen = sizeof(int),
24502663 .mode = 0644,
24512664 .proc_handler = proc_dointvec_minmax,
2452
- .extra1 = &zero,
2453
- .extra2 = &one,
2665
+ .extra1 = SYSCTL_ZERO,
2666
+ .extra2 = SYSCTL_ONE,
24542667 },
24552668 {
24562669 .procname = "default_ttl",
....@@ -2458,7 +2671,7 @@
24582671 .maxlen = sizeof(int),
24592672 .mode = 0644,
24602673 .proc_handler = proc_dointvec_minmax,
2461
- .extra1 = &one,
2674
+ .extra1 = SYSCTL_ONE,
24622675 .extra2 = &ttl_max,
24632676 },
24642677 { }