From 517a303e425b606cde3b70a1481ff557bba17462 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 28 Feb 2022 14:35:39 -0500 Subject: parse: Check for globs with unescaped trailing backslashes Both macOS and musl fail to fail on an unescaped backslash, so check for it ourselves. Link: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html Link: https://github.com/void-linux/void-packages/pull/35836 Link: https://www.openwall.com/lists/musl/2022/02/25/2 Link: https://www.austingroupbugs.net/view.php?id=806 --- parse.c | 25 +++++++++++++++++++++++-- tests.sh | 3 --- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/parse.c b/parse.c index 826d325..3439f23 100644 --- a/parse.c +++ b/parse.c @@ -1686,11 +1686,14 @@ static struct expr *parse_fnmatch(const struct parser_state *state, struct expr return NULL; } + const char *arg = expr->argv[0]; + const char *pattern = expr->sdata; + if (casefold) { #ifdef FNM_CASEFOLD expr->idata = FNM_CASEFOLD; #else - parse_error(state, "${blu}%s${rs} is missing platform support.\n", expr->argv[0]); + parse_error(state, "${blu}%s${rs} is missing platform support.\n", arg); free_expr(expr); return NULL; #endif @@ -1698,9 +1701,27 @@ static struct expr *parse_fnmatch(const struct parser_state *state, struct expr expr->idata = 0; } + // POSIX says, about fnmatch(): + // + // If pattern ends with an unescaped , fnmatch() shall + // return a non-zero value (indicating either no match or an error). + // + // But not all implementations obey this, so check for it ourselves. + size_t i, len = strlen(pattern); + for (i = 0; i < len; ++i) { + if (pattern[len - i - 1] != '\\') { + break; + } + } + if (i % 2 != 0) { + parse_warning(state, "${blu}%s${rs} ${bld}%s${rs}: Unescaped trailing backslash.\n\n", arg, pattern); + free_expr(expr); + return &expr_false; + } + expr->cost = 400.0; - if (strchr(expr->sdata, '*')) { + if (strchr(pattern, '*')) { expr->probability = 0.5; } else { expr->probability = 0.1; diff --git a/tests.sh b/tests.sh index 9003efd..995b7a6 100755 --- a/tests.sh +++ b/tests.sh @@ -1338,9 +1338,6 @@ function test_name_bracket() { } function test_name_backslash() { - # fnmatch() is broken on macOS - skip_if test "$UNAME" = "Darwin" - # An unescaped \ doesn't match bfs_diff weirdnames -name '\' } -- cgit v1.2.3