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