diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2022-02-28 14:35:39 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2022-02-28 14:35:39 -0500 |
commit | 517a303e425b606cde3b70a1481ff557bba17462 (patch) | |
tree | cdb4100bab98bbd335aa192128aff949850f3ffe /parse.c | |
parent | e14f04e52f792d12f3798b3c69bd0279ac7d3150 (diff) | |
download | bfs-517a303e425b606cde3b70a1481ff557bba17462.tar.xz |
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
Diffstat (limited to 'parse.c')
-rw-r--r-- | parse.c | 25 |
1 files changed, 23 insertions, 2 deletions
@@ -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 <backslash>, 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; |