Blame SOURCES/0046-xtables-Fix-for-false-positive-rule-matching.patch

1dc35b
From 27b68bd11b99429d1b830dbe76fc0148b5a24a16 Mon Sep 17 00:00:00 2001
8cce6c
From: Phil Sutter <phil@nwl.cc>
8cce6c
Date: Mon, 4 Feb 2019 21:52:53 +0100
8cce6c
Subject: [PATCH] xtables: Fix for false-positive rule matching
8cce6c
8cce6c
When comparing two rules with non-standard targets, differences in
8cce6c
targets' payloads wasn't respected.
8cce6c
8cce6c
The cause is a rather hideous one: Unlike xtables_find_match(),
8cce6c
xtables_find_target() did not care whether the found target was already
8cce6c
in use or not, so the same target instance was assigned to both rules
8cce6c
and therefore payload comparison happened over the same memory location.
8cce6c
8cce6c
With legacy iptables it is not possible to reuse a target: The only case
8cce6c
where two rules (i.e., iptables_command_state instances) could exist at
8cce6c
the same time is when comparing rules, but that's handled using libiptc.
8cce6c
8cce6c
The above change clashes with ebtables-nft's reuse of target objects:
8cce6c
While input parsing still just assigns the object from xtables_targets
8cce6c
list, rule conversion from nftnl to iptables_command_state allocates new
8cce6c
data. To fix this, make ebtables-nft input parsing use the common
8cce6c
command_jump() routine instead of its own simplified copy. In turn, this
8cce6c
also eliminates the ebtables-nft-specific variants of parse_target(),
8cce6c
though with a slight change of behaviour: Names of user-defined chains
8cce6c
are no longer allowed to contain up to 31 but merely 28 characters.
8cce6c
8cce6c
Signed-off-by: Phil Sutter <phil@nwl.cc>
8cce6c
Signed-off-by: Florian Westphal <fw@strlen.de>
8cce6c
(cherry picked from commit 148131f20421046fea028e638581e938ec985783)
8cce6c
Signed-off-by: Phil Sutter <psutter@redhat.com>
8cce6c
---
8cce6c
 iptables/nft-bridge.c                         | 10 ++++
8cce6c
 iptables/nft-bridge.h                         |  2 -
8cce6c
 iptables/nft-shared.c                         |  5 ++
8cce6c
 .../testcases/iptables/0005-delete-rules_0    |  7 +++
8cce6c
 iptables/xtables-eb-translate.c               | 24 +---------
8cce6c
 iptables/xtables-eb.c                         | 47 +------------------
8cce6c
 libxtables/xtables.c                          | 18 ++++++-
8cce6c
 7 files changed, 41 insertions(+), 72 deletions(-)
8cce6c
8cce6c
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
8cce6c
index ad583a60c424d..140fcf0a31b84 100644
8cce6c
--- a/iptables/nft-bridge.c
8cce6c
+++ b/iptables/nft-bridge.c
8cce6c
@@ -45,6 +45,16 @@ void ebt_cs_clean(struct iptables_command_state *cs)
8cce6c
 		free(m);
8cce6c
 		m = nm;
8cce6c
 	}
8cce6c
+
8cce6c
+	if (cs->target) {
8cce6c
+		free(cs->target->t);
8cce6c
+		cs->target->t = NULL;
8cce6c
+
8cce6c
+		if (cs->target == cs->target->next) {
8cce6c
+			free(cs->target);
8cce6c
+			cs->target = NULL;
8cce6c
+		}
8cce6c
+	}
8cce6c
 }
8cce6c
 
8cce6c
 static void ebt_print_mac(const unsigned char *mac)
8cce6c
diff --git a/iptables/nft-bridge.h b/iptables/nft-bridge.h
8cce6c
index de52cd7195bbb..d90066f1030a2 100644
8cce6c
--- a/iptables/nft-bridge.h
8cce6c
+++ b/iptables/nft-bridge.h
8cce6c
@@ -32,7 +32,6 @@ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mas
8cce6c
  */
8cce6c
 
8cce6c
 #define EBT_TABLE_MAXNAMELEN 32
8cce6c
-#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
8cce6c
 #define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
8cce6c
 
8cce6c
 /* verdicts >0 are "branches" */
