Skip to content

Commit

Permalink
deps: update uvwasi to 0.0.20 and fixup tests
Browse files Browse the repository at this point in the history
- update uvwasi to 0.0.20
- adjust tests to reflect udpated behaviour from
  nodejs/uvwasi#224 included
  in uvwasi 0.0.20

Signed-off-by: Michael Dawson <midawson@redhat.com>
PR-URL: #51355
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
  • Loading branch information
mhdawson authored and richardlau committed Mar 25, 2024
1 parent 401837b commit 4c8fa3e
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 44 deletions.
2 changes: 1 addition & 1 deletion deps/uvwasi/include/uvwasi.h
Expand Up @@ -11,7 +11,7 @@ extern "C" {

#define UVWASI_VERSION_MAJOR 0
#define UVWASI_VERSION_MINOR 0
#define UVWASI_VERSION_PATCH 19
#define UVWASI_VERSION_PATCH 20
#define UVWASI_VERSION_HEX ((UVWASI_VERSION_MAJOR << 16) | \
(UVWASI_VERSION_MINOR << 8) | \
(UVWASI_VERSION_PATCH))
Expand Down
118 changes: 94 additions & 24 deletions deps/uvwasi/src/path_resolver.c
Expand Up @@ -31,6 +31,42 @@ static char* uvwasi__strchr_slash(const char* s) {
return NULL;
}

static uvwasi_errno_t uvwasi__combine_paths(const uvwasi_t* uvwasi,
const char* path1,
uvwasi_size_t path1_len,
const char* path2,
uvwasi_size_t path2_len,
char** combined_path,
uvwasi_size_t* combined_len) {
/* This function joins two paths with '/'. */
uvwasi_errno_t err;
char* combined;
int combined_size;
int r;

*combined_path = NULL;
*combined_len = 0;

/* The max combined size is the path1 length + the path2 length
+ 2 for a terminating NULL and a possible path separator. */
combined_size = path1_len + path2_len + 2;
combined = uvwasi__malloc(uvwasi, combined_size);
if (combined == NULL) return UVWASI_ENOMEM;

r = snprintf(combined, combined_size, "%s/%s", path1, path2);
if (r <= 0) {
err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
goto exit;
}

err = UVWASI_ESUCCESS;
*combined_path = combined;
*combined_len = strlen(combined);

exit:
if (err != UVWASI_ESUCCESS) uvwasi__free(uvwasi, combined);
return err;
}

