diff --git a/deps/uvwasi/src/uvwasi.c b/deps/uvwasi/src/uvwasi.c index 3b663cf912..979b0f20cf 100644 --- a/deps/uvwasi/src/uvwasi.c +++ b/deps/uvwasi/src/uvwasi.c @@ -34,11 +34,12 @@ static uvwasi_errno_t uvwasi__resolve_path(const struct uvwasi_fd_wrap_t* fd, /* TODO(cjihrig): path_len is treated as a size. Need to verify if path_len is really a string length or a size. Also need to verify if it is null terminated. */ - /* TODO(cjihrig): flags is currently unused. */ + uv_fs_t realpath_req; uvwasi_errno_t err; char* abs_path; char* tok; char* ptr; + int realpath_size; int abs_size; int input_is_absolute; int r; @@ -96,6 +97,27 @@ static uvwasi_errno_t uvwasi__resolve_path(const struct uvwasi_fd_wrap_t* fd, ptr += r; } + if ((flags & UVWASI_LOOKUP_SYMLINK_FOLLOW) == UVWASI_LOOKUP_SYMLINK_FOLLOW) { + r = uv_fs_realpath(NULL, &realpath_req, resolved_path, NULL); + if (r == 0) { + realpath_size = strlen(realpath_req.ptr) + 1; + if (realpath_size > PATH_MAX_BYTES) { + err = UVWASI_ENOBUFS; + uv_fs_req_cleanup(&realpath_req); + goto exit; + } + + memcpy(resolved_path, realpath_req.ptr, realpath_size); + } else if (r != UV_ENOENT) { + /* Report errors except ENOENT. */ + err = uvwasi__translate_uv_error(r); + uv_fs_req_cleanup(&realpath_req); + goto exit; + } + + uv_fs_req_cleanup(&realpath_req); + } + /* Verify that the resolved path is still in the sandbox. */ if (resolved_path != strstr(resolved_path, fd->real_path)) { err = UVWASI_ENOTCAPABLE; diff --git a/test/fixtures/outside.txt b/test/fixtures/outside.txt new file mode 100644 index 0000000000..044c4b9614 --- /dev/null +++ b/test/fixtures/outside.txt @@ -0,0 +1,2 @@ +this file is part of the WASI tests. it exists outside of the sandbox, and +should be inaccessible from the WASI tests. diff --git a/test/fixtures/wasi/subdir/input_link.txt b/test/fixtures/wasi/subdir/input_link.txt new file mode 120000 index 0000000000..4a6d09bf82 --- /dev/null +++ b/test/fixtures/wasi/subdir/input_link.txt @@ -0,0 +1 @@ +../input.txt \ No newline at end of file diff --git a/test/fixtures/wasi/subdir/loop1 b/test/fixtures/wasi/subdir/loop1 new file mode 120000 index 0000000000..433d7fdbce --- /dev/null +++ b/test/fixtures/wasi/subdir/loop1 @@ -0,0 +1 @@ +./loop2 \ No newline at end of file diff --git a/test/fixtures/wasi/subdir/loop2 b/test/fixtures/wasi/subdir/loop2 new file mode 120000 index 0000000000..2907735afc --- /dev/null +++ b/test/fixtures/wasi/subdir/loop2 @@ -0,0 +1 @@ +./loop1 \ No newline at end of file diff --git a/test/fixtures/wasi/subdir/outside.txt b/test/fixtures/wasi/subdir/outside.txt new file mode 120000 index 0000000000..2e06947067 --- /dev/null +++ b/test/fixtures/wasi/subdir/outside.txt @@ -0,0 +1 @@ +../../outside.txt \ No newline at end of file diff --git a/test/wasi/c/follow_symlink.c b/test/wasi/c/follow_symlink.c new file mode 100644 index 0000000000..badb0ee267 --- /dev/null +++ b/test/wasi/c/follow_symlink.c @@ -0,0 +1,14 @@ +#include +#include + +int main() { + FILE* file = fopen("/sandbox/subdir/input_link.txt", "r"); + assert(file != NULL); + + char c = fgetc(file); + while (c != EOF) { + int wrote = fputc(c, stdout); + assert(wrote != EOF); + c = fgetc(file); + } +} diff --git a/test/wasi/c/poll.c b/test/wasi/c/poll.c new file mode 100644 index 0000000000..6b6ef71fd6 --- /dev/null +++ b/test/wasi/c/poll.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include + +int main(void) { + struct pollfd fds[2]; + time_t before, now; + int ret; + + fds[0] = (struct pollfd){.fd = 1, .events = POLLOUT, .revents = 0}; + fds[1] = (struct pollfd){.fd = 2, .events = POLLOUT, .revents = 0}; + + ret = poll(fds, 2, -1); + assert(ret == 2); + assert(fds[0].revents == POLLOUT); + assert(fds[1].revents == POLLOUT); + + fds[0] = (struct pollfd){.fd = 0, .events = POLLIN, .revents = 0}; + time(&before); + ret = poll(fds, 1, 2000); + time(&now); + assert(ret == 0); + assert(now - before >= 2); + + sleep(1); + time(&now); + assert(now - before >= 3); + + return 0; +} diff --git a/test/wasi/c/symlink_escape.c b/test/wasi/c/symlink_escape.c new file mode 100644 index 0000000000..32dcc64eeb --- /dev/null +++ b/test/wasi/c/symlink_escape.c @@ -0,0 +1,9 @@ +#include +#include +#include + +int main() { + FILE* file = fopen("/sandbox/subdir/outside.txt", "r"); + assert(file == NULL); + assert(errno == ENOTCAPABLE); +} diff --git a/test/wasi/c/symlink_loop.c b/test/wasi/c/symlink_loop.c new file mode 100644 index 0000000000..23bd70ba60 --- /dev/null +++ b/test/wasi/c/symlink_loop.c @@ -0,0 +1,9 @@ +#include +#include +#include + +int main() { + FILE* file = fopen("/sandbox/subdir/loop1", "r"); + assert(file == NULL); + assert(errno == ELOOP); +} diff --git a/test/wasi/test-wasi.js b/test/wasi/test-wasi.js index 6ef821c1f2..b52c013d24 100644 --- a/test/wasi/test-wasi.js +++ b/test/wasi/test-wasi.js @@ -59,10 +59,12 @@ if (process.argv[2] === 'wasi-child') { runWASI({ test: 'clock_getres' }); runWASI({ test: 'exitcode', exitCode: 120 }); runWASI({ test: 'fd_prestat_get_refresh' }); + runWASI({ test: 'follow_symlink', stdout: 'hello from input.txt\n' }); // runWASI({ test: 'getentropy' }); runWASI({ test: 'getrusage' }); runWASI({ test: 'gettimeofday' }); runWASI({ test: 'notdir' }); + // runWASI({ test: 'poll' }); runWASI({ test: 'preopen_populates' }); runWASI({ test: 'read_file', stdout: 'hello from input.txt\n' }); runWASI({ @@ -71,5 +73,7 @@ if (process.argv[2] === 'wasi-child') { }); runWASI({ test: 'stat' }); runWASI({ test: 'stdin', stdin: 'hello world', stdout: 'hello world' }); + runWASI({ test: 'symlink_escape' }); + runWASI({ test: 'symlink_loop' }); runWASI({ test: 'write_file' }); } diff --git a/test/wasi/wasm/follow_symlink.wasm b/test/wasi/wasm/follow_symlink.wasm new file mode 100755 index 0000000000..48cf8da1eb Binary files /dev/null and b/test/wasi/wasm/follow_symlink.wasm differ diff --git a/test/wasi/wasm/poll.wasm b/test/wasi/wasm/poll.wasm new file mode 100755 index 0000000000..98d0736762 Binary files /dev/null and b/test/wasi/wasm/poll.wasm differ diff --git a/test/wasi/wasm/symlink_escape.wasm b/test/wasi/wasm/symlink_escape.wasm new file mode 100755 index 0000000000..0cdb8327a1 Binary files /dev/null and b/test/wasi/wasm/symlink_escape.wasm differ diff --git a/test/wasi/wasm/symlink_loop.wasm b/test/wasi/wasm/symlink_loop.wasm new file mode 100755 index 0000000000..3883d5278c Binary files /dev/null and b/test/wasi/wasm/symlink_loop.wasm differ