From 9811374b6b73cc3984c54900ae831d0e06d581ca Mon Sep 17 00:00:00 2001 From: Yage Hu Date: Fri, 14 Jun 2024 07:52:07 -0700 Subject: [PATCH] Disallow absolute path at the raw WASI level (#270) This commit fixes a `path_open` behavior that allows opening absolute paths. Although the path normalization correctly resolves the path and enforces the sandbox, it's still a good idea to converge with other runtimes here. fixes #269 Signed-off-by: Yage Hu --- src/path_resolver.c | 5 ++++ test/test-path-open-absolute.c | 53 ++++++++++++++++++++++++++++++++++ test/test-path-resolution.c | 26 ++++++++--------- 3 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 test/test-path-open-absolute.c diff --git a/src/path_resolver.c b/src/path_resolver.c index afafac0..77f0623 100644 --- a/src/path_resolver.c +++ b/src/path_resolver.c @@ -440,6 +440,11 @@ uvwasi_errno_t uvwasi__resolve_path(const uvwasi_t* uvwasi, normalized_parent = NULL; resolved_link_target = NULL; + if (uvwasi__is_absolute_path(input, input_len)) { + *resolved_path = NULL; + return UVWASI_ENOTCAPABLE; + } + start: normalized_path = NULL; err = UVWASI_ESUCCESS; diff --git a/test/test-path-open-absolute.c b/test/test-path-open-absolute.c new file mode 100644 index 0000000..a647035 --- /dev/null +++ b/test/test-path-open-absolute.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include "uvwasi.h" +#include "uv.h" +#include "test-common.h" + +#define TEST_TMP_DIR "./out/tmp" +#define TEST_FILE "/test-path-open-absolute.file" +#define OFLAGS_CREAT 1 +#define RIGHTS_FD_WRITE 64 + +int main(void) { + 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); + + 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, + TEST_FILE, + strlen(TEST_FILE) + 1, + OFLAGS_CREAT, + RIGHTS_FD_WRITE, + 0, + 0, + &fd); + assert(err == UVWASI_ENOTCAPABLE && "open absolute path should fail"); + + uvwasi_destroy(&uvwasi); + free(init_options.preopens); + + return 0; +} diff --git a/test/test-path-resolution.c b/test/test-path-resolution.c index 40b7415..4c03e2e 100644 --- a/test/test-path-resolution.c +++ b/test/test-path-resolution.c @@ -182,13 +182,13 @@ int main(void) { /* Arguments: fd mapped path, fd real path, path to resolve, expected path */ pass("/", "/foo", "test_path", "/foo/test_path"); - pass("/", "/foo", "/test_path", "/foo/test_path"); + pass("/", "/foo", "test_path", "/foo/test_path"); pass("/bar", "/baz", "test_path", "/baz/test_path"); pass("/bar", "/baz", "./test_path", "/baz/test_path"); pass("/bar", "/baz", "../bar/test_path", "/baz/test_path"); pass("/bar", "/baz", "../bar/./test_path/../test_path", "/baz/test_path"); - pass("/bar", "/baz", "/bar/test_path", "/baz/test_path"); - pass("/bar", "/baz", "/bar/../bar/test_path", "/baz/test_path"); + pass("/bar", "/baz", "bar/test_path", "/baz/bar/test_path"); + pass("/bar", "/baz", "bar/../bar/test_path", "/baz/bar/test_path"); pass(".", "/foo", "test_path", "/foo/test_path"); pass("./", "/foo", "test_path", "/foo/test_path"); pass(".", "/foo", "./test_path", "/foo/test_path"); @@ -222,16 +222,16 @@ int main(void) { create_symlink("./qux", TEST_TMP_DIR "/dir/quux"); /* Arguments: fd mapped path, fd real path, path to resolve, expected path */ - pass_follow("/", TEST_TMP_DIR, "/bar", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/bar2", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/bar3", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/bar4", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/bar5", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/baz", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/baz2", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/baz3", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/dir/qux", TEST_TMP_DIR "/foo"); - pass_follow("/", TEST_TMP_DIR, "/dir/quux", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "bar", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "bar2", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "bar3", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "bar4", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "bar5", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "baz", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "baz2", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "baz3", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "dir/qux", TEST_TMP_DIR "/foo"); + pass_follow("/", TEST_TMP_DIR, "dir/quux", TEST_TMP_DIR "/foo"); /* Arguments: fd mapped path, fd real path, path to resolve, expected error */ fail_follow("/dir", TEST_TMP_DIR "/dir", "/dir/qux", UVWASI_ENOTCAPABLE);