The action associated with the `{numberstring}` pattern, passes `yytext`
to `strtoull` with base 0:
errno = 0;
yylval->val = strtoull(yytext, NULL, 0);
if (errno != 0) {
yylval->string = xstrdup(yytext);
return STRING;
}
return NUM;
If `yytext` begins with '0', it will be parsed as octal. However, this
has unexpected consequences if the token contains non-octal characters.
`09` will be parsed as 0; `0308` will be parsed as 24, because
`strtoull` and its siblings stop parsing as soon as they reach a
character in the input which is not valid for the base.
Replace the `{numberstring}` match with separate `{hexstring}` and
`{decstring}` matches. For `{decstring}` set the base to 8 if the
leading character is '0', and handle an incompletely parsed token in
the same way as one that causes `strtoull` to set `errno`.
Thus, instead of:
$ sudo nft -f - <<<'
table x {
chain y {
ip saddr 0308 continue comment "parsed as 0.0.0.24/32"
}
}
'
$ sudo nft list chain x y
table ip x {
chain y {
ip saddr 0.0.0.24 continue comment "parsed as 0.0.0.24/32"
}
}
We get:
$ sudo ./src/nft -f - <<<'
> table x {
> chain y {
> ip saddr 0308 continue comment "error"
> }
> }
> '
/dev/stdin:4:14-17: Error: Could not resolve hostname: Name or service not known
ip saddr 0308 continue comment "error"
^^^^
Add a test-case.
Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=932880
Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1363
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
hexdigit [0-9a-fA-F]
decstring {digit}+
hexstring 0[xX]{hexdigit}+
-numberstring ({decstring}|{hexstring})
letter [a-zA-Z]
string ({letter}|[_.])({letter}|{digit}|[/\-_\.])*
quotedstring \"[^"]*\"
return STRING;
}
-{numberstring} {
+{hexstring} {
errno = 0;
- yylval->val = strtoull(yytext, NULL, 0);
+ yylval->val = strtoull(yytext, NULL, 16);
if (errno != 0) {
yylval->string = xstrdup(yytext);
return STRING;
return NUM;
}
+{decstring} {
+ int base = yytext[0] == '0' ? 8 : 10;
+ char *end;
+
+ errno = 0;
+ yylval->val = strtoull(yytext, &end, base);
+ if (errno != 0 || *end) {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ return NUM;
+ }
+
{classid}/[ \t\n:\-},] {
yylval->string = xstrdup(yytext);
return STRING;
--- /dev/null
+#!/bin/bash
+
+$NFT add table t || exit 1
+$NFT add chain t c || exit 1
+$NFT add rule t c 'ip saddr 01 continue comment "0.0.0.1"' || exit 1
+$NFT add rule t c 'ip saddr 08 continue comment "error"' && {
+ echo "'"ip saddr 08"'" not rejected 1>&2
+ exit 1
+}
+$NFT delete table t || exit 1
+
+exit 0
+