Skip to content
This repository has been archived by the owner on Oct 7, 2020. It is now read-only.

Commit

Permalink
wasi: support resolving symlinks
Browse files Browse the repository at this point in the history
This commit adds support for resolving symlinks during
path resolution. This commit also ports all of the remaining
tests from nodejs/node#27850, with
the 'poll' test currently disabled.
  • Loading branch information
cjihrig committed Nov 4, 2019
1 parent ab6f437 commit 3e749dc
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 1 deletion.
24 changes: 23 additions & 1 deletion deps/uvwasi/src/uvwasi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/outside.txt
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions test/fixtures/wasi/subdir/input_link.txt
1 change: 1 addition & 0 deletions test/fixtures/wasi/subdir/loop1
1 change: 1 addition & 0 deletions test/fixtures/wasi/subdir/loop2
1 change: 1 addition & 0 deletions test/fixtures/wasi/subdir/outside.txt
14 changes: 14 additions & 0 deletions test/wasi/c/follow_symlink.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include <assert.h>
#include <stdio.h>

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);
}
}
31 changes: 31 additions & 0 deletions test/wasi/c/poll.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <assert.h>
#include <poll.h>
#include <time.h>
#include <unistd.h>

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;
}
9 changes: 9 additions & 0 deletions test/wasi/c/symlink_escape.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>

int main() {
FILE* file = fopen("/sandbox/subdir/outside.txt", "r");
assert(file == NULL);
assert(errno == ENOTCAPABLE);
}
9 changes: 9 additions & 0 deletions test/wasi/c/symlink_loop.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>

int main() {
FILE* file = fopen("/sandbox/subdir/loop1", "r");
assert(file == NULL);
assert(errno == ELOOP);
}
4 changes: 4 additions & 0 deletions test/wasi/test-wasi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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' });
}
Binary file added test/wasi/wasm/follow_symlink.wasm
Binary file not shown.
Binary file added test/wasi/wasm/poll.wasm
Binary file not shown.
Binary file added test/wasi/wasm/symlink_escape.wasm
Binary file not shown.
Binary file added test/wasi/wasm/symlink_loop.wasm
Binary file not shown.

0 comments on commit 3e749dc

Please sign in to comment.