]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
libnftables: Fix for input without trailing newline
authorPhil Sutter <phil@nwl.cc>
Tue, 10 Apr 2018 17:00:20 +0000 (19:00 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 11 Apr 2018 07:57:28 +0000 (09:57 +0200)
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>
src/libnftables.c
src/main.c
src/scanner.l

index 6e271209d87ec3b713bbd9f75af05883ba9537d0..8bf989b08cc540d46f6e2733ed62f6be18af93af 100644 (file)
@@ -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;
 }
index 353b87bc66631a000ddb2989053c57a975b8479e..1f08dfecc26061e97984239088c1fc62f5cfd2d3 100644 (file)
@@ -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) {
index 1d8e8ba0ecf42ad5fed879bbf2448de9e7b66a80..d908a8fefc4f4e0059170ce8be60d48a9b0fe9be 100644 (file)
@@ -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++;                                          \