8cce6c
@@ -122,6 +121,5 @@ void ebt_add_match(struct xtables_match *m,
8cce6c
 void ebt_add_watcher(struct xtables_target *watcher,
8cce6c
                      struct iptables_command_state *cs);
8cce6c
 int ebt_command_default(struct iptables_command_state *cs);
8cce6c
-struct xtables_target *ebt_command_jump(const char *jumpto);
8cce6c
 
8cce6c
 #endif
8cce6c
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
8cce6c
index dfc1c803cb68d..ce40787f92f7d 100644
8cce6c
--- a/iptables/nft-shared.c
8cce6c
+++ b/iptables/nft-shared.c
8cce6c
@@ -687,6 +687,11 @@ void nft_clear_iptables_command_state(struct iptables_command_state *cs)
8cce6c
 	if (cs->target) {
8cce6c
 		free(cs->target->t);
8cce6c
 		cs->target->t = NULL;
8cce6c
+
8cce6c
+		if (cs->target == cs->target->next) {
8cce6c
+			free(cs->target);
8cce6c
+			cs->target = NULL;
8cce6c
+		}
8cce6c
 	}
8cce6c
 }
8cce6c
 
8cce6c
diff --git a/iptables/tests/shell/testcases/iptables/0005-delete-rules_0 b/iptables/tests/shell/testcases/iptables/0005-delete-rules_0
8cce6c
index 9312fd53c3437..5038cbce5a5cf 100755
8cce6c
--- a/iptables/tests/shell/testcases/iptables/0005-delete-rules_0
8cce6c
+++ b/iptables/tests/shell/testcases/iptables/0005-delete-rules_0
8cce6c
@@ -5,3 +5,10 @@
8cce6c
 $XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j DROP
8cce6c
 $XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j REJECT
8cce6c
 [[ $? -eq 1 ]] || exit 1
8cce6c
+
8cce6c
+# test incorrect deletion of rules with deviating payload
8cce6c
+# in non-standard target
8cce6c
+
8cce6c
+$XT_MULTI iptables -A FORWARD -i eth23 -o eth42 -j MARK --set-mark 23
8cce6c
+$XT_MULTI iptables -D FORWARD -i eth23 -o eth42 -j MARK --set-mark 42
8cce6c
+[[ $? -eq 1 ]] || exit 1
8cce6c
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
8cce6c
index f98c385555eb1..0fe14d2d0db32 100644
8cce6c
--- a/iptables/xtables-eb-translate.c
8cce6c
+++ b/iptables/xtables-eb-translate.c
8cce6c
@@ -64,27 +64,6 @@ static int parse_rule_number(const char *rule)
8cce6c
 	return rule_nr;
8cce6c
 }
8cce6c
 
8cce6c
-static const char *
8cce6c
-parse_target(const char *targetname)
8cce6c
-{
8cce6c
-	const char *ptr;
8cce6c
-
8cce6c
-	if (strlen(targetname) < 1)
8cce6c
-		xtables_error(PARAMETER_PROBLEM,
8cce6c
-			      "Invalid target name (too short)");
8cce6c
-
8cce6c
-	if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN)
8cce6c
-		xtables_error(PARAMETER_PROBLEM,
8cce6c
-			      "Invalid target '%s' (%d chars max)",
8cce6c
-			      targetname, EBT_CHAIN_MAXNAMELEN);
8cce6c
-
8cce6c
-	for (ptr = targetname; *ptr; ptr++)
8cce6c
-		if (isspace(*ptr))
8cce6c
-			xtables_error(PARAMETER_PROBLEM,
8cce6c
-				      "Invalid target name `%s'", targetname);
8cce6c
-	return targetname;
8cce6c
-}
8cce6c
-
8cce6c
 static int get_current_chain(const char *chain)
8cce6c
 {
8cce6c
 	if (strcmp(chain, "PREROUTING") == 0)
8cce6c
@@ -411,8 +390,7 @@ print_zero:
8cce6c
 				break;
8cce6c
 			} else if (c == 'j') {
8cce6c
 				ebt_check_option2(&flags, OPT_JUMP);
8cce6c
-				cs.jumpto = parse_target(optarg);
8cce6c
-				cs.target = ebt_command_jump(cs.jumpto);
8cce6c
+				command_jump(&cs);
8cce6c
 				break;
8cce6c
 			} else if (c == 's') {
8cce6c
 				ebt_check_option2(&flags, OPT_SOURCE);
8cce6c
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
8cce6c
index 4c52c29aa4817..55cb0fe204748 100644
8cce6c
--- a/iptables/xtables-eb.c
8cce6c
+++ b/iptables/xtables-eb.c
8cce6c
@@ -139,27 +139,6 @@ static int parse_rule_number(const char *rule)
8cce6c
 	return rule_nr;
8cce6c
 }
