summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2018-04-10 19:00:20 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2018-04-11 09:57:28 +0200
commit2b3f18e0cf7a7914b500cf17cc47e5bddb9d6848 (patch)
treea06a723c5e218908d76b44b9118d18c04394805a /src
parent5b10dbb6ccba10cfe57facc499c30b48e32a146a (diff)
libnftables: Fix for input without trailing newline
Input parser implementation requires a newline at end of input, otherwise the last pattern may not be recognized correctly. If input comes from a file, the culprit was YY_INPUT macro not expecting the last line not ending with a newline, so the last word wasn't accepted. This is easily fixed by checking for feof(yyin) in there. A simple test case for that is: | echo -en "table ip t {\nchain c {\n}\n}" >/tmp/foo | nft -f /tmp/foo Input from a string buffer is a bit more tricky: The culprit here is that detection of classid pattern is done by checking the character following it which makes it impossible to sit right at end of input and I haven't found an alternative to that. After dropping the manual newline appending when combining argv into a single buffer in main(), a rule like this won't be recognized anymore: | nft add rule ip t c meta priority feed:babe Since a direct call to run_cmd_from_buffer() via libnftables bypasses the sanitizing done in main() entirely, it has to happen in libnftables instead which means creating a newline-terminated duplicate of the input buffer. Note that main() created a buffer one byte longer than needed since it accounts for whitespace at end of each argv but doesn't add it to the buffer for the last one, so buffer length is reduced by two bytes instead of just one although only one less character is printed into it. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/libnftables.c9
-rw-r--r--src/main.c5
-rw-r--r--src/scanner.l2
3 files changed, 11 insertions, 5 deletions
diff --git a/src/libnftables.c b/src/libnftables.c
index 6e271209..8bf989b0 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -280,13 +280,19 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, char *buf, size_t buflen)
int rc = 0;
struct parser_state state;
LIST_HEAD(msgs);
+ size_t nlbuflen;
void *scanner;
FILE *fp;
+ char *nlbuf;
+
+ nlbuflen = max(buflen + 1, strlen(buf) + 2);
+ nlbuf = xzalloc(nlbuflen);
+ snprintf(nlbuf, nlbuflen, "%s\n", buf);
parser_init(nft->nf_sock, &nft->cache, &state,
&msgs, nft->debug_mask, &nft->output);
scanner = scanner_init(&state);
- scanner_push_buffer(scanner, &indesc_cmdline, buf);
+ scanner_push_buffer(scanner, &indesc_cmdline, nlbuf);
if (nft_run(nft, nft->nf_sock, scanner, &state, &msgs) != 0)
rc = -1;
@@ -296,6 +302,7 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, char *buf, size_t buflen)
nft_ctx_set_output(nft, fp);
scanner_destroy(scanner);
iface_cache_release();
+ free(nlbuf);
return rc;
}
diff --git a/src/main.c b/src/main.c
index 353b87bc..1f08dfec 100644
--- a/src/main.c
+++ b/src/main.c
@@ -264,14 +264,13 @@ int main(int argc, char * const *argv)
for (len = 0, i = optind; i < argc; i++)
len += strlen(argv[i]) + strlen(" ");
- buf = xzalloc(len + 2);
+ buf = xzalloc(len);
for (i = optind; i < argc; i++) {
strcat(buf, argv[i]);
if (i + 1 < argc)
strcat(buf, " ");
}
- strcat(buf, "\n");
- rc = !!nft_run_cmd_from_buffer(nft, buf, len + 2);
+ rc = !!nft_run_cmd_from_buffer(nft, buf, len);
} else if (filename != NULL) {
rc = !!nft_run_cmd_from_filename(nft, filename);
} else if (interactive) {
diff --git a/src/scanner.l b/src/scanner.l
index 1d8e8ba0..d908a8fe 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -47,7 +47,7 @@
errno = 0; \
clearerr(yyin); \
} \
- if (result > 1) { \
+ if (result > 1 && !feof(yyin)) { \
while (result > 1 && \
(buf[result - 1] != '\n' && buf[result - 1] != ' ')) \
result--, n++; \