Skip to content

Commit

Permalink
Preserve trailing slash in file path
Browse files Browse the repository at this point in the history
This commit fixes the behavior of `path_open` such that if the path
contains trailing slashes and the target file is not a directory, the
call errors. This behavior is consistent with Linux host, Wasmtime,
WAMR, and WasmEdge.

fixes #267

Signed-off-by: Yage Hu <[email protected]>
  • Loading branch information
yagehu committed Jun 8, 2024
1 parent 7aaa0b4 commit 408d98b
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 11 deletions.
19 changes: 17 additions & 2 deletions src/path_resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 && IS_SLASH(path[path_len - 1]);

is_absolute = uvwasi__is_absolute_path(path, path_len);
normalized_path[0] = '\0';
ptr = normalized_path;
Expand Down Expand Up @@ -156,6 +159,12 @@ uvwasi_errno_t uvwasi__normalize_path(const char* path,
*ptr = '\0';
}

if (has_trailing_slash && !IS_SLASH(*(ptr - 1))) {
*ptr = '/';
ptr++;
*ptr = '\0';
}

return UVWASI_ESUCCESS;
}

Expand All @@ -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] == '/')) {
Expand Down Expand Up @@ -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;
}

Expand Down
56 changes: 56 additions & 0 deletions test/test-path-open-trailing-slash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#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;
}
18 changes: 9 additions & 9 deletions test/test-path-resolution.c
Original file line number Diff line number Diff line change
Expand Up @@ -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("/", "/");
Expand All @@ -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");

Expand Down

0 comments on commit 408d98b

Please sign in to comment.