From 07e437f569c68e218b2e7592dae458b0d50fbaad Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 25 Feb 2019 14:56:21 +0800 Subject: [PATCH] musl: glob-util: filter out . and .. even if GLOB_ALTDIRFUNC is not supported musl neither support GLOB_ALTDIRFUNC nor GLOB_BRACE. Let's make safe_glob() work even when GLOB_ALTDIRFUNC is not supported. Currently, GLOB_BRACE is simply ignored when it is not supported. --- src/basic/glob-util.c | 76 +++++++++++++++++++++++++++++++++++++++++ src/include/musl/glob.h | 18 ++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/include/musl/glob.h diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c index 5843ef088f3..eda7bcb6c51 100644 --- a/src/basic/glob-util.c +++ b/src/basic/glob-util.c @@ -9,6 +9,78 @@ #include "string-util.h" #include "strv.h" +#ifndef __GLIBC__ +static bool safe_glob_verify(const char *p, const char *prefix) { + if (isempty(p)) + return false; /* should not happen, but for safey. */ + + if (prefix) { + /* Skip the prefix, as we allow dots in prefix. + * Note, glob() does not normalize paths, hence do not use path_startswith(). */ + p = startswith(p, prefix); + if (!p) + return false; /* should not happen, but for safety. */ + } + + for (;;) { + p += strspn(p, "/"); + if (*p == '\0') + return true; + if (*p == '.') { + p++; + if (IN_SET(*p, '/', '\0')) + return false; /* refuse dot */ + if (*p == '.') { + p++; + if (IN_SET(*p, '/', '\0')) + return false; /* refuse dot dot */ + } + } + + p += strcspn(p, "/"); + if (*p == '\0') + return true; + } +} + +static int filter_glob_result(char * const *result, const char *path, char ***ret) { + int r; + + assert(path); + + if (strv_isempty(result)) + return -ENOENT; + + _cleanup_free_ char *prefix = NULL; + r = glob_non_glob_prefix(path, &prefix); + if (r < 0 && r != -ENOENT) + return r; + + _cleanup_strv_free_ char **filtered = NULL; + size_t n_filtered = 0; + STRV_FOREACH(p, result) { + if (!safe_glob_verify(*p, prefix)) + continue; + + if (!ret) + return 0; /* Found at least one entry, let's return earlier. */ + + /* When musl is used, each entry is not a head of allocated memory. Hence, it is + * necessary to copy the string. */ + r = strv_extend_with_size(&filtered, &n_filtered, *p); + if (r < 0) + return r; + } + + if (n_filtered == 0) + return -ENOENT; + + assert(ret); + *ret = TAKE_PTR(filtered); + return 0; +} +#endif + DEFINE_TRIVIAL_DESTRUCTOR(closedir_wrapper, void, closedir); int safe_glob_full(const char *path, int flags, opendir_t opendir_func, char ***ret) { @@ -32,6 +104,10 @@ int safe_glob_full(const char *path, int flags, opendir_t opendir_func, char *** if (r != 0) return errno_or_else(EIO); +#ifndef __GLIBC__ + return filter_glob_result(g.gl_pathv, path, ret); +#endif + if (strv_isempty(g.gl_pathv)) return -ENOENT; diff --git a/src/include/musl/glob.h b/src/include/musl/glob.h new file mode 100644 index 00000000000..12faa8ebfca --- /dev/null +++ b/src/include/musl/glob.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include_next + +#ifndef GLOB_ALTDIRFUNC +#define GLOB_ALTDIRFUNC (1 << 9) +#define gl_flags __dummy1 +#define gl_closedir __dummy2[0] +#define gl_readdir __dummy2[1] +#define gl_opendir __dummy2[2] +#define gl_lstat __dummy2[3] +#define gl_stat __dummy2[4] +#endif + +#ifndef GLOB_BRACE +#define GLOB_BRACE (1 << 10) +#endif -- 2.47.3