vfs: make vfs_path_normalize more robust and consistent

* Correctly process trailing . and .. without /
* Fix potential read past the input buffer
* Always strip trailing /
This commit is contained in:
Andrei Alexeyev 2021-06-18 04:26:54 +03:00
parent 62f55854aa
commit 2a31511588
No known key found for this signature in database
GPG key ID: 72D26128040B9690
6 changed files with 19 additions and 23 deletions

View file

@ -144,11 +144,6 @@ char* strftimealloc(const char *fmt, const struct tm *timeinfo) {
};
}
void strip_trailing_slashes(char *buf) {
for(char *c = buf + strlen(buf) - 1; c >= buf && (*c == '/' || *c == '\\'); c--)
*c = 0;
}
char* strappend(char **dst, char *src) {
if(!*dst) {
return *dst = strdup(src);

View file

@ -48,7 +48,6 @@ void stralloc(char **dest, const char *src);
char* strjoin(const char *first, ...) attr_sentinel attr_returns_allocated;
char* vstrfmt(const char *fmt, va_list args) attr_returns_allocated;
char* strfmt(const char *fmt, ...) attr_printf(1, 2) attr_returns_allocated;
void strip_trailing_slashes(char *buf);
char* strtok_r(char *str, const char *delim, char **nextp);
char* strappend(char **dst, char *src);
char* strftimealloc(const char *fmt, const struct tm *timeinfo) attr_returns_allocated;

View file

@ -17,6 +17,8 @@ char *vfs_path_normalize(const char *path, char *out) {
char *last_sep = out - 1;
char *path_end = strchr(path, 0);
#define IS_SEP_OR_NUL(chr) (VFS_IS_PATH_SEPARATOR(chr) || (chr == '\0'))
while(p < path_end) {
if(VFS_IS_PATH_SEPARATOR(*p)) {
if(o > out && !VFS_IS_PATH_SEPARATOR(o[-1])) {
@ -27,13 +29,13 @@ char *vfs_path_normalize(const char *path, char *out) {
do {
++p;
} while(p < path_end && VFS_IS_PATH_SEPARATOR(*p));
} else if(*p == '.' && VFS_IS_PATH_SEPARATOR(p[1])) {
} else if(*p == '.' && IS_SEP_OR_NUL(p[1])) {
p += 2;
} else if(!strncmp(p, "..", 2) && VFS_IS_PATH_SEPARATOR(p[2])) {
} else if(p + 1 < path_end && !strncmp(p, "..", 2) && IS_SEP_OR_NUL(p[2])) {
if(last_sep >= out) {
do {
--last_sep;
} while(!VFS_IS_PATH_SEPARATOR(*last_sep) && last_sep >= out);
} while(last_sep >= out && !VFS_IS_PATH_SEPARATOR(*last_sep));
o = last_sep-- + 1;
}
@ -44,9 +46,18 @@ char *vfs_path_normalize(const char *path, char *out) {
}
}
#undef IS_SEP_OR_NUL
// remove trailing slash
if(o > out && VFS_IS_PATH_SEPARATOR(o[-1])) {
--o;
assert(o == out || !VFS_IS_PATH_SEPARATOR(o[-1]));
}
*o = 0;
// log_debug("[%s] --> [%s]", path, out);
// log_debug("[%s] --> [%s]", path, out);
return out;
}
@ -124,7 +135,7 @@ void vfs_path_root_prefix(char *path) {
}
}
char* vfs_syspath_normalize_inplace(char *path) {
char *vfs_syspath_normalize_inplace(char *path) {
char buf[strlen(path)+1];
strcpy(buf, path);
vfs_syspath_normalize(buf, sizeof(buf), path);

View file

@ -19,9 +19,9 @@
static_assert(sizeof(VFS_PATH_SEPARATOR_STR) == 2, "No more than one VFS path separator, please");
char* vfs_path_normalize(const char *path, char *out);
char* vfs_path_normalize_alloc(const char *path);
char* vfs_path_normalize_inplace(char *path);
char *vfs_path_normalize(const char *path, char *out);
char *vfs_path_normalize_alloc(const char *path);
char *vfs_path_normalize_inplace(char *path);
void vfs_path_split_left(char *path, char **lpath, char **rpath);
void vfs_path_split_right(char *path, char **lpath, char **rpath);
void vfs_path_root_prefix(char *path);

View file

@ -282,7 +282,6 @@ int vfs_dir_list_order_descending(const void *a, const void *b) {
void* vfs_dir_walk(const char *path, void* (*visit)(const char *path, void *arg), void *arg) {
char npath[strlen(path) + 1];
vfs_path_normalize(path, npath);
strip_trailing_slashes(npath);
VFSDir *dir = vfs_dir_open(npath);
void *result = NULL;

View file

@ -294,16 +294,8 @@ static void vfs_zipfile_init_pathmap(VFSNode *node) {
for(zip_int64_t i = 0; i < num; ++i) {
const char *original = zip_get_name(tls->zip, i, 0);
char normalized[strlen(original) + 1];
vfs_path_normalize(original, normalized);
if(*normalized) {
char *c = strchr(normalized, 0) - 1;
if(*c == '/') {
*c = 0;
}
}
if(strcmp(original, normalized)) {
ht_set(&zdata->pathmap, normalized, i);
}