aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2009-07-18 09:22:30 -0400
committerJan Engelhardt <jengelh@medozas.de>2009-08-10 07:35:31 -0400
commite2fe35c17fed62d4ab5038fa9bc489e967ff8416 (patch)
tree84a4b0b688276b6788081f441984abd01d036b4d /net
parent90e7d4ab5c8b0c4c2e00e4893977f6aeec0f18f1 (diff)
netfilter: xtables: check for standard verdicts in policies
This adds the second check that Rusty wanted to have a long time ago. :-) Base chain policies must have absolute verdicts that cease processing in the table, otherwise rule execution may continue in an unexpected spurious fashion (e.g. next chain that follows in memory). Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/netfilter/arp_tables.c21
-rw-r--r--net/ipv4/netfilter/ip_tables.c21
-rw-r--r--net/ipv6/netfilter/ip6_tables.c21
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
536static 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
536static inline int check_entry_size_and_hooks(struct arpt_entry *e, 551static 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
711static 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
711static int 726static int
712check_entry_size_and_hooks(struct ipt_entry *e, 727check_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
743static 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
743static int 758static int
744check_entry_size_and_hooks(struct ip6t_entry *e, 759check_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];