From c6753190e130e323c4082d6afcf3b5051ddb3272 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 14 Sep 2023 11:42:16 +0200 Subject: [PATCH nft,v1.0.6 39/41] scanner: restrict include directive to regular files commit 999ca7dade519ad5757f07a9c488b326a5e7d785 upstream. 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 --- src/scanner.l | 69 ++++++++++++++++++- .../testcases/bogons/nft-f/include-device | 1 + 2 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 tests/shell/testcases/bogons/nft-f/include-device diff --git a/src/scanner.l b/src/scanner.l index b4315b8f8860..a158ed06b845 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -947,9 +948,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; @@ -961,12 +1012,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: @@ -1039,7 +1102,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; } @@ -1076,7 +1139,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 index 000000000000..1eb797735481 --- /dev/null +++ b/tests/shell/testcases/bogons/nft-f/include-device @@ -0,0 +1 @@ +include "/dev/null" -- 2.30.2