diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-07-30 00:14:45 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-07-30 00:14:45 -0700 |
commit | 2f865fd3e2cd871387de67394013b1137142357c (patch) | |
tree | 99e0c3db635608336e0864d02dae6c10ceec6b48 | |
parent | 768aeab3232cd3077ffff579ff2d59441c6968ef (diff) | |
download | safepath-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.c | 34 |
1 files changed, 22 insertions, 12 deletions
@@ -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; |