From 328fd59f43e6773ee1e76b6ff9b6b8a380de72db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A4mes=20M=C3=A9n=C3=A9trey?= Date: Mon, 7 Nov 2022 12:56:16 +0100 Subject: [PATCH] linux-sgx: Allow to open files with arbitrary paths in the sandbox using IPFS (#1685) A limitation of the current implementation of SGX IPFS in WAMR is that it prevents to open files which are not in the current directory. This restriction is lifted and can now open files in paths, similarly to the WASI openat call, which takes into account the sandbox of the file system. --- core/shared/platform/linux-sgx/sgx_file.c | 45 ++++++++++++++++--- core/shared/platform/linux-sgx/sgx_file.h | 2 + core/shared/platform/linux-sgx/sgx_ipfs.c | 27 +++++++++-- core/shared/platform/linux-sgx/sgx_ipfs.h | 2 +- core/shared/platform/linux-sgx/sgx_wamr.edl | 3 ++ .../platform/linux-sgx/untrusted/file.c | 6 +++ samples/file/wasm-app/main.c | 7 ++- 7 files changed, 80 insertions(+), 12 deletions(-) diff --git a/core/shared/platform/linux-sgx/sgx_file.c b/core/shared/platform/linux-sgx/sgx_file.c index 772a8087..a8ae8d2f 100644 --- a/core/shared/platform/linux-sgx/sgx_file.c +++ b/core/shared/platform/linux-sgx/sgx_file.c @@ -88,6 +88,8 @@ ocall_linkat(int *p_ret, int olddirfd, const char *oldpath, int newdirfd, int ocall_unlinkat(int *p_ret, int dirfd, const char *pathname, int flags); int +ocall_readlink(ssize_t *p_ret, const char *pathname, char *buf, size_t bufsiz); +int ocall_readlinkat(ssize_t *p_ret, int dirfd, const char *pathname, char *buf, size_t bufsiz); int @@ -190,18 +192,29 @@ openat(int dirfd, const char *pathname, int flags, ...) errno = get_errno(); #if WASM_ENABLE_SGX_IPFS != 0 - // When WAMR uses Intel SGX IPFS to enabled, it opens a second - // file descriptor to interact with the secure file. - // The first file descriptor opened earlier is used to interact - // with the metadata of the file (e.g., time, flags, etc.). - int ret; - void *file_ptr = ipfs_fopen(fd, pathname, flags); - if (file_ptr == NULL) { + struct stat sb; + int ret = fstatat(dirfd, pathname, &sb, 0); + if (ret < 0) { if (ocall_close(&ret, fd) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); } return -1; } + + // Ony files are managed by SGX IPFS + if (S_ISREG(sb.st_mode)) { + // When WAMR uses Intel SGX IPFS to enabled, it opens a second + // file descriptor to interact with the secure file. + // The first file descriptor opened earlier is used to interact + // with the metadata of the file (e.g., time, flags, etc.). + void *file_ptr = ipfs_fopen(fd, flags); + if (file_ptr == NULL) { + if (ocall_close(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return -1; + } + } #endif return fd; @@ -699,6 +712,24 @@ unlinkat(int dirfd, const char *pathname, int flags) return ret; } +ssize_t +readlink(const char *pathname, char *buf, size_t bufsiz) +{ + ssize_t ret; + + if (buf == NULL) + return -1; + + if (ocall_readlink(&ret, pathname, buf, bufsiz) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { diff --git a/core/shared/platform/linux-sgx/sgx_file.h b/core/shared/platform/linux-sgx/sgx_file.h index c35c2246..8690e1f6 100644 --- a/core/shared/platform/linux-sgx/sgx_file.h +++ b/core/shared/platform/linux-sgx/sgx_file.h @@ -219,6 +219,8 @@ linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int unlinkat(int dirfd, const char *pathname, int flags); ssize_t +readlink(const char *pathname, char *buf, size_t bufsiz); +ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz); int symlinkat(const char *target, int newdirfd, const char *linkpath); diff --git a/core/shared/platform/linux-sgx/sgx_ipfs.c b/core/shared/platform/linux-sgx/sgx_ipfs.c index 5abb3687..2b0a38ff 100644 --- a/core/shared/platform/linux-sgx/sgx_ipfs.c +++ b/core/shared/platform/linux-sgx/sgx_ipfs.c @@ -248,7 +248,7 @@ ipfs_close(int fd) } void * -ipfs_fopen(int fd, const char *filename, int flags) +ipfs_fopen(int fd, int flags) { // Mapping back the mode const char *mode; @@ -291,8 +291,29 @@ ipfs_fopen(int fd, const char *filename, int flags) return NULL; } - // Opening the file - void *sgx_file = sgx_fopen_auto_key(filename, mode); + // Determine the symbolic link of the file descriptor, because IPFS does not + // support opening a relative path to a file descriptor (i.e., openat). + // Using the symbolic link in /proc/self allows to retrieve the same path as + // opened by the initial openat and respects the chroot of WAMR. + size_t ret; + char symbolic_path[32]; + ret = + snprintf(symbolic_path, sizeof(symbolic_path), "/proc/self/fd/%d", fd); + if (ret >= sizeof(symbolic_path)) { + errno = ENAMETOOLONG; + return NULL; + } + + // Resolve the symbolic link to real absolute path, because IPFS can only + // open a file with a same file name it was initially created. Otherwise, + // IPFS throws SGX_ERROR_FILE_NAME_MISMATCH. + char real_path[PATH_MAX] = { 0 }; + ret = readlink(symbolic_path, real_path, PATH_MAX - 1); + if (ret == -1) + return NULL; + + // Opening the file using the real path + void *sgx_file = sgx_fopen_auto_key(real_path, mode); if (sgx_file == NULL) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); diff --git a/core/shared/platform/linux-sgx/sgx_ipfs.h b/core/shared/platform/linux-sgx/sgx_ipfs.h index ade40bd5..e4de9027 100644 --- a/core/shared/platform/linux-sgx/sgx_ipfs.h +++ b/core/shared/platform/linux-sgx/sgx_ipfs.h @@ -28,7 +28,7 @@ ipfs_write(int fd, const struct iovec *iov, int iovcnt, bool has_offset, int ipfs_close(int fd); void * -ipfs_fopen(int fd, const char *filename, int flags); +ipfs_fopen(int fd, int flags); int ipfs_fflush(int fd); off_t diff --git a/core/shared/platform/linux-sgx/sgx_wamr.edl b/core/shared/platform/linux-sgx/sgx_wamr.edl index d8b6030d..7cb4817f 100644 --- a/core/shared/platform/linux-sgx/sgx_wamr.edl +++ b/core/shared/platform/linux-sgx/sgx_wamr.edl @@ -48,6 +48,9 @@ enclave { int flags); int ocall_unlinkat(int dirfd, [in, string]const char *pathname, int flags); + ssize_t ocall_readlink([in, string]const char *pathname, + [out, size=bufsiz]char *buf, + size_t bufsiz); ssize_t ocall_readlinkat(int dirfd, [in, string]const char *pathname, [out, size=bufsiz]char *buf, diff --git a/core/shared/platform/linux-sgx/untrusted/file.c b/core/shared/platform/linux-sgx/untrusted/file.c index 22abe7d8..cb9bf6a2 100644 --- a/core/shared/platform/linux-sgx/untrusted/file.c +++ b/core/shared/platform/linux-sgx/untrusted/file.c @@ -186,6 +186,12 @@ ocall_unlinkat(int dirfd, const char *pathname, int flags) return unlinkat(dirfd, pathname, flags); } +ssize_t +ocall_readlink(const char *pathname, char *buf, size_t bufsiz) +{ + return readlink(pathname, buf, bufsiz); +} + ssize_t ocall_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { diff --git a/samples/file/wasm-app/main.c b/samples/file/wasm-app/main.c index 9931f366..caf6436d 100644 --- a/samples/file/wasm-app/main.c +++ b/samples/file/wasm-app/main.c @@ -12,7 +12,8 @@ #include #include -#define PATH_TEST_FILE "test.txt" +#define PATH_TEST_FOLDER "./test" +#define PATH_TEST_FILE (PATH_TEST_FOLDER "/test.txt") #define FILE_TEXT "Hello, world!" #define WORLD_OFFSET 7 #define NAME_REPLACMENT "James" @@ -28,6 +29,10 @@ main(int argc, char **argv) int ret; long long stat_size; + // Test: Create a folder to store the file, if it does not exist yet + ret = mkdir(PATH_TEST_FOLDER, 777); + assert(ret == 0 || (ret == -1 && errno == EEXIST)); + // Test: File opening (fopen) printf("Opening a file..\n"); file = fopen(PATH_TEST_FILE, "w+");