]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xtables: Fix for false-positive rule matching
authorPhil Sutter <phil@nwl.cc>
Mon, 4 Feb 2019 20:52:53 +0000 (21:52 +0100)
committerFlorian Westphal <fw@strlen.de>
Tue, 5 Feb 2019 15:09:41 +0000 (16:09 +0100)
When comparing two rules with non-standard targets, differences in
targets' payloads wasn't respected.

The cause is a rather hideous one: Unlike xtables_find_match(),
xtables_find_target() did not care whether the found target was already
in use or not, so the same target instance was assigned to both rules
and therefore payload comparison happened over the same memory location.

With legacy iptables it is not possible to reuse a target: The only case
where two rules (i.e., iptables_command_state instances) could exist at
the same time is when comparing rules, but that's handled using libiptc.

The above change clashes with ebtables-nft's reuse of target objects:
While input parsing still just assigns the object from xtables_targets
list, rule conversion from nftnl to iptables_command_state allocates new
data. To fix this, make ebtables-nft input parsing use the common
command_jump() routine instead of its own simplified copy. In turn, this
also eliminates the ebtables-nft-specific variants of parse_target(),
though with a slight change of behaviour: Names of user-defined chains
are no longer allowed to contain up to 31 but merely 28 characters.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Florian Westphal <fw@strlen.de>
iptables/nft-bridge.c
iptables/nft-bridge.h
iptables/nft-shared.c
iptables/tests/shell/testcases/iptables/0005-delete-rules_0
iptables/xtables-eb-translate.c
iptables/xtables-eb.c
libxtables/xtables.c

index b4265c8af4f70095c6feea84b35dc53823f598c9..7c390dfa2a898ea7b6a377fadc7a6cd38fbaa7a3 100644 (file)
@@ -45,6 +45,16 @@ void ebt_cs_clean(struct iptables_command_state *cs)
                free(m);
                m = nm;
        }
+
+       if (cs->target) {
+               free(cs->target->t);
+               cs->target->t = NULL;
+
+               if (cs->target == cs->target->next) {
+                       free(cs->target);
+                       cs->target = NULL;
+               }
+       }
 }
 
 static void ebt_print_mac(const unsigned char *mac)
index de52cd7195bbb06cf436f1814229b2e70823e716..d90066f1030a2cc5ef703256044c80bba6694f9b 100644 (file)
@@ -32,7 +32,6 @@ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mas
  */
 
 #define EBT_TABLE_MAXNAMELEN 32
-#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
 #define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
 
 /* verdicts >0 are "branches" */
@@ -122,6 +121,5 @@ void ebt_add_match(struct xtables_match *m,
 void ebt_add_watcher(struct xtables_target *watcher,
                      struct iptables_command_state *cs);
 int ebt_command_default(struct iptables_command_state *cs);
-struct xtables_target *ebt_command_jump(const char *jumpto);
 
 #endif
index 2d4b8d557eb7321aa829f203a003ba05c1068ec7..a72d414d78111351d1f8e565d750e5ed576be0e2 100644 (file)
@@ -687,6 +687,11 @@ void nft_clear_iptables_command_state(struct iptables_command_state *cs)
        if (cs->target) {
                free(cs->target->t);
                cs->target->t = NULL;
+
+               if (cs->target == cs->target->next) {
+                       free(cs->target);
+                       cs->target = NULL;
+               }
        }
 }
 
index 9312fd53c3437c15759d5a0b8f32781331bc7c36..5038cbce5a5cf22e316b12289405e09eb60ac594 100755 (executable)
@@ -5,3 +5,10 @@
 $XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j DROP
 $XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j REJECT
 [[ $? -eq 1 ]] || exit 1
+
+# test incorrect deletion of rules with deviating payload
+# in non-standard target
+
+$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j MARK --set-mark 23
+$XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j MARK --set-mark 42
+[[ $? -eq 1 ]] || exit 1
index f98c385555eb1cef5352408a158df4baa2974df0..0fe14d2d0db320791fcd080b1fa5666abdf2b654 100644 (file)
@@ -64,27 +64,6 @@ static int parse_rule_number(const char *rule)
        return rule_nr;
 }
 
