diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 21 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 21 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 21 |
3 files changed, 57 insertions, 6 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 064082dffafb..7bc11ffbb845 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -533,6 +533,21 @@ out: | |||
533 | return ret; | 533 | return ret; |
534 | } | 534 | } |
535 | 535 | ||
536 | static bool check_underflow(struct arpt_entry *e) | ||
537 | { | ||
538 | const struct arpt_entry_target *t; | ||
539 | unsigned int verdict; | ||
540 | |||
541 | if (!unconditional(&e->arp)) | ||
542 | return false; | ||
543 | t = arpt_get_target(e); | ||
544 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) | ||
545 | return false; | ||
546 | verdict = ((struct arpt_standard_target *)t)->verdict; | ||
547 | verdict = -verdict - 1; | ||
548 | return verdict == NF_DROP || verdict == NF_ACCEPT; | ||
549 | } | ||
550 | |||
536 | static inline int check_entry_size_and_hooks(struct arpt_entry *e, | 551 | static inline int check_entry_size_and_hooks(struct arpt_entry *e, |
537 | struct xt_table_info *newinfo, | 552 | struct xt_table_info *newinfo, |
538 | unsigned char *base, | 553 | unsigned char *base, |
@@ -564,8 +579,10 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, | |||
564 | if ((unsigned char *)e - base == hook_entries[h]) | 579 | if ((unsigned char *)e - base == hook_entries[h]) |
565 | newinfo->hook_entry[h] = hook_entries[h]; | 580 | newinfo->hook_entry[h] = hook_entries[h]; |
566 | if ((unsigned char *)e - base == underflows[h]) { | 581 | if ((unsigned char *)e - base == underflows[h]) { |
567 | if (!unconditional(&e->arp)) { | 582 | if (!check_underflow(e)) { |
568 | pr_err("Underflows must be unconditional\n"); | 583 | pr_err("Underflows must be unconditional and " |
584 | "use the STANDARD target with " | ||
585 | "ACCEPT/DROP\n"); | ||
569 | return -EINVAL; | 586 | return -EINVAL; |
570 | } | 587 | } |
571 | newinfo->underflow[h] = underflows[h]; | 588 | newinfo->underflow[h] = underflows[h]; |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 6e546d573d9c..0b43fd7ca04a 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -708,6 +708,21 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size, | |||
708 | return ret; | 708 | return ret; |
709 | } | 709 | } |
710 | 710 | ||
711 | static bool check_underflow(struct ipt_entry *e) | ||
712 | { | ||
713 | const struct ipt_entry_target *t; | ||
714 | unsigned int verdict; | ||
715 | |||
716 | if (!unconditional(&e->ip)) | ||
717 | return false; | ||
718 | t = ipt_get_target(e); | ||
719 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) | ||
720 | return false; | ||
721 | verdict = ((struct ipt_standard_target *)t)->verdict; | ||
722 | verdict = -verdict - 1; | ||
723 | return verdict == NF_DROP || verdict == NF_ACCEPT; | ||
724 | } | ||
725 | |||
711 | static int | 726 | static int |
712 | check_entry_size_and_hooks(struct ipt_entry *e, | 727 | check_entry_size_and_hooks(struct ipt_entry *e, |
713 | struct xt_table_info *newinfo, | 728 | struct xt_table_info *newinfo, |
@@ -740,8 +755,10 @@ check_entry_size_and_hooks(struct ipt_entry *e, | |||
740 | if ((unsigned char *)e - base == hook_entries[h]) | 755 | if ((unsigned char *)e - base == hook_entries[h]) |
741 | newinfo->hook_entry[h] = hook_entries[h]; | 756 | newinfo->hook_entry[h] = hook_entries[h]; |
742 | if ((unsigned char *)e - base == underflows[h]) { | 757 | if ((unsigned char *)e - base == underflows[h]) { |
743 | if (!unconditional(&e->ip)) { | 758 | if (!check_underflow(e)) { |
744 | pr_err("Underflows must be unconditional\n"); | 759 | pr_err("Underflows must be unconditional and " |
760 | "use the STANDARD target with " | ||
761 | "ACCEPT/DROP\n"); | ||
745 | return -EINVAL; | 762 | return -EINVAL; |
746 | } | 763 | } |
747 | newinfo->underflow[h] = underflows[h]; | 764 | newinfo->underflow[h] = underflows[h]; |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index b0599b98d1b6..a5d0c27cc26f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -740,6 +740,21 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
740 | return ret; | 740 | return ret; |
741 | } | 741 | } |
742 | 742 | ||
743 | static bool check_underflow(struct ip6t_entry *e) | ||
744 | { | ||
745 | const struct ip6t_entry_target *t; | ||
746 | unsigned int verdict; | ||
747 | |||
748 | if (!unconditional(&e->ipv6)) | ||
749 | return false; | ||
750 | t = ip6t_get_target(e); | ||
751 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) | ||
752 | return false; | ||
753 | verdict = ((struct ip6t_standard_target *)t)->verdict; | ||
754 | verdict = -verdict - 1; | ||
755 | return verdict == NF_DROP || verdict == NF_ACCEPT; | ||
756 | } | ||
757 | |||
743 | static int | 758 | static int |
744 | check_entry_size_and_hooks(struct ip6t_entry *e, | 759 | check_entry_size_and_hooks(struct ip6t_entry *e, |
745 | struct xt_table_info *newinfo, | 760 | struct xt_table_info *newinfo, |
@@ -772,8 +787,10 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
772 | if ((unsigned char *)e - base == hook_entries[h]) | 787 | if ((unsigned char *)e - base == hook_entries[h]) |
773 | newinfo->hook_entry[h] = hook_entries[h]; | 788 | newinfo->hook_entry[h] = hook_entries[h]; |
774 | if ((unsigned char *)e - base == underflows[h]) { | 789 | if ((unsigned char *)e - base == underflows[h]) { |
775 | if (!unconditional(&e->ipv6)) { | 790 | if (!check_underflow(e)) { |
776 | pr_err("Underflows must be unconditional\n"); | 791 | pr_err("Underflows must be unconditional and " |
792 | "use the STANDARD target with " | ||
793 | "ACCEPT/DROP\n"); | ||
777 | return -EINVAL; | 794 | return -EINVAL; |
778 | } | 795 | } |
779 | newinfo->underflow[h] = underflows[h]; | 796 | newinfo->underflow[h] = underflows[h]; |