diff options
-rw-r--r-- | include/net/fib_rules.h | 3 | ||||
-rw-r--r-- | net/core/fib_rules.c | 55 | ||||
-rw-r--r-- | net/decnet/dn_rules.c | 7 | ||||
-rw-r--r-- | net/ipv4/fib_rules.c | 7 | ||||
-rw-r--r-- | net/ipv4/ipmr.c | 3 | ||||
-rw-r--r-- | net/ipv6/fib6_rules.c | 7 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 3 |
7 files changed, 63 insertions, 22 deletions
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index e5cfcfc7dd93..b473df5b9512 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h | |||
@@ -75,7 +75,8 @@ struct fib_rules_ops { | |||
75 | int (*configure)(struct fib_rule *, | 75 | int (*configure)(struct fib_rule *, |
76 | struct sk_buff *, | 76 | struct sk_buff *, |
77 | struct fib_rule_hdr *, | 77 | struct fib_rule_hdr *, |
78 | struct nlattr **); | 78 | struct nlattr **, |
79 | struct netlink_ext_ack *); | ||
79 | int (*delete)(struct fib_rule *); | 80 | int (*delete)(struct fib_rule *); |
80 | int (*compare)(struct fib_rule *, | 81 | int (*compare)(struct fib_rule *, |
81 | struct fib_rule_hdr *, | 82 | struct fib_rule_hdr *, |
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 67801104e9a8..ebd9351b213a 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c | |||
@@ -469,14 +469,18 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
469 | if (frh->src_len) | 469 | if (frh->src_len) |
470 | if (!tb[FRA_SRC] || | 470 | if (!tb[FRA_SRC] || |
471 | frh->src_len > (ops->addr_size * 8) || | 471 | frh->src_len > (ops->addr_size * 8) || |
472 | nla_len(tb[FRA_SRC]) != ops->addr_size) | 472 | nla_len(tb[FRA_SRC]) != ops->addr_size) { |
473 | NL_SET_ERR_MSG(extack, "Invalid source address"); | ||
473 | goto errout; | 474 | goto errout; |
475 | } | ||
474 | 476 | ||
475 | if (frh->dst_len) | 477 | if (frh->dst_len) |
476 | if (!tb[FRA_DST] || | 478 | if (!tb[FRA_DST] || |
477 | frh->dst_len > (ops->addr_size * 8) || | 479 | frh->dst_len > (ops->addr_size * 8) || |
478 | nla_len(tb[FRA_DST]) != ops->addr_size) | 480 | nla_len(tb[FRA_DST]) != ops->addr_size) { |
481 | NL_SET_ERR_MSG(extack, "Invalid dst address"); | ||
479 | goto errout; | 482 | goto errout; |
483 | } | ||
480 | 484 | ||
481 | nlrule = kzalloc(ops->rule_size, GFP_KERNEL); | 485 | nlrule = kzalloc(ops->rule_size, GFP_KERNEL); |
482 | if (!nlrule) { | 486 | if (!nlrule) { |
@@ -537,6 +541,7 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
537 | nlrule->l3mdev = nla_get_u8(tb[FRA_L3MDEV]); | 541 | nlrule->l3mdev = nla_get_u8(tb[FRA_L3MDEV]); |
538 | if (nlrule->l3mdev != 1) | 542 | if (nlrule->l3mdev != 1) |
539 | #endif | 543 | #endif |
544 | NL_SET_ERR_MSG(extack, "Invalid l3mdev"); | ||
540 | goto errout_free; | 545 | goto errout_free; |
541 | } | 546 | } |
542 | 547 | ||
@@ -554,31 +559,41 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
554 | nlrule->suppress_ifgroup = -1; | 559 | nlrule->suppress_ifgroup = -1; |
555 | 560 | ||
556 | if (tb[FRA_GOTO]) { | 561 | if (tb[FRA_GOTO]) { |
557 | if (nlrule->action != FR_ACT_GOTO) | 562 | if (nlrule->action != FR_ACT_GOTO) { |
563 | NL_SET_ERR_MSG(extack, "Unexpected goto"); | ||
558 | goto errout_free; | 564 | goto errout_free; |
565 | } | ||
559 | 566 | ||
560 | nlrule->target = nla_get_u32(tb[FRA_GOTO]); | 567 | nlrule->target = nla_get_u32(tb[FRA_GOTO]); |
561 | /* Backward jumps are prohibited to avoid endless loops */ | 568 | /* Backward jumps are prohibited to avoid endless loops */ |
562 | if (nlrule->target <= nlrule->pref) | 569 | if (nlrule->target <= nlrule->pref) { |
570 | NL_SET_ERR_MSG(extack, "Backward goto not supported"); | ||
563 | goto errout_free; | 571 | goto errout_free; |
572 | } | ||
564 | } else if (nlrule->action == FR_ACT_GOTO) { | 573 | } else if (nlrule->action == FR_ACT_GOTO) { |
574 | NL_SET_ERR_MSG(extack, "Missing goto target for action goto"); | ||
565 | goto errout_free; | 575 | goto errout_free; |
566 | } | 576 | } |
567 | 577 | ||
568 | if (nlrule->l3mdev && nlrule->table) | 578 | if (nlrule->l3mdev && nlrule->table) { |
579 | NL_SET_ERR_MSG(extack, "l3mdev and table are mutually exclusive"); | ||
569 | goto errout_free; | 580 | goto errout_free; |
581 | } | ||
570 | 582 | ||
571 | if (tb[FRA_UID_RANGE]) { | 583 | if (tb[FRA_UID_RANGE]) { |
572 | if (current_user_ns() != net->user_ns) { | 584 | if (current_user_ns() != net->user_ns) { |
573 | err = -EPERM; | 585 | err = -EPERM; |
586 | NL_SET_ERR_MSG(extack, "No permission to set uid"); | ||
574 | goto errout_free; | 587 | goto errout_free; |
575 | } | 588 | } |
576 | 589 | ||
577 | nlrule->uid_range = nla_get_kuid_range(tb); | 590 | nlrule->uid_range = nla_get_kuid_range(tb); |
578 | 591 | ||
579 | if (!uid_range_set(&nlrule->uid_range) || | 592 | if (!uid_range_set(&nlrule->uid_range) || |
580 | !uid_lte(nlrule->uid_range.start, nlrule->uid_range.end)) | 593 | !uid_lte(nlrule->uid_range.start, nlrule->uid_range.end)) { |
594 | NL_SET_ERR_MSG(extack, "Invalid uid range"); | ||
581 | goto errout_free; | 595 | goto errout_free; |
596 | } | ||
582 | } else { | 597 | } else { |
583 | nlrule->uid_range = fib_kuid_range_unset; | 598 | nlrule->uid_range = fib_kuid_range_unset; |
584 | } | 599 | } |
@@ -589,15 +604,19 @@ static int fib_nl2rule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
589 | if (tb[FRA_SPORT_RANGE]) { | 604 | if (tb[FRA_SPORT_RANGE]) { |
590 | err = nla_get_port_range(tb[FRA_SPORT_RANGE], | 605 | err = nla_get_port_range(tb[FRA_SPORT_RANGE], |
591 | &nlrule->sport_range); | 606 | &nlrule->sport_range); |
592 | if (err) | 607 | if (err) { |
608 | NL_SET_ERR_MSG(extack, "Invalid sport range"); | ||
593 | goto errout_free; | 609 | goto errout_free; |
610 | } | ||
594 | } | 611 | } |
595 | 612 | ||
596 | if (tb[FRA_DPORT_RANGE]) { | 613 | if (tb[FRA_DPORT_RANGE]) { |
597 | err = nla_get_port_range(tb[FRA_DPORT_RANGE], | 614 | err = nla_get_port_range(tb[FRA_DPORT_RANGE], |
598 | &nlrule->dport_range); | 615 | &nlrule->dport_range); |
599 | if (err) | 616 | if (err) { |
617 | NL_SET_ERR_MSG(extack, "Invalid dport range"); | ||
600 | goto errout_free; | 618 | goto errout_free; |
619 | } | ||
601 | } | 620 | } |
602 | 621 | ||
603 | *rule = nlrule; | 622 | *rule = nlrule; |
@@ -621,18 +640,23 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
621 | int err = -EINVAL, unresolved = 0; | 640 | int err = -EINVAL, unresolved = 0; |
622 | bool user_priority = false; | 641 | bool user_priority = false; |
623 | 642 | ||
624 | if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) | 643 | if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) { |
644 | NL_SET_ERR_MSG(extack, "Invalid msg length"); | ||
625 | goto errout; | 645 | goto errout; |
646 | } | ||
626 | 647 | ||
627 | ops = lookup_rules_ops(net, frh->family); | 648 | ops = lookup_rules_ops(net, frh->family); |
628 | if (!ops) { | 649 | if (!ops) { |
629 | err = -EAFNOSUPPORT; | 650 | err = -EAFNOSUPPORT; |
651 | NL_SET_ERR_MSG(extack, "Rule family not supported"); | ||
630 | goto errout; | 652 | goto errout; |
631 | } | 653 | } |
632 | 654 | ||
633 | err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); | 655 | err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); |
634 | if (err < 0) | 656 | if (err < 0) { |
657 | NL_SET_ERR_MSG(extack, "Error parsing msg"); | ||
635 | goto errout; | 658 | goto errout; |
659 | } | ||
636 | 660 | ||
637 | err = fib_nl2rule(skb, nlh, extack, ops, tb, &rule, &user_priority); | 661 | err = fib_nl2rule(skb, nlh, extack, ops, tb, &rule, &user_priority); |
638 | if (err) | 662 | if (err) |
@@ -644,7 +668,7 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
644 | goto errout_free; | 668 | goto errout_free; |
645 | } | 669 | } |
646 | 670 | ||
647 | err = ops->configure(rule, skb, frh, tb); | 671 | err = ops->configure(rule, skb, frh, tb, extack); |
648 | if (err < 0) | 672 | if (err < 0) |
649 | goto errout_free; | 673 | goto errout_free; |
650 | 674 | ||
@@ -723,18 +747,23 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
723 | int err = -EINVAL; | 747 | int err = -EINVAL; |
724 | bool user_priority = false; | 748 | bool user_priority = false; |
725 | 749 | ||
726 | if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) | 750 | if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*frh))) { |
751 | NL_SET_ERR_MSG(extack, "Invalid msg length"); | ||
727 | goto errout; | 752 | goto errout; |
753 | } | ||
728 | 754 | ||
729 | ops = lookup_rules_ops(net, frh->family); | 755 | ops = lookup_rules_ops(net, frh->family); |
730 | if (ops == NULL) { | 756 | if (ops == NULL) { |
731 | err = -EAFNOSUPPORT; | 757 | err = -EAFNOSUPPORT; |
758 | NL_SET_ERR_MSG(extack, "Rule family not supported"); | ||
732 | goto errout; | 759 | goto errout; |
733 | } | 760 | } |
734 | 761 | ||
735 | err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); | 762 | err = nlmsg_parse(nlh, sizeof(*frh), tb, FRA_MAX, ops->policy, extack); |
736 | if (err < 0) | 763 | if (err < 0) { |
764 | NL_SET_ERR_MSG(extack, "Error parsing msg"); | ||
737 | goto errout; | 765 | goto errout; |
766 | } | ||
738 | 767 | ||
739 | err = fib_nl2rule(skb, nlh, extack, ops, tb, &nlrule, &user_priority); | 768 | err = fib_nl2rule(skb, nlh, extack, ops, tb, &nlrule, &user_priority); |
740 | if (err) | 769 | if (err) |
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index c795c3f509c9..72236695db3d 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c | |||
@@ -121,13 +121,16 @@ static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | |||
121 | 121 | ||
122 | static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | 122 | static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
123 | struct fib_rule_hdr *frh, | 123 | struct fib_rule_hdr *frh, |
124 | struct nlattr **tb) | 124 | struct nlattr **tb, |
125 | struct netlink_ext_ack *extack) | ||
125 | { | 126 | { |
126 | int err = -EINVAL; | 127 | int err = -EINVAL; |
127 | struct dn_fib_rule *r = (struct dn_fib_rule *)rule; | 128 | struct dn_fib_rule *r = (struct dn_fib_rule *)rule; |
128 | 129 | ||
129 | if (frh->tos) | 130 | if (frh->tos) { |
131 | NL_SET_ERR_MSG(extack, "Invalid tos value"); | ||
130 | goto errout; | 132 | goto errout; |
133 | } | ||
131 | 134 | ||
132 | if (rule->table == RT_TABLE_UNSPEC) { | 135 | if (rule->table == RT_TABLE_UNSPEC) { |
133 | if (rule->action == FR_ACT_TO_TBL) { | 136 | if (rule->action == FR_ACT_TO_TBL) { |
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 737d11bc8838..f8eb78d042a4 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c | |||
@@ -213,14 +213,17 @@ static const struct nla_policy fib4_rule_policy[FRA_MAX+1] = { | |||
213 | 213 | ||
214 | static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | 214 | static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
215 | struct fib_rule_hdr *frh, | 215 | struct fib_rule_hdr *frh, |
216 | struct nlattr **tb) | 216 | struct nlattr **tb, |
217 | struct netlink_ext_ack *extack) | ||
217 | { | 218 | { |
218 | struct net *net = sock_net(skb->sk); | 219 | struct net *net = sock_net(skb->sk); |
219 | int err = -EINVAL; | 220 | int err = -EINVAL; |
220 | struct fib4_rule *rule4 = (struct fib4_rule *) rule; | 221 | struct fib4_rule *rule4 = (struct fib4_rule *) rule; |
221 | 222 | ||
222 | if (frh->tos & ~IPTOS_TOS_MASK) | 223 | if (frh->tos & ~IPTOS_TOS_MASK) { |
224 | NL_SET_ERR_MSG(extack, "Invalid tos"); | ||
223 | goto errout; | 225 | goto errout; |
226 | } | ||
224 | 227 | ||
225 | /* split local/main if they are not already split */ | 228 | /* split local/main if they are not already split */ |
226 | err = fib_unmerge(net); | 229 | err = fib_unmerge(net); |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 2fb4de3f7f66..38e092eafc97 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -201,7 +201,8 @@ static const struct nla_policy ipmr_rule_policy[FRA_MAX + 1] = { | |||
201 | }; | 201 | }; |
202 | 202 | ||
203 | static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | 203 | static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
204 | struct fib_rule_hdr *frh, struct nlattr **tb) | 204 | struct fib_rule_hdr *frh, struct nlattr **tb, |
205 | struct netlink_ext_ack *extack) | ||
205 | { | 206 | { |
206 | return 0; | 207 | return 0; |
207 | } | 208 | } |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index df113c7b5fc8..6547fc6491a6 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -245,15 +245,18 @@ static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = { | |||
245 | 245 | ||
246 | static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | 246 | static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
247 | struct fib_rule_hdr *frh, | 247 | struct fib_rule_hdr *frh, |
248 | struct nlattr **tb) | 248 | struct nlattr **tb, |
249 | struct netlink_ext_ack *extack) | ||
249 | { | 250 | { |
250 | int err = -EINVAL; | 251 | int err = -EINVAL; |
251 | struct net *net = sock_net(skb->sk); | 252 | struct net *net = sock_net(skb->sk); |
252 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | 253 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; |
253 | 254 | ||
254 | if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) { | 255 | if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) { |
255 | if (rule->table == RT6_TABLE_UNSPEC) | 256 | if (rule->table == RT6_TABLE_UNSPEC) { |
257 | NL_SET_ERR_MSG(extack, "Invalid table"); | ||
256 | goto errout; | 258 | goto errout; |
259 | } | ||
257 | 260 | ||
258 | if (fib6_new_table(net, rule->table) == NULL) { | 261 | if (fib6_new_table(net, rule->table) == NULL) { |
259 | err = -ENOBUFS; | 262 | err = -ENOBUFS; |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 298fd8b6ed17..20a419ee8000 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -180,7 +180,8 @@ static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = { | |||
180 | }; | 180 | }; |
181 | 181 | ||
182 | static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | 182 | static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
183 | struct fib_rule_hdr *frh, struct nlattr **tb) | 183 | struct fib_rule_hdr *frh, struct nlattr **tb, |
184 | struct netlink_ext_ack *extack) | ||
184 | { | 185 | { |
185 | return 0; | 186 | return 0; |
186 | } | 187 | } |