diff options
author | Martin Pärtel <martin.partel@gmail.com> | 2022-10-17 08:51:29 +0300 |
---|---|---|
committer | Martin Pärtel <martin.partel@gmail.com> | 2022-10-17 08:51:29 +0300 |
commit | 6afff1fc626904b3036822d571fe0051094d3449 (patch) | |
tree | 095379cad8cab2d5da6fe3fe1d1ff5a43a292119 /src | |
parent | 6fa5cd6480c83240cff72265ccdc45bcdb9576f6 (diff) | |
download | bindfs-6afff1fc626904b3036822d571fe0051094d3449.tar.gz |
Fixed --resolve-symlinks when mountpoint name starts with source dir name.
Fixes #122
Diffstat (limited to 'src')
-rw-r--r-- | src/bindfs.c | 4 | ||||
-rw-r--r-- | src/misc.c | 39 | ||||
-rw-r--r-- | src/misc.h | 4 |
3 files changed, 45 insertions, 2 deletions
diff --git a/src/bindfs.c b/src/bindfs.c index 65384dc..263aa0e 100644 --- a/src/bindfs.c +++ b/src/bindfs.c @@ -393,10 +393,10 @@ static char *process_path(const char *path, bool resolve_symlinks) we want to be able to operate on broken symlinks. */ return strdup(path); } - } else if (strncmp(result, settings.mntdest, settings.mntdest_len) == 0) { + } else if (path_starts_with(result, settings.mntdest, settings.mntdest_len)) { /* Recursive call. We cannot handle this without deadlocking, especially in single-threaded mode. */ - DPRINTF("Denying recursive access to mountpoint `%s'", result); + DPRINTF("Denying recursive access to mountpoint \"%s\" at \"%s\"", settings.mntdest, result); free(result); errno = EPERM; return NULL; @@ -135,6 +135,45 @@ const char *my_dirname(char *path) } } +static const char* find_last_char_between(const char* start, const char* end, char ch) { + assert(start != NULL && end != NULL); + const char* p = end - 1; + while (p >= start) { + if (*p == ch) { + return p; + } + --p; + } + return NULL; +} + +bool path_starts_with(const char *path, const char* prefix, size_t prefix_len) +{ + size_t path_len = strlen(path); + while (prefix_len > 0 && prefix[prefix_len - 1] == '/') { + --prefix_len; + } + while (path_len > 0 && path[path_len - 1] == '/') { + --path_len; + } + + if (strncmp(path, prefix, prefix_len) == 0) { + // We still need to check that the last path component of + // 'path' does not simply start with the last path component of 'prefix'. + const char* prefix_slash = find_last_char_between(prefix, prefix + prefix_len, '/'); + const char* prefix_part = prefix_slash ? prefix_slash + 1 : prefix; + size_t prefix_part_len = (prefix + prefix_len - prefix_part); + + const char* path_part = path + (prefix_part - prefix); + const char* path_slash = strchr(path_part, '/'); + size_t path_part_len = path_slash ? path_slash - path_part : path_len - (path_part - path); + + return prefix_part_len == path_part_len; + } + + return false; +} + static char **dup_argv(int argc, const char * const *argv, struct arena *arena) { char **pointer_list = arena_malloc(arena, (argc + 1) * sizeof(char*)); @@ -53,6 +53,10 @@ const char *my_basename(const char *path); Otherwise, returns ".". */ const char *my_dirname(char *path); +/* Returns true if the initial path components of 'path' are the path components of 'prefix'. + Assumes 'strlen(prefix) == prefix_len'. */ +bool path_starts_with(const char *path, const char* prefix, size_t prefix_len); + /* Filters arguments in comma-separated lists prefixed by '-o'. * Allocates 'new_argv' and its strings, as well as some temporary data, into 'arena'. */ void filter_o_opts( |