-static const char *
-parse_target(const char *targetname)
-{
-       const char *ptr;
-
-       if (strlen(targetname) < 1)
-               xtables_error(PARAMETER_PROBLEM,
-                             "Invalid target name (too short)");
-
-       if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN)
-               xtables_error(PARAMETER_PROBLEM,
-                             "Invalid target '%s' (%d chars max)",
-                             targetname, EBT_CHAIN_MAXNAMELEN);
-
-       for (ptr = targetname; *ptr; ptr++)
-               if (isspace(*ptr))
-                       xtables_error(PARAMETER_PROBLEM,
-                                     "Invalid target name `%s'", targetname);
-       return targetname;
-}
-
 static int get_current_chain(const char *chain)
 {
        if (strcmp(chain, "PREROUTING") == 0)
@@ -411,8 +390,7 @@ print_zero:
                                break;
                        } else if (c == 'j') {
                                ebt_check_option2(&flags, OPT_JUMP);
-                               cs.jumpto = parse_target(optarg);
-                               cs.target = ebt_command_jump(cs.jumpto);
+                               command_jump(&cs);
                                break;
                        } else if (c == 's') {
                                ebt_check_option2(&flags, OPT_SOURCE);
index b9d98a055e43200dfab2451d941ccf4f8225c590..75d43963d5ef868e2ef6b00e2ba9013447cf9f94 100644 (file)
@@ -139,27 +139,6 @@ static int parse_rule_number(const char *rule)
        return rule_nr;
 }
 
-static const char *
-parse_target(const char *targetname)
-{
-       const char *ptr;
-
-       if (strlen(targetname) < 1)
-               xtables_error(PARAMETER_PROBLEM,
-                             "Invalid target name (too short)");
-
-       if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN)
-               xtables_error(PARAMETER_PROBLEM,
-                             "Invalid target '%s' (%d chars max)",
-                             targetname, EBT_CHAIN_MAXNAMELEN);
-
-       for (ptr = targetname; *ptr; ptr++)
-               if (isspace(*ptr))
-                       xtables_error(PARAMETER_PROBLEM,
-                                     "Invalid target name `%s'", targetname);
-       return targetname;
-}
-
 static int
 append_entry(struct nft_handle *h,
             const char *chain,
@@ -365,29 +344,6 @@ static struct option *merge_options(struct option *oldopts,
        return merge;
 }
 
-/*
- * More glue code.
- */
-struct xtables_target *ebt_command_jump(const char *jumpto)
-{
-       struct xtables_target *target;
-       unsigned int verdict;
-
-       /* Standard target? */
-       if (!ebt_fill_target(jumpto, &verdict))
-               jumpto = "standard";
-
-       /* For ebtables, all targets are preloaded. Hence it is either in
-        * xtables_targets or a custom chain to jump to, in which case
-        * returning NULL is fine. */
-       for (target = xtables_targets; target; target = target->next) {
-               if (!strcmp(target->name, jumpto))
-                       break;
-       }
-
-       return target;
-}
-
 static void print_help(const struct xtables_target *t,
                       const struct xtables_rule_match *m, const char *table)
 {
@@ -1055,8 +1011,7 @@ print_zero:
                        } else if (c == 'j') {
                                ebt_check_option2(&flags, OPT_JUMP);
                                if (strcmp(optarg, "CONTINUE") != 0) {
-                                       cs.jumpto = parse_target(optarg);
-                                       cs.target = ebt_command_jump(cs.jumpto);
+                                       command_jump(&cs);
                                }
                                break;
                        } else if (c == 's') {
index ea9bb102c8eb4abb3c1250481d1da8c0e6f1932d..895f6988eaf57048d54458274728a5ce9d318234 100644 (file)
@@ -756,8 +756,24 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
        }
 
        for (ptr = xtables_targets; ptr; ptr = ptr->next) {
-               if (extension_cmp(name, ptr->name, ptr->family))
+               if (extension_cmp(name, ptr->name, ptr->family)) {
+                       struct xtables_target *clone;
+
+                       /* First target of this type: */
+                       if (ptr->t == NULL)
+                               break;
+
+                       /* Second and subsequent clones */
+                       clone = xtables_malloc(sizeof(struct xtables_target));
+                       memcpy(clone, ptr, sizeof(struct xtables_target));
+                       clone->udata = NULL;
+                       clone->tflags = 0;
+                       /* This is a clone: */
+                       clone->next = clone;
+
+                       ptr = clone;
                        break;
+               }
        }
 
 #ifndef NO_SHARED_LIBS