deps: update uvwasi to 0.0.20 and fixup tests

- update uvwasi to 0.0.20
- adjust tests to reflect udpated behaviour from
  https://github.com/nodejs/uvwasi/pull/224 included
  in uvwasi 0.0.20

Signed-off-by: Michael Dawson <midawson@redhat.com>
PR-URL: https://github.com/nodejs/node/pull/51355
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
This commit is contained in:
Michael Dawson 2024-01-03 22:51:08 +00:00
parent 00ac5edff2
commit 3badecd125
6 changed files with 153 additions and 44 deletions

View File

@ -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))

View File

@ -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,
@ -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;
@ -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;
@ -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;
@ -458,19 +497,47 @@ start:
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;
}
@ -484,5 +551,8 @@ exit:
uvwasi__free(uvwasi, link_target);
uvwasi__free(uvwasi, normalized_path);
uvwasi__free(uvwasi, normalized_parent);
uvwasi__free(uvwasi, resolved_link_target);
return err;
}

View File

@ -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 */
@ -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"
@ -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)
@ -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", "
@ -679,6 +689,17 @@ 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
@ -686,7 +707,9 @@ uvwasi_errno_t uvwasi_fd_advise(uvwasi_t* uvwasi,
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;
}
@ -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,
@ -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,
@ -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;
@ -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,
@ -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)
@ -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;
@ -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;

View File

@ -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);

View File

@ -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');
@ -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);
@ -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' });

Binary file not shown.