aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMartin Pärtel <martin.partel@gmail.com>2022-10-17 08:51:29 +0300
committerMartin Pärtel <martin.partel@gmail.com>2022-10-17 08:51:29 +0300
commit6afff1fc626904b3036822d571fe0051094d3449 (patch)
tree095379cad8cab2d5da6fe3fe1d1ff5a43a292119 /src
parent6fa5cd6480c83240cff72265ccdc45bcdb9576f6 (diff)
downloadbindfs-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.c4
-rw-r--r--src/misc.c39
-rw-r--r--src/misc.h4
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;
diff --git a/src/misc.c b/src/misc.c
index cedd247..122497d 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -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*));
diff --git a/src/misc.h b/src/misc.h
index 360ddd1..07c0472 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -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(