8cce6c
 
8cce6c
-static const char *
8cce6c
-parse_target(const char *targetname)
8cce6c
-{
8cce6c
-	const char *ptr;
8cce6c
-
8cce6c
-	if (strlen(targetname) < 1)
8cce6c
-		xtables_error(PARAMETER_PROBLEM,
8cce6c
-			      "Invalid target name (too short)");
8cce6c
-
8cce6c
-	if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN)
8cce6c
-		xtables_error(PARAMETER_PROBLEM,
8cce6c
-			      "Invalid target '%s' (%d chars max)",
8cce6c
-			      targetname, EBT_CHAIN_MAXNAMELEN);
8cce6c
-
8cce6c
-	for (ptr = targetname; *ptr; ptr++)
8cce6c
-		if (isspace(*ptr))
8cce6c
-			xtables_error(PARAMETER_PROBLEM,
8cce6c
-				      "Invalid target name `%s'", targetname);
8cce6c
-	return targetname;
8cce6c
-}
8cce6c
-
8cce6c
 static int
8cce6c
 append_entry(struct nft_handle *h,
8cce6c
 	     const char *chain,
8cce6c
@@ -376,29 +355,6 @@ static struct option *merge_options(struct option *oldopts,
8cce6c
 	return merge;
8cce6c
 }
8cce6c
 
8cce6c
-/*
8cce6c
- * More glue code.
8cce6c
- */
8cce6c
-struct xtables_target *ebt_command_jump(const char *jumpto)
8cce6c
-{
8cce6c
-	struct xtables_target *target;
8cce6c
-	unsigned int verdict;
8cce6c
-
8cce6c
-	/* Standard target? */
8cce6c
-	if (!ebt_fill_target(jumpto, &verdict))
8cce6c
-		jumpto = "standard";
8cce6c
-
8cce6c
-	/* For ebtables, all targets are preloaded. Hence it is either in
8cce6c
-	 * xtables_targets or a custom chain to jump to, in which case
8cce6c
-	 * returning NULL is fine. */
8cce6c
-	for (target = xtables_targets; target; target = target->next) {
8cce6c
-		if (!strcmp(target->name, jumpto))
8cce6c
-			break;
8cce6c
-	}
8cce6c
-
8cce6c
-	return target;
8cce6c
-}
8cce6c
-
8cce6c
 static void print_help(const struct xtables_target *t,
8cce6c
 		       const struct xtables_rule_match *m, const char *table)
8cce6c
 {
8cce6c
@@ -1066,8 +1022,7 @@ print_zero:
8cce6c
 			} else if (c == 'j') {
8cce6c
 				ebt_check_option2(&flags, OPT_JUMP);
8cce6c
 				if (strcmp(optarg, "CONTINUE") != 0) {
8cce6c
-					cs.jumpto = parse_target(optarg);
8cce6c
-					cs.target = ebt_command_jump(cs.jumpto);
8cce6c
+					command_jump(&cs);
8cce6c
 				}
8cce6c
 				break;
8cce6c
 			} else if (c == 's') {
8cce6c
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
8cce6c
index ea9bb102c8eb4..895f6988eaf57 100644
8cce6c
--- a/libxtables/xtables.c
8cce6c
+++ b/libxtables/xtables.c
8cce6c
@@ -756,8 +756,24 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
8cce6c
 	}
8cce6c
 
8cce6c
 	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
8cce6c
-		if (extension_cmp(name, ptr->name, ptr->family))
8cce6c
+		if (extension_cmp(name, ptr->name, ptr->family)) {
8cce6c
+			struct xtables_target *clone;
8cce6c
+
8cce6c
+			/* First target of this type: */
8cce6c
+			if (ptr->t == NULL)
8cce6c
+				break;
8cce6c
+
8cce6c
+			/* Second and subsequent clones */
8cce6c
+			clone = xtables_malloc(sizeof(struct xtables_target));
8cce6c
+			memcpy(clone, ptr, sizeof(struct xtables_target));
8cce6c
+			clone->udata = NULL;
8cce6c
+			clone->tflags = 0;
8cce6c
+			/* This is a clone: */
8cce6c
+			clone->next = clone;
8cce6c
+
8cce6c
+			ptr = clone;
8cce6c
 			break;
8cce6c
+		}
8cce6c
 	}
8cce6c
 
8cce6c
 #ifndef NO_SHARED_LIBS
8cce6c
-- 
1dc35b
2.21.0
8cce6c