diff options
-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; |