uvwasi_errno_t uvwasi__normalize_path(const char* path,
uvwasi_size_t path_len,
Expand Down Expand Up @@ -234,39 +270,35 @@ static uvwasi_errno_t uvwasi__normalize_relative_path(
uvwasi_errno_t err;
char* combined;
char* normalized;
int combined_size;
int fd_path_len;
int norm_len;
int r;
uvwasi_size_t combined_len;
uvwasi_size_t fd_path_len;
uvwasi_size_t norm_len;

*normalized_path = NULL;
*normalized_len = 0;

/* The max combined size is the path length + the file descriptor's path
length + 2 for a terminating NULL and a possible path separator. */
fd_path_len = strlen(fd->normalized_path);
combined_size = path_len + fd_path_len + 2;
combined = uvwasi__malloc(uvwasi, combined_size);
if (combined == NULL)
return UVWASI_ENOMEM;

normalized = uvwasi__malloc(uvwasi, combined_size);
err = uvwasi__combine_paths(uvwasi,
fd->normalized_path,
fd_path_len,
path,
path_len,
&combined,
&combined_len);
if (err != UVWASI_ESUCCESS) goto exit;

normalized = uvwasi__malloc(uvwasi, combined_len + 1);
if (normalized == NULL) {
err = UVWASI_ENOMEM;
goto exit;
}

r = snprintf(combined, combined_size, "%s/%s", fd->normalized_path, path);
if (r <= 0) {
err = uvwasi__translate_uv_error(uv_translate_sys_error(errno));
goto exit;
}

/* Normalize the input path. */
err = uvwasi__normalize_path(combined,
combined_size - 1,
combined_len,
normalized,
combined_size - 1);
combined_len);
if (err != UVWASI_ESUCCESS)
goto exit;

Expand Down Expand Up @@ -374,9 +406,14 @@ uvwasi_errno_t uvwasi__resolve_path(const uvwasi_t* uvwasi,
char* host_path;
char* normalized_path;
char* link_target;
char* normalized_parent;
char* resolved_link_target;
uvwasi_size_t input_len;
uvwasi_size_t host_path_len;
uvwasi_size_t normalized_len;
uvwasi_size_t link_target_len;
uvwasi_size_t normalized_parent_len;
uvwasi_size_t resolved_link_target_len;
int follow_count;
int r;

Expand All @@ -385,6 +422,8 @@ uvwasi_errno_t uvwasi__resolve_path(const uvwasi_t* uvwasi,
link_target = NULL;
follow_count = 0;
host_path = NULL;
normalized_parent = NULL;
resolved_link_target = NULL;

start:
normalized_path = NULL;
Expand Down Expand Up @@ -458,19 +497,47 @@ uvwasi_errno_t uvwasi__resolve_path(const uvwasi_t* uvwasi,
goto exit;
}

input_len = strlen(req.ptr);
link_target_len = strlen(req.ptr);
uvwasi__free(uvwasi, link_target);
link_target = uvwasi__malloc(uvwasi, input_len + 1);
link_target = uvwasi__malloc(uvwasi, link_target_len + 1);
if (link_target == NULL) {
uv_fs_req_cleanup(&req);
err = UVWASI_ENOMEM;
goto exit;
}

memcpy(link_target, req.ptr, input_len + 1);
input = link_target;
uvwasi__free(uvwasi, normalized_path);
memcpy(link_target, req.ptr, link_target_len + 1);
uv_fs_req_cleanup(&req);

if (1 == uvwasi__is_absolute_path(link_target, link_target_len)) {
input = link_target;
input_len = link_target_len;
} else {
uvwasi__free(uvwasi, normalized_parent);
uvwasi__free(uvwasi, resolved_link_target);

err = uvwasi__combine_paths(uvwasi,
normalized_path,
normalized_len,
"..",
2,
&normalized_parent,
&normalized_parent_len);
if (err != UVWASI_ESUCCESS) goto exit;
err = uvwasi__combine_paths(uvwasi,
normalized_parent,
normalized_parent_len,
link_target,
link_target_len,
&resolved_link_target,
&resolved_link_target_len);
if (err != UVWASI_ESUCCESS) goto exit;

input = resolved_link_target;
input_len = resolved_link_target_len;
}

uvwasi__free(uvwasi, normalized_path);
goto start;
}

Expand All @@ -484,5 +551,8 @@ uvwasi_errno_t uvwasi__resolve_path(const uvwasi_t* uvwasi,

uvwasi__free(uvwasi, link_target);
uvwasi__free(uvwasi, normalized_path);
uvwasi__free(uvwasi, normalized_parent);
uvwasi__free(uvwasi, resolved_link_target);

return err;
}
55 changes: 45 additions & 10 deletions deps/uvwasi/src/uvwasi.c
Expand Up @@ -8,6 +8,8 @@
# include <dirent.h>
# include <time.h>
#else
# define _CRT_INTERNAL_NONSTDC_NAMES 1
# include <sys/stat.h>
# include <io.h>
#endif /* _WIN32 */

Expand All @@ -17,6 +19,10 @@
# define UVWASI_FD_READDIR_SUPPORTED 1
#endif

#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif

#include "uvwasi.h"
#include "uvwasi_alloc.h"
#include "uv.h"
Expand All @@ -37,10 +43,13 @@

#define VALIDATE_FSTFLAGS_OR_RETURN(flags) \
do { \
if ((flags) & ~(UVWASI_FILESTAT_SET_ATIM | \
UVWASI_FILESTAT_SET_ATIM_NOW | \
UVWASI_FILESTAT_SET_MTIM | \
UVWASI_FILESTAT_SET_MTIM_NOW)) { \
uvwasi_fstflags_t f = flags; \
if (((f) & ~(UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW | \
UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) || \
((f) & (UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW)) \
== (UVWASI_FILESTAT_SET_ATIM | UVWASI_FILESTAT_SET_ATIM_NOW) || \
((f) & (UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) \
== (UVWASI_FILESTAT_SET_MTIM | UVWASI_FILESTAT_SET_MTIM_NOW)) { \
return UVWASI_EINVAL; \
} \
} while (0)
Expand Down Expand Up @@ -624,9 +633,10 @@ uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi,
uvwasi_advice_t advice) {
struct uvwasi_fd_wrap_t* wrap;
uvwasi_errno_t err;
uv_fs_t req;
int r;
#ifdef POSIX_FADV_NORMAL
int mapped_advice;
int r;
#endif /* POSIX_FADV_NORMAL */

UVWASI_DEBUG("uvwasi_fd_advise(uvwasi=%p, fd=%d, offset=%"PRIu64", "
Expand Down Expand Up @@ -679,14 +689,27 @@ uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi,
if (err != UVWASI_ESUCCESS)
return err;

r = uv_fs_fstat(NULL, &req, wrap->fd, NULL);
if (r == -1) {
err = uvwasi__translate_uv_error(r);
goto exit;
}

if (S_ISDIR(req.statbuf.st_mode)) {
err = UVWASI_EBADF;
goto exit;
}

err = UVWASI_ESUCCESS;

#ifdef POSIX_FADV_NORMAL
r = posix_fadvise(wrap->fd, offset, len, mapped_advice);
if (r != 0)
err = uvwasi__translate_uv_error(uv_translate_sys_error(r));
#endif /* POSIX_FADV_NORMAL */
exit:
uv_mutex_unlock(&wrap->mutex);
uv_fs_req_cleanup(&req);
return err;
}

Expand Down Expand Up @@ -1775,8 +1798,6 @@ uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi,
if (uvwasi == NULL || path == NULL)
return UVWASI_EINVAL;

VALIDATE_FSTFLAGS_OR_RETURN(fst_flags);

err = uvwasi_fd_table_get(uvwasi->fds,
fd,
&wrap,
Expand All @@ -1785,6 +1806,8 @@ uvwasi_errno_t uvwasi_path_filestat_set_times(uvwasi_t* uvwasi,
if (err != UVWASI_ESUCCESS)
return err;

VALIDATE_FSTFLAGS_OR_RETURN(fst_flags);

err = uvwasi__resolve_path(uvwasi,
wrap,
path,
Expand Down Expand Up @@ -2306,6 +2329,7 @@ uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi,
uvwasi_fd_t fd,
const char* new_path,
uvwasi_size_t new_path_len) {
char* truncated_old_path;
char* resolved_new_path;
struct uvwasi_fd_wrap_t* wrap;
uvwasi_errno_t err;
Expand All @@ -2332,6 +2356,15 @@ uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi,
if (err != UVWASI_ESUCCESS)
return err;

truncated_old_path = uvwasi__malloc(uvwasi, old_path_len + 1);
if (truncated_old_path == NULL) {
uv_mutex_unlock(&wrap->mutex);
return UVWASI_ENOMEM;
}

memcpy(truncated_old_path, old_path, old_path_len);
truncated_old_path[old_path_len] = '\0';

err = uvwasi__resolve_path(uvwasi,
wrap,
new_path,
Expand All @@ -2340,12 +2373,14 @@ uvwasi_errno_t uvwasi_path_symlink(uvwasi_t* uvwasi,
0);
if (err != UVWASI_ESUCCESS) {
uv_mutex_unlock(&wrap->mutex);
uvwasi__free(uvwasi, truncated_old_path);
return err;
}

/* Windows support may require setting the flags option. */
r = uv_fs_symlink(NULL, &req, old_path, resolved_new_path, 0, NULL);
r = uv_fs_symlink(NULL, &req, truncated_old_path, resolved_new_path, 0, NULL);
uv_mutex_unlock(&wrap->mutex);
uvwasi__free(uvwasi, truncated_old_path);
uvwasi__free(uvwasi, resolved_new_path);
uv_fs_req_cleanup(&req);
if (r != 0)
Expand Down Expand Up @@ -2696,7 +2731,7 @@ uvwasi_errno_t uvwasi_sock_shutdown(uvwasi_t* uvwasi,
uvwasi_sdflags_t how) {
struct uvwasi_fd_wrap_t* wrap;
uvwasi_errno_t err = 0;
shutdown_data_t shutdown_data;
shutdown_data_t shutdown_data = {0};

if (how & ~UVWASI_SHUT_WR)
return UVWASI_ENOTSUP;
Expand Down Expand Up @@ -2794,7 +2829,7 @@ uvwasi_errno_t uvwasi_sock_accept(uvwasi_t* uvwasi,
goto close_sock_and_error_exit;
}

int r = uv_accept((uv_stream_t*) wrap->sock, (uv_stream_t*) uv_connect_sock);
r = uv_accept((uv_stream_t*) wrap->sock, (uv_stream_t*) uv_connect_sock);
if (r == UV_EAGAIN) {
// still no connection or error so run the loop again
continue;
Expand Down
2 changes: 1 addition & 1 deletion test/wasi/c/create_symlink.c
Expand Up @@ -4,7 +4,7 @@
#include <unistd.h>

int main() {
const char* target = "./input.txt";
const char* target = "./input-in-subdir.txt";
const char* linkpath = "/sandbox/subdir/test_link";
char readlink_result[128];
size_t result_size = sizeof(readlink_result);
Expand Down
20 changes: 12 additions & 8 deletions test/wasi/test-wasi-symlinks.js
Expand Up @@ -42,6 +42,7 @@ if (process.argv[2] === 'wasi-child') {
const sandboxedFile = path.join(sandbox, 'input.txt');
const externalFile = tmpdir.resolve('outside.txt');
const sandboxedDir = path.join(sandbox, 'subdir');
const sandboxedFileInSubdir = path.join(sandboxedDir, 'input-in-subdir.txt');
const sandboxedSymlink = path.join(sandboxedDir, 'input_link.txt');
const escapingSymlink = path.join(sandboxedDir, 'outside.txt');
const loopSymlink1 = path.join(sandboxedDir, 'loop1');
Expand All @@ -52,13 +53,14 @@ if (process.argv[2] === 'wasi-child') {
fs.mkdirSync(sandboxedDir);
fs.mkdirSync(sandboxedTmp);
fs.writeFileSync(sandboxedFile, 'hello from input.txt', 'utf8');
fs.writeFileSync(sandboxedFileInSubdir, 'hello from input in subdir.txt',
'utf8');
fs.writeFileSync(externalFile, 'this should be inaccessible', 'utf8');
fs.symlinkSync(path.join('.', 'input.txt'), sandboxedSymlink, 'file');
fs.symlinkSync(path.join('..', 'outside.txt'), escapingSymlink, 'file');
fs.symlinkSync(path.join('subdir', 'loop2'),
loopSymlink1, 'file');
fs.symlinkSync(path.join('subdir', 'loop1'),
loopSymlink2, 'file');
fs.symlinkSync(path.join('.', 'input-in-subdir.txt'),
sandboxedSymlink, 'file');
fs.symlinkSync(path.join('..', '..', 'outside.txt'), escapingSymlink, 'file');
fs.symlinkSync('loop2', loopSymlink1, 'file');
fs.symlinkSync('loop1', loopSymlink2, 'file');

function runWASI(options) {
console.log('executing', options.test);
Expand All @@ -76,8 +78,10 @@ if (process.argv[2] === 'wasi-child') {
assert.strictEqual(child.stdout.toString(), options.stdout || '');
}

runWASI({ test: 'create_symlink', stdout: 'hello from input.txt' });
runWASI({ test: 'follow_symlink', stdout: 'hello from input.txt' });
runWASI({ test: 'create_symlink',
stdout: 'hello from input in subdir.txt' });
runWASI({ test: 'follow_symlink',
stdout: 'hello from input in subdir.txt' });
runWASI({ test: 'link' });
runWASI({ test: 'symlink_escape' });
runWASI({ test: 'symlink_loop' });
Expand Down
Binary file modified test/wasi/wasm/create_symlink.wasm
Binary file not shown.

0 comments on commit 4c8fa3e

Please sign in to comment.