From 9b8fe049b3b7fb5b372513e9c35cd8f837e62226 Mon Sep 17 00:00:00 2001 From: "Alfred E. Neumayer" Date: Fri, 27 Oct 2023 06:48:10 +0200 Subject: [PATCH] core/iwasm: Support mapped file system access on non-libuv WASI (#2628) This patch enables mapping host directories to guest directories by parsing the `map_dir_list` argument in API `wasm_runtime_init_wasi` for libc-wasi. It follows the format `::`. It also adds argument `--map-dir=` argument for `iwasm` common line tool, and allows to add multiple mappings: ```bash iwasm --map-dir= --map-dir= ... ``` --- core/iwasm/common/wasm_runtime_common.c | 78 ++++++++++++++++++++++++- core/iwasm/include/wasm_export.h | 1 + product-mini/platforms/posix/main.c | 20 ++++++- 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index 8af58370..031fb539 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -3012,8 +3012,82 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - fd_table_insert_existing(curfds, wasm_fd, raw_fd); - fd_prestats_insert(prestats, dir_list[i], wasm_fd); + if (!fd_table_insert_existing(curfds, wasm_fd, raw_fd) + || !fd_prestats_insert(prestats, dir_list[i], wasm_fd)) { + if (error_buf) + snprintf( + error_buf, error_buf_size, + "error while pre-opening directory %s: insertion failed\n", + dir_list[i]); + goto fail; + } + } + + for (i = 0; i < map_dir_count; i++, wasm_fd++) { + char mapping_copy_buf[256]; + char *mapping_copy = mapping_copy_buf; + char *map_mapped = NULL, *map_host = NULL; + const unsigned long max_len = strlen(map_dir_list[i]) * 2 + 3; + + /* Allocation limit for runtime environments with reduced stack size */ + if (max_len > 256) { + if (!(mapping_copy = wasm_runtime_malloc(max_len))) { + snprintf(error_buf, error_buf_size, + "error while allocating for directory mapping\n"); + goto fail; + } + } + + strncpy(mapping_copy, map_dir_list[i], strlen(map_dir_list[i]) + 1); + map_mapped = strtok(mapping_copy, "::"); + map_host = strtok(NULL, "::"); + + if (!map_mapped || !map_host) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening mapped directory: " + "invalid map\n"); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + path = realpath(map_host, resolved_path); + if (!path) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening mapped directory %s: %d\n", + map_host, errno); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + raw_fd = open(path, O_RDONLY | O_DIRECTORY, 0); + if (raw_fd == -1) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening mapped directory %s: %d\n", + map_host, errno); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + if (!fd_table_insert_existing(curfds, wasm_fd, raw_fd) + || !fd_prestats_insert(prestats, map_mapped, wasm_fd)) { + if (error_buf) + snprintf(error_buf, error_buf_size, + "error while pre-opening mapped directory %s: " + "insertion failed\n", + dir_list[i]); + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); + goto fail; + } + + if (mapping_copy != mapping_copy_buf) + wasm_runtime_free(mapping_copy); } /* addr_pool(textual) -> apool */ diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 2a30ddc9..1d90cc37 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -423,6 +423,7 @@ wasm_runtime_get_module_hash(wasm_module_t module); * @param dir_list The list of directories to preopen. (real path) * @param dir_count The number of elements in dir_list. * @param map_dir_list The list of directories to preopen. (mapped path) + * Format for each map entry: :: * @param map_dir_count The number of elements in map_dir_list. * If map_dir_count is smaller than dir_count, * mapped path is assumed to be same as the diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index b27bd8c2..08fd65f1 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -75,6 +75,9 @@ print_help() printf(" --dir= Grant wasi access to the given host directories\n"); printf(" to the program, for example:\n"); printf(" --dir= --dir=\n"); + printf(" --map-dir= Grant wasi access to the given host directories\n"); + printf(" to the program at a specific guest path, for example:\n"); + printf(" --map-dir= --map-dir=\n"); printf(" --addr-pool= Grant wasi access to the given network addresses in\n"); printf(" CIRD notation to the program, seperated with ',',\n"); printf(" for example:\n"); @@ -573,6 +576,8 @@ main(int argc, char *argv[]) #if WASM_ENABLE_LIBC_WASI != 0 const char *dir_list[8] = { NULL }; uint32 dir_list_size = 0; + const char *map_dir_list[8] = { NULL }; + uint32 map_dir_list_size = 0; const char *env_list[8] = { NULL }; uint32 env_list_size = 0; const char *addr_pool[8] = { NULL }; @@ -711,6 +716,16 @@ main(int argc, char *argv[]) } dir_list[dir_list_size++] = argv[0] + 6; } + else if (!strncmp(argv[0], "--map-dir=", 10)) { + if (argv[0][10] == '\0') + return print_help(); + if (map_dir_list_size >= sizeof(map_dir_list) / sizeof(char *)) { + printf("Only allow max map dir number %d\n", + (int)(sizeof(map_dir_list) / sizeof(char *))); + return 1; + } + map_dir_list[map_dir_list_size++] = argv[0] + 10; + } else if (!strncmp(argv[0], "--env=", 6)) { char *tmp_env; @@ -920,8 +935,9 @@ main(int argc, char *argv[]) } #if WASM_ENABLE_LIBC_WASI != 0 - wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, NULL, 0, - env_list, env_list_size, argv, argc); + wasm_runtime_set_wasi_args(wasm_module, dir_list, dir_list_size, + map_dir_list, map_dir_list_size, env_list, + env_list_size, argv, argc); wasm_runtime_set_wasi_addr_pool(wasm_module, addr_pool, addr_pool_size); wasm_runtime_set_wasi_ns_lookup_pool(wasm_module, ns_lookup_pool,