diff --git a/src/path_resolver.c b/src/path_resolver.c index 0905982..8c3ac89 100644 --- a/src/path_resolver.c +++ b/src/path_resolver.c @@ -78,10 +78,13 @@ uvwasi_errno_t uvwasi__normalize_path(const char* path, char* last; size_t cur_len; int is_absolute; + int has_trailing_slash; if (path_len > normalized_len) return UVWASI_ENOBUFS; + has_trailing_slash = path_len > 0 && path[path_len - 1] == '/'; + is_absolute = uvwasi__is_absolute_path(path, path_len); normalized_path[0] = '\0'; ptr = normalized_path; @@ -156,6 +159,12 @@ uvwasi_errno_t uvwasi__normalize_path(const char* path, *ptr = '\0'; } + if (has_trailing_slash && *(ptr - 1) != '/') { + *ptr = '/'; + ptr++; + *ptr = '\0'; + } + return UVWASI_ESUCCESS; } @@ -171,7 +180,9 @@ static int uvwasi__is_path_sandboxed(const char* path, return path == strstr(path, fd_path) ? 1 : 0; /* Handle relative fds that normalized to '.' */ - if (fd_path_len == 1 && fd_path[0] == '.') { + if ((fd_path_len == 1 && fd_path[0] == '.') + || (fd_path_len == 2 && fd_path[0] == '.' && fd_path[1] == '/') + ) { /* If the fd's path is '.', then any path does not begin with '..' is OK. */ if ((path_len == 2 && path[0] == '.' && path[1] == '.') || (path_len > 2 && path[0] == '.' && path[1] == '.' && path[2] == '/')) { @@ -348,7 +359,11 @@ static uvwasi_errno_t uvwasi__resolve_path_to_host( fake_path_len = strlen(fd->normalized_path); /* If the fake path is '.' just ignore it. */ - if (fake_path_len == 1 && fd->normalized_path[0] == '.') { + if ((fake_path_len == 1 && fd->normalized_path[0] == '.') + || (fake_path_len == 2 + && fd->normalized_path[0] == '.' + && fd->normalized_path[1] == '/') + ) { fake_path_len = 0; } diff --git a/test/test-path-open-trailing-slash.c b/test/test-path-open-trailing-slash.c new file mode 100644 index 0000000..9933539 --- /dev/null +++ b/test/test-path-open-trailing-slash.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include "uvwasi.h" +#include "uv.h" +#include "test-common.h" + +#define TEST_TMP_DIR "./out/tmp" +#define TEST_FILE "./out/tmp/test-path-open-trailing-slash.file" + +int main(void) { + const char* path = "test-path-open-trailing-slash.file/"; + uvwasi_t uvwasi; + uvwasi_fd_t fd; + uvwasi_options_t init_options; + uvwasi_errno_t err; + uv_fs_t req; + int r; + + setup_test_environment(); + + r = uv_fs_mkdir(NULL, &req, TEST_TMP_DIR, 0777, NULL); + uv_fs_req_cleanup(&req); + assert(r == 0 || r == UV_EEXIST); + + r = uv_fs_open(NULL, &req, TEST_FILE, UV_FS_O_CREAT | UV_FS_O_RDWR, 0777, NULL); + uv_fs_req_cleanup(&req); + assert(r >= 0); + + uvwasi_options_init(&init_options); + init_options.preopenc = 1; + init_options.preopens = calloc(1, sizeof(uvwasi_preopen_t)); + init_options.preopens[0].mapped_path = "/var"; + init_options.preopens[0].real_path = TEST_TMP_DIR; + + err = uvwasi_init(&uvwasi, &init_options); + assert(err == 0); + + err = uvwasi_path_open(&uvwasi, + 3, + 0, + path, + strlen(path) + 1, + 0, + 0, + 0, + 0, + &fd); + assert(err == UVWASI_ENOTDIR); + + uvwasi_destroy(&uvwasi); + free(init_options.preopens); + + return 0; +} diff --git a/test/test-path-resolution.c b/test/test-path-resolution.c index 50510b5..40b7415 100644 --- a/test/test-path-resolution.c +++ b/test/test-path-resolution.c @@ -148,12 +148,12 @@ int main(void) { /* Arguments: input path, expected normalized path */ check_normalize("", "."); check_normalize(".", "."); - check_normalize("./", "."); + check_normalize("./", "./"); check_normalize("./.", "."); check_normalize("./..", ".."); - check_normalize("./../", ".."); + check_normalize("./../", "../"); check_normalize("..", ".."); - check_normalize("../", ".."); + check_normalize("../", "../"); check_normalize("../.", ".."); check_normalize("../..", "../.."); check_normalize("/", "/"); @@ -165,18 +165,18 @@ int main(void) { check_normalize("/foo/../bar", "/bar"); check_normalize("/../bar", "/bar"); check_normalize("/../../../bar", "/bar"); - check_normalize("/../../../bar/", "/bar"); + check_normalize("/../../../bar/", "/bar/"); check_normalize("/../../../", "/"); check_normalize("////..//../..///", "/"); - check_normalize("./foo//", "foo"); + check_normalize("./foo//", "foo/"); check_normalize("./foo/////bar", "foo/bar"); check_normalize("//", "/"); - check_normalize("..//", ".."); - check_normalize(".//", "."); + check_normalize("..//", "../"); + check_normalize(".//", "./"); check_normalize("./foo/bar/baz/../../../..", ".."); - check_normalize("./foo/bar/baz/../../../../", ".."); + check_normalize("./foo/bar/baz/../../../../", "../"); check_normalize("./foo/bar/baz/../../../../..", "../.."); - check_normalize("./foo/bar/baz/../../../../../", "../.."); + check_normalize("./foo/bar/baz/../../../../../", "../../"); check_normalize("../../../test_path", "../../../test_path"); check_normalize("./././test_path", "test_path");