.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * net/core/fib_rules.c Generic Routing Rules |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or |
---|
5 | | - * modify it under the terms of the GNU General Public License as |
---|
6 | | - * published by the Free Software Foundation, version 2. |
---|
7 | 4 | * |
---|
8 | 5 | * Authors: Thomas Graf <tgraf@suug.ch> |
---|
9 | 6 | */ |
---|
.. | .. |
---|
17 | 14 | #include <net/sock.h> |
---|
18 | 15 | #include <net/fib_rules.h> |
---|
19 | 16 | #include <net/ip_tunnels.h> |
---|
| 17 | +#include <linux/indirect_call_wrapper.h> |
---|
| 18 | + |
---|
| 19 | +#if defined(CONFIG_IPV6) && defined(CONFIG_IPV6_MULTIPLE_TABLES) |
---|
| 20 | +#ifdef CONFIG_IP_MULTIPLE_TABLES |
---|
| 21 | +#define INDIRECT_CALL_MT(f, f2, f1, ...) \ |
---|
| 22 | + INDIRECT_CALL_INET(f, f2, f1, __VA_ARGS__) |
---|
| 23 | +#else |
---|
| 24 | +#define INDIRECT_CALL_MT(f, f2, f1, ...) INDIRECT_CALL_1(f, f2, __VA_ARGS__) |
---|
| 25 | +#endif |
---|
| 26 | +#elif defined(CONFIG_IP_MULTIPLE_TABLES) |
---|
| 27 | +#define INDIRECT_CALL_MT(f, f2, f1, ...) INDIRECT_CALL_1(f, f1, __VA_ARGS__) |
---|
| 28 | +#else |
---|
| 29 | +#define INDIRECT_CALL_MT(f, f2, f1, ...) f(__VA_ARGS__) |
---|
| 30 | +#endif |
---|
20 | 31 | |
---|
21 | 32 | static const struct fib_kuid_range fib_kuid_range_unset = { |
---|
22 | 33 | KUIDT_INIT(0), |
---|
.. | .. |
---|
270 | 281 | uid_gt(fl->flowi_uid, rule->uid_range.end)) |
---|
271 | 282 | goto out; |
---|
272 | 283 | |
---|
273 | | - ret = ops->match(rule, fl, flags); |
---|
| 284 | + ret = INDIRECT_CALL_MT(ops->match, |
---|
| 285 | + fib6_rule_match, |
---|
| 286 | + fib4_rule_match, |
---|
| 287 | + rule, fl, flags); |
---|
274 | 288 | out: |
---|
275 | 289 | return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; |
---|
276 | 290 | } |
---|
.. | .. |
---|
301 | 315 | } else if (rule->action == FR_ACT_NOP) |
---|
302 | 316 | continue; |
---|
303 | 317 | else |
---|
304 | | - err = ops->action(rule, fl, flags, arg); |
---|
| 318 | + err = INDIRECT_CALL_MT(ops->action, |
---|
| 319 | + fib6_rule_action, |
---|
| 320 | + fib4_rule_action, |
---|
| 321 | + rule, fl, flags, arg); |
---|
305 | 322 | |
---|
306 | | - if (!err && ops->suppress && ops->suppress(rule, arg)) |
---|
| 323 | + if (!err && ops->suppress && INDIRECT_CALL_MT(ops->suppress, |
---|
| 324 | + fib6_rule_suppress, |
---|
| 325 | + fib4_rule_suppress, |
---|
| 326 | + rule, flags, arg)) |
---|
307 | 327 | continue; |
---|
308 | 328 | |
---|
309 | 329 | if (err != -EAGAIN) { |
---|
.. | .. |
---|
324 | 344 | } |
---|
325 | 345 | EXPORT_SYMBOL_GPL(fib_rules_lookup); |
---|
326 | 346 | |
---|
327 | | -static int call_fib_rule_notifier(struct notifier_block *nb, struct net *net, |
---|
| 347 | +static int call_fib_rule_notifier(struct notifier_block *nb, |
---|
328 | 348 | enum fib_event_type event_type, |
---|
329 | | - struct fib_rule *rule, int family) |
---|
| 349 | + struct fib_rule *rule, int family, |
---|
| 350 | + struct netlink_ext_ack *extack) |
---|
330 | 351 | { |
---|
331 | 352 | struct fib_rule_notifier_info info = { |
---|
332 | 353 | .info.family = family, |
---|
| 354 | + .info.extack = extack, |
---|
333 | 355 | .rule = rule, |
---|
334 | 356 | }; |
---|
335 | 357 | |
---|
336 | | - return call_fib_notifier(nb, net, event_type, &info.info); |
---|
| 358 | + return call_fib_notifier(nb, event_type, &info.info); |
---|
337 | 359 | } |
---|
338 | 360 | |
---|
339 | 361 | static int call_fib_rule_notifiers(struct net *net, |
---|
.. | .. |
---|
353 | 375 | } |
---|
354 | 376 | |
---|
355 | 377 | /* Called with rcu_read_lock() */ |
---|
356 | | -int fib_rules_dump(struct net *net, struct notifier_block *nb, int family) |
---|
| 378 | +int fib_rules_dump(struct net *net, struct notifier_block *nb, int family, |
---|
| 379 | + struct netlink_ext_ack *extack) |
---|
357 | 380 | { |
---|
358 | 381 | struct fib_rules_ops *ops; |
---|
359 | 382 | struct fib_rule *rule; |
---|
| 383 | + int err = 0; |
---|
360 | 384 | |
---|
361 | 385 | ops = lookup_rules_ops(net, family); |
---|
362 | 386 | if (!ops) |
---|
363 | 387 | return -EAFNOSUPPORT; |
---|
364 | | - list_for_each_entry_rcu(rule, &ops->rules_list, list) |
---|
365 | | - call_fib_rule_notifier(nb, net, FIB_EVENT_RULE_ADD, rule, |
---|
366 | | - family); |
---|
| 388 | + list_for_each_entry_rcu(rule, &ops->rules_list, list) { |
---|
| 389 | + err = call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD, |
---|
| 390 | + rule, family, extack); |
---|
| 391 | + if (err) |
---|
| 392 | + break; |
---|
| 393 | + } |
---|
367 | 394 | rules_ops_put(ops); |
---|
368 | 395 | |
---|
369 | | - return 0; |
---|
| 396 | + return err; |
---|
370 | 397 | } |
---|
371 | 398 | EXPORT_SYMBOL_GPL(fib_rules_dump); |
---|
372 | 399 | |
---|
.. | .. |
---|
746 | 773 | goto errout; |
---|
747 | 774 | } |
---|
748 | 775 | |
---|
749 | | - err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); |
---|
| 776 | + err = nlmsg_parse_deprecated(nlh, sizeof(*frh), tb, FRA_MAX, |
---|
| 777 | + ops->policy, extack); |
---|
750 | 778 | if (err < 0) { |
---|
751 | 779 | NL_SET_ERR_MSG(extack, "Error parsing msg"); |
---|
752 | 780 | goto errout; |
---|
.. | .. |
---|
853 | 881 | goto errout; |
---|
854 | 882 | } |
---|
855 | 883 | |
---|
856 | | - err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); |
---|
| 884 | + err = nlmsg_parse_deprecated(nlh, sizeof(*frh), tb, FRA_MAX, |
---|
| 885 | + ops->policy, extack); |
---|
857 | 886 | if (err < 0) { |
---|
858 | 887 | NL_SET_ERR_MSG(extack, "Error parsing msg"); |
---|
859 | 888 | goto errout; |
---|
.. | .. |
---|
1063 | 1092 | return err; |
---|
1064 | 1093 | } |
---|
1065 | 1094 | |
---|
| 1095 | +static int fib_valid_dumprule_req(const struct nlmsghdr *nlh, |
---|
| 1096 | + struct netlink_ext_ack *extack) |
---|
| 1097 | +{ |
---|
| 1098 | + struct fib_rule_hdr *frh; |
---|
| 1099 | + |
---|
| 1100 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) { |
---|
| 1101 | + NL_SET_ERR_MSG(extack, "Invalid header for fib rule dump request"); |
---|
| 1102 | + return -EINVAL; |
---|
| 1103 | + } |
---|
| 1104 | + |
---|
| 1105 | + frh = nlmsg_data(nlh); |
---|
| 1106 | + if (frh->dst_len || frh->src_len || frh->tos || frh->table || |
---|
| 1107 | + frh->res1 || frh->res2 || frh->action || frh->flags) { |
---|
| 1108 | + NL_SET_ERR_MSG(extack, |
---|
| 1109 | + "Invalid values in header for fib rule dump request"); |
---|
| 1110 | + return -EINVAL; |
---|
| 1111 | + } |
---|
| 1112 | + |
---|
| 1113 | + if (nlmsg_attrlen(nlh, sizeof(*frh))) { |
---|
| 1114 | + NL_SET_ERR_MSG(extack, "Invalid data after header in fib rule dump request"); |
---|
| 1115 | + return -EINVAL; |
---|
| 1116 | + } |
---|
| 1117 | + |
---|
| 1118 | + return 0; |
---|
| 1119 | +} |
---|
| 1120 | + |
---|
1066 | 1121 | static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) |
---|
1067 | 1122 | { |
---|
| 1123 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
1068 | 1124 | struct net *net = sock_net(skb->sk); |
---|
1069 | 1125 | struct fib_rules_ops *ops; |
---|
1070 | 1126 | int idx = 0, family; |
---|
1071 | 1127 | |
---|
1072 | | - family = rtnl_msg_family(cb->nlh); |
---|
| 1128 | + if (cb->strict_check) { |
---|
| 1129 | + int err = fib_valid_dumprule_req(nlh, cb->extack); |
---|
| 1130 | + |
---|
| 1131 | + if (err < 0) |
---|
| 1132 | + return err; |
---|
| 1133 | + } |
---|
| 1134 | + |
---|
| 1135 | + family = rtnl_msg_family(nlh); |
---|
1073 | 1136 | if (family != AF_UNSPEC) { |
---|
1074 | 1137 | /* Protocol specific dump request */ |
---|
1075 | 1138 | ops = lookup_rules_ops(net, family); |
---|