]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
scanner: restrict include directive to regular files
authorFlorian Westphal <fw@strlen.de>
Thu, 14 Sep 2023 09:42:16 +0000 (11:42 +0200)
committerFlorian Westphal <fw@strlen.de>
Fri, 29 Sep 2023 10:52:13 +0000 (12:52 +0200)
Similar to previous change, also check all

include "foo"

and reject those if they refer to named fifos, block devices etc.

Directories are still skipped, I don't think we can change this
anymore.

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1664
Signed-off-by: Florian Westphal <fw@strlen.de>
src/scanner.l
tests/shell/testcases/bogons/nft-f/include-device [new file with mode: 0644]

index 1aae1ecb09ef03c32b92ecbf878d84d1bc92482c..15b272ab1e9e16271a6e9964b5714282eba8420e 100644 (file)
@@ -18,6 +18,7 @@
 #include <arpa/inet.h>
 #include <linux/types.h>
 #include <linux/netfilter.h>
+#include <sys/stat.h>
 
 #include <nftables.h>
 #include <erec.h>
@@ -972,9 +973,59 @@ static void scanner_push_file(struct nft_ctx *nft, void *scanner,
        scanner_push_indesc(state, indesc);
 }
 
+enum nft_include_type {
+       NFT_INCLUDE,
+       NFT_CMDLINE,
+};
+
+static bool __is_useable(unsigned int type, enum nft_include_type t)
+{
+       type &= S_IFMT;
+       switch (type) {
+       case S_IFREG: return true;
+       case S_IFIFO:
+                return t == NFT_CMDLINE; /* disallow include /path/to/fifo */
+       default:
+               break;
+       }
+
+       return false;
+}
+
+/* need to use stat() to, fopen() will block for named fifos */
+static bool filename_is_useable(const char *name)
+{
+       struct stat sb;
+       int err;
+
+       err = stat(name, &sb);
+       if (err)
+               return false;
+
+       return __is_useable(sb.st_mode, NFT_INCLUDE);
+}
+
+static bool fp_is_useable(FILE *fp, enum nft_include_type t)
+{
+       int fd = fileno(fp);
+       struct stat sb;
+       int err;
+
+       if (fd < 0)
+               return false;
+
+       err = fstat(fd, &sb);
+       if (err < 0)
+               return false;
+
+       return __is_useable(sb.st_mode, t);
+}
+
 static int include_file(struct nft_ctx *nft, void *scanner,
                        const char *filename, const struct location *loc,
-                       const struct input_descriptor *parent_indesc)
+                       const struct input_descriptor *parent_indesc,
+                       enum nft_include_type includetype)
+
 {
        struct parser_state *state = yyget_extra(scanner);
        struct error_record *erec;
@@ -986,12 +1037,24 @@ static int include_file(struct nft_ctx *nft, void *scanner,
                goto err;
        }
 
+       if (includetype == NFT_INCLUDE && !filename_is_useable(filename)) {
+               erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+               goto err;
+       }
+
        f = fopen(filename, "r");
        if (f == NULL) {
                erec = error(loc, "Could not open file \"%s\": %s\n",
                             filename, strerror(errno));
                goto err;
        }
+
+       if (!fp_is_useable(f, includetype)) {
+               fclose(f);
+               erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+               goto err;
+       }
+
        scanner_push_file(nft, scanner, f, filename, loc, parent_indesc);
        return 0;
 err:
@@ -1064,7 +1127,7 @@ static int include_glob(struct nft_ctx *nft, void *scanner, const char *pattern,
                        if (len == 0 || path[len - 1] == '/')
                                continue;
 
-                       ret = include_file(nft, scanner, path, loc, indesc);
+                       ret = include_file(nft, scanner, path, loc, indesc, NFT_INCLUDE);
                        if (ret != 0)
                                goto err;
                }
@@ -1101,7 +1164,7 @@ err:
 int scanner_read_file(struct nft_ctx *nft, const char *filename,
                      const struct location *loc)
 {
-       return include_file(nft, nft->scanner, filename, loc, NULL);
+       return include_file(nft, nft->scanner, filename, loc, NULL, NFT_CMDLINE);
 }
 
 static bool search_in_include_path(const char *filename)
diff --git a/tests/shell/testcases/bogons/nft-f/include-device b/tests/shell/testcases/bogons/nft-f/include-device
new file mode 100644 (file)
index 0000000..1eb7977
--- /dev/null
@@ -0,0 +1 @@
+include "/dev/null"