From dc2cbab5315f191129ab22adc00ad4de02439a43 Mon Sep 17 00:00:00 2001 From: Yage Hu Date: Mon, 11 Dec 2023 13:05:37 -0800 Subject: [PATCH] Forbid fd_advise on directories (#240) * Forbid fd_advise on directories This commit adds a check to `fd_advise`. If the fd is a directory, return `ebadf`. This brings uvwasi in line with Wasmtime's behavior. WASI folks have stated that fd_advise should not work on directories as this is a Linux-specific behavior. --- src/uvwasi.c | 22 ++++++++++++++++++- test/test-fd-advise-dir.c | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 test/test-fd-advise-dir.c diff --git a/src/uvwasi.c b/src/uvwasi.c index 86f7762..0d345a8 100644 --- a/src/uvwasi.c +++ b/src/uvwasi.c @@ -8,6 +8,8 @@ # include # include #else +# define _CRT_INTERNAL_NONSTDC_NAMES 1 +# include # include #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" @@ -627,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", " @@ -682,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 @@ -689,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; } diff --git a/test/test-fd-advise-dir.c b/test/test-fd-advise-dir.c new file mode 100644 index 0000000..b579e24 --- /dev/null +++ b/test/test-fd-advise-dir.c @@ -0,0 +1,45 @@ +#include +#include + +#include "uv.h" +#include "uvwasi.h" +#include "test-common.h" + +#define TEST_TMP_DIR "./out/tmp" +#define TEST_PATH_ADVISE TEST_TMP_DIR "/test_fd_advise_dir" + +int main(void) { +#if !defined(_WIN32) && !defined(__ANDROID__) + uvwasi_t uvwasi; + uvwasi_options_t init_options; + uv_fs_t req; + uvwasi_errno_t err; + 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); + + r = uv_fs_mkdir(NULL, &req, TEST_PATH_ADVISE, 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_PATH_ADVISE; + + err = uvwasi_init(&uvwasi, &init_options); + assert(err == 0); + + err = uvwasi_fd_advise(&uvwasi, 3, 10, 20, UVWASI_ADVICE_DONTNEED); + assert(err == UVWASI_EBADF); + + uvwasi_destroy(&uvwasi); + free(init_options.preopens); +#endif /* !defined(_WIN32) && !defined(__ANDROID__) */ + return 0; +}