]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
netfilter: xtables: check for standard verdicts in policies
authorJan Engelhardt <jengelh@medozas.de>
Sat, 18 Jul 2009 13:22:30 +0000 (15:22 +0200)
committerJan Engelhardt <jengelh@medozas.de>
Mon, 10 Aug 2009 11:35:31 +0000 (13:35 +0200)
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>
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv6/netfilter/ip6_tables.c

index 064082dffafbf7f2c2bd8908b6ee7c6729591109..7bc11ffbb845319f9835528b8bff921cd3f24e37 100644 (file)
@@ -533,6 +533,21 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size,
        return ret;
 }
 
+static bool check_underflow(struct arpt_entry *e)
+{
+       const struct arpt_entry_target *t;
+       unsigned int verdict;
+
+       if (!unconditional(&e->arp))
+               return false;
+       t = arpt_get_target(e);
+       if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
+               return false;
+       verdict = ((struct arpt_standard_target *)t)->verdict;
+       verdict = -verdict - 1;
+       return verdict == NF_DROP || verdict == NF_ACCEPT;
+}
+
 static inline int check_entry_size_and_hooks(struct arpt_entry *e,
                                             struct xt_table_info *newinfo,
                                             unsigned char *base,
@@ -564,8 +579,10 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
                if ((unsigned char *)e - base == hook_entries[h])
                        newinfo->hook_entry[h] = hook_entries[h];
                if ((unsigned char *)e - base == underflows[h]) {
-                       if (!unconditional(&e->arp)) {
-                               pr_err("Underflows must be unconditional\n");
+                       if (!check_underflow(e)) {
+                               pr_err("Underflows must be unconditional and "
+                                      "use the STANDARD target with "
+                                      "ACCEPT/DROP\n");
                                return -EINVAL;
                        }
                        newinfo->underflow[h] = underflows[h];
index 6e546d573d9ce9278cdc7e77e976d2d91a125356..0b43fd7ca04aa7ca3828f677ecf34b9359d2875f 100644 (file)
@@ -708,6 +708,21 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
        return ret;
 }
 
+static bool check_underflow(struct ipt_entry *e)
+{
+       const struct ipt_entry_target *t;
+       unsigned int verdict;
+
+       if (!unconditional(&e->ip))
+               return false;
+       t = ipt_get_target(e);
+       if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
+               return false;
+       verdict = ((struct ipt_standard_target *)t)->verdict;
+       verdict = -verdict - 1;
+       return verdict == NF_DROP || verdict == NF_ACCEPT;
+}
+
 static int
 check_entry_size_and_hooks(struct ipt_entry *e,
                           struct xt_table_info *newinfo,
@@ -740,8 +755,10 @@ check_entry_size_and_hooks(struct ipt_entry *e,
                if ((unsigned char *)e - base == hook_entries[h])
                        newinfo->hook_entry[h] = hook_entries[h];
                if ((unsigned char *)e - base == underflows[h]) {
-                       if (!unconditional(&e->ip)) {
-                               pr_err("Underflows must be unconditional\n");
+                       if (!check_underflow(e)) {
+                               pr_err("Underflows must be unconditional and "
+                                      "use the STANDARD target with "
+                                      "ACCEPT/DROP\n");
                                return -EINVAL;
                        }
                        newinfo->underflow[h] = underflows[h];
index b0599b98d1b65e9b5e83d0f0e5a24c8673024064..a5d0c27cc26f6fd0ea2fdb0fee398b1681a258ef 100644 (file)
@@ -740,6 +740,21 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
        return ret;
 }
 
+static bool check_underflow(struct ip6t_entry *e)
+{
+       const struct ip6t_entry_target *t;
+       unsigned int verdict;
+
+       if (!unconditional(&e->ipv6))
+               return false;
+       t = ip6t_get_target(e);
+       if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
+               return false;
+       verdict = ((struct ip6t_standard_target *)t)->verdict;
+       verdict = -verdict - 1;
+       return verdict == NF_DROP || verdict == NF_ACCEPT;
+}
+
 static int
 check_entry_size_and_hooks(struct ip6t_entry *e,
                           struct xt_table_info *newinfo,
@@ -772,8 +787,10 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
                if ((unsigned char *)e - base == hook_entries[h])
                        newinfo->hook_entry[h] = hook_entries[h];
                if ((unsigned char *)e - base == underflows[h]) {
-                       if (!unconditional(&e->ipv6)) {
-                               pr_err("Underflows must be unconditional\n");
+                       if (!check_underflow(e)) {
+                               pr_err("Underflows must be unconditional and "
+                                      "use the STANDARD target with "
+                                      "ACCEPT/DROP\n");
                                return -EINVAL;
                        }
                        newinfo->underflow[h] = underflows[h];