Xtables-restore tries to reject rule commands in input which contain a
--table parameter (since it is adding this itself based on the previous
table line). Sadly getopt_long's flexibility makes it hard to get this
check right: Since the last fix, comments starting with a dash and
containing a 't' character somewhere later were rejected. Simple
example:
| *filter
| -A FORWARD -m comment --comment "- allow this one" -j ACCEPT
| COMMIT
To hopefully sort this once and for all, introduce is_table_param()
which should cover all possible variants of legal and illegal
parameters. Also add a test to make sure it does what it is supposed to.
Fixes: f8e5ebc5986bf ("iptables: Fix crash on malformed iptables-restore")
Signed-off-by: Phil Sutter <[email protected]>
---
.../ipt-restore/0009-table-name-comment_0 | 48 +++++++++++++++++++
iptables/xshared.c | 44 ++++++++++++++---
2 files changed, 86 insertions(+), 6 deletions(-)
create mode 100755
iptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_0
diff --git
a/iptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_0
b/iptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_0
new file mode 100755
index 0000000000000..71c8feffd5adf
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0009-table-name-comment_0
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+OKLINES="- some comment
+--asdf
+-asdf t
+-?t"
+
+NONOLINES="-t foo
+-t
+--table
+--table foo
+--table=foo
+-asdft
+-tasdf
+--tab=foo
+-dfetbl"
+
+to_dump() { # (comment)
+ echo "*filter"
+ echo "-A FORWARD -m comment --comment \"$@\" -j ACCEPT"
+ echo "COMMIT"
+}
+
+ret=0
+
+while read okline; do
+ $XT_MULTI iptables -A FORWARD -m comment --comment "$okline" -j ACCEPT
|| {
+ echo "iptables failed for comment '$okline'"
+ ret=1
+ }
+ to_dump "$okline" | $XT_MULTI iptables-restore || {
+ echo "iptables-restore failed for comment '$okline'"
+ ret=1
+ }
+done <<< "$OKLINES"
+
+while read nonoline; do
+ $XT_MULTI iptables -A FORWARD -m comment --comment "$nonoline" -j
ACCEPT >/dev/null 2>&1 || {
+ echo "iptables accepted comment '$nonoline'"
+ ret=1
+ }
+ to_dump "$nonoline" | $XT_MULTI iptables-restore >/dev/null 2>&1 && {
+ echo "iptables-restore accepted comment '$nonoline'"
+ ret=1
+ }
+done <<< "$NONOLINES"
+
+exit $ret
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 36a2ec5f193d3..faa21d6cd69af 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -446,6 +446,43 @@ static void add_param(struct xt_param_buf *param, const
char *curchar)
"Parameter too long!");
}
+static bool is_table_param(const char *s)
+{
+ if (s[0] != '-')
+ return false;
+
+ /* it is an option */
+ switch (s[1]) {
+ case 't':
+ /* -t found */
+ return true;
+ case '-':
+ /* it is a long option */
+ if (s[2] != 't')
+ return false;
+ if (index(s, '='))
+ return !strncmp(s, "--table", index(s, '=') - s);
+ return !strncmp(s, "--table", 7);
+ default:
+ break;
+ }
+ /* short options may be combined, check if 't' is among them */
+next:
+ s++;
+ switch (*s) {
+ case 't':
+ case ' ':
+ case '\0':
+ break;
+ case 'a' ... 's':
+ case 'u' ... 'z':
+ case 'A' ... 'Z':
+ case '0' ... '9':
+ goto next;
+ }
+ return *s == 't';
+}
+
void add_param_to_argv(char *parsestart, int line)
{
int quote_open = 0, escaped = 0;
@@ -499,15 +536,10 @@ void add_param_to_argv(char *parsestart, int line)
param.buffer[param.len] = '\0';
/* check if table name specified */
- if ((param.buffer[0] == '-' &&
- param.buffer[1] != '-' &&
- strchr(param.buffer, 't')) ||
- (!strncmp(param.buffer, "--t", 3) &&
- !strncmp(param.buffer, "--table", strlen(param.buffer)))) {
+ if (is_table_param(param.buffer))
xtables_error(PARAMETER_PROBLEM,
"The -t option (seen in line %u) cannot
be used in %s.\n",
line, xt_params->program_name);
- }
add_argv(param.buffer, 0);
param.len = 0;
--
2.23.0