aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-07-30 00:14:45 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-07-30 00:14:45 -0700
commit2f865fd3e2cd871387de67394013b1137142357c (patch)
tree99e0c3db635608336e0864d02dae6c10ceec6b48
parent768aeab3232cd3077ffff579ff2d59441c6968ef (diff)
downloadsafepath-2f865fd3e2cd871387de67394013b1137142357c.tar.gz
safepath-2f865fd3e2cd871387de67394013b1137142357c.tar.bz2
safepath-2f865fd3e2cd871387de67394013b1137142357c.zip
Handle consecutive slashes better.
* safepath.c (safepath_check): At the start of an absolute path and at every component separation, go to the last slash if there are multiple slashes; do not report multiple slashes as an invalid path. Also, if a symbolic link target ends with a slash, then do not add a slash between it and the rest of the path. We thereby conform to the POSIX requirement that if a link target consists of nothing but slashes, then those slashes replace the leading slashes of the rest of the path.
-rw-r--r--safepath.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/safepath.c b/safepath.c
index f91ff58..270e486 100644
--- a/safepath.c
+++ b/safepath.c
@@ -298,7 +298,7 @@ int safepath_check(const char *name)
struct stat st;
int abs = (*name == '/');
const char *start = abs ? "/" : ".";
- size_t pos = abs ? 1 : 0;
+ size_t pos = strspn(name, "/"); /* skip all leading slashes */
char *copy;
int ret = SAFEPATH_OK, count = 0, root_checked = abs;
@@ -341,10 +341,9 @@ int safepath_check(const char *name)
size_t nxslash = pos + strcspn(copy + pos, "/");
int savechar = copy[nxslash];
- /* consecutive slashes */
- if (nxslash == pos) {
- ret = SAFEPATH_INVAL;
- goto free_out;
+ if (savechar) {
+ while (copy[nxslash + 1] == '/')
+ nxslash++;
}
/* null terminate the path at the next slash */
@@ -390,7 +389,10 @@ int safepath_check(const char *name)
goto free_out;
}
- if (len == sizeof link) {
+ if (len == 0) {
+ ret = SAFEPATH_INVAL;
+ goto free_out;
+ } else if (len == sizeof link) {
ret = SAFEPATH_TOOLONG;
goto free_out;
}
@@ -430,7 +432,7 @@ int safepath_check(const char *name)
ret = SAFEPATH_NOMEM;
goto out;
}
- pos = 1;
+ pos = strspn(copy, "/");
continue;
} else {
size_t total = len + 1 + strlen(copy + nxslash + 1) + 1;
@@ -440,11 +442,15 @@ int safepath_check(const char *name)
goto free_out;
}
strcpy(resolved, link);
- resolved[len] = '/';
- strcpy(resolved + len + 1, copy + nxslash + 1);
+ if (link[len - 1] != '/') {
+ resolved[len] = '/';
+ strcpy(resolved + len + 1, copy + nxslash + 1);
+ } else {
+ strcpy(resolved + len, copy + nxslash + 1);
+ }
free(copy);
copy = resolved;
- pos = 1;
+ pos = strspn(copy, "/");
continue;
}
} else {
@@ -469,8 +475,12 @@ int safepath_check(const char *name)
}
memcpy(resolved, copy, pos);
strcpy(resolved + pos, link);
- resolved[pos + len] = '/';
- strcpy(resolved + pos + len + 1, copy + nxslash + 1);
+ if (link[len - 1] != '/') {
+ resolved[pos + len] = '/';
+ strcpy(resolved + pos + len + 1, copy + nxslash + 1);
+ } else {
+ strcpy(resolved + pos + len, copy + nxslash + 1);
+ }
free(copy);
copy = resolved;
continue;