Wasm: Add support for directory access.

Due to the sandboxed nature of WebAssembly, by default WASM modules
don't have any access to the underlying filesystem.

There is however a capabilities based mechanism[0] for allowing such
access.

This adds a config option to the 'wasm' application type;
'access.filesystem' which takes an array of directory paths that are
then made available to the WASM module. This access works recursively,
i.e everything under a specific path is allowed access to.

Example config might look like

  "access" {
      "filesystem": [
          "/tmp",
          "/var/tmp"
      ]
  }

The actual mechanism used allows directories to be mapped differently in
the guest. But at the moment we don't support that and just map say /tmp
to /tmp. This can be revisited if it's something users clamour for.

Network sockets are another resource that may be controlled in this
manner, for example there is a wasi_config_preopen_socket() function,
however this requires the runtime to open the network socket then
effectively pass this through to the guest.

This is something that can be revisited in the future if users desire
it.

[0]:
<https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-capabilities.md>

Reviewed-by: Alejandro Colomar <alx@nginx.com>
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
This commit is contained in:
Andrew Clayton
2023-08-09 18:22:46 +01:00
parent e99854afdf
commit 47ff51009f
6 changed files with 69 additions and 1 deletions

View File

@@ -99,6 +99,8 @@ typedef struct {
const char *request_init_handler;
const char *request_end_handler;
const char *response_end_handler;
nxt_conf_value_t *access;
} nxt_wasm_app_conf_t;

View File

@@ -252,6 +252,7 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_target_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_php_common_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_php_options_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_php_target_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_access_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_app_limits_members[];
static nxt_conf_vldt_object_t nxt_conf_vldt_app_processes_members[];
@@ -1081,12 +1082,27 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_members[] = {
}, {
.name = nxt_string("response_end_handler"),
.type = NXT_CONF_VLDT_STRING,
}, {
.name = nxt_string("access"),
.type = NXT_CONF_VLDT_OBJECT,
.validator = nxt_conf_vldt_object,
.u.members = nxt_conf_vldt_wasm_access_members,
},
NXT_CONF_VLDT_NEXT(nxt_conf_vldt_common_members)
};
static nxt_conf_vldt_object_t nxt_conf_vldt_wasm_access_members[] = {
{
.name = nxt_string("filesystem"),
.type = NXT_CONF_VLDT_ARRAY,
},
NXT_CONF_VLDT_END
};
static nxt_conf_vldt_object_t nxt_conf_vldt_common_members[] = {
{
.name = nxt_string("type"),

View File

@@ -369,6 +369,11 @@ static nxt_conf_map_t nxt_wasm_app_conf[] = {
NXT_CONF_MAP_CSTRZ,
offsetof(nxt_common_app_conf_t, u.wasm.response_end_handler),
},
{
nxt_string("access"),
NXT_CONF_MAP_PTR,
offsetof(nxt_common_app_conf_t, u.wasm.access),
},
};

View File

@@ -247,6 +247,7 @@ nxt_wasmtime_get_function_exports(nxt_wasm_ctx_t *ctx)
static int
nxt_wasmtime_wasi_init(const nxt_wasm_ctx_t *ctx)
{
char **dir;
wasi_config_t *wasi_config;
wasmtime_error_t *error;
nxt_wasmtime_ctx_t *rt_ctx = &nxt_wasmtime_ctx;
@@ -258,6 +259,10 @@ nxt_wasmtime_wasi_init(const nxt_wasm_ctx_t *ctx)
wasi_config_inherit_stdout(wasi_config);
wasi_config_inherit_stderr(wasi_config);
for (dir = ctx->dirs; dir != NULL && *dir != NULL; dir++) {
wasi_config_preopen_dir(wasi_config, *dir, *dir);
}
error = wasmtime_context_set_wasi(rt_ctx->ctx, wasi_config);
if (error != NULL) {
nxt_wasmtime_err_msg(error, NULL, "failed to instantiate WASI");

View File

@@ -204,6 +204,15 @@ nxt_wasm_start(nxt_task_t *task, nxt_process_data_t *data)
nxt_unit_done(unit_ctx);
NXT_WASM_DO_HOOK(NXT_WASM_FH_MODULE_END);
if (nxt_wasm_ctx.dirs != NULL) {
char **p;
for (p = nxt_wasm_ctx.dirs; *p != NULL; p++) {
nxt_free(*p);
}
nxt_free(nxt_wasm_ctx.dirs);
}
nxt_wops->destroy(&nxt_wasm_ctx);
exit(EXIT_SUCCESS);
@@ -214,9 +223,11 @@ static nxt_int_t
nxt_wasm_setup(nxt_task_t *task, nxt_process_t *process,
nxt_common_app_conf_t *conf)
{
int err;
int n, i, err;
nxt_conf_value_t *dirs = NULL;
nxt_wasm_app_conf_t *c;
nxt_wasm_func_handler_t *fh;
static nxt_str_t filesystem_str = nxt_string("filesystem");
c = &conf->u.wasm;
@@ -237,6 +248,33 @@ nxt_wasm_setup(nxt_task_t *task, nxt_process_t *process,
fh[NXT_WASM_FH_REQUEST_END].func_name = c->request_end_handler;
fh[NXT_WASM_FH_RESPONSE_END].func_name = c->response_end_handler;
/* Get any directories to pass through to the WASM module */
if (c->access != NULL) {
dirs = nxt_conf_get_object_member(c->access, &filesystem_str, NULL);
}
n = (dirs != NULL) ? nxt_conf_object_members_count(dirs) : 0;
if (n == 0) {
goto out_init;
}
nxt_wasm_ctx.dirs = nxt_zalloc((n + 1) * sizeof(char *));
if (nxt_slow_path(nxt_wasm_ctx.dirs == NULL)) {
return NXT_ERROR;
}
for (i = 0; i < n; i++) {
nxt_str_t str;
nxt_conf_value_t *value;
value = nxt_conf_get_array_element(dirs, i);
nxt_conf_get_string(value, &str);
nxt_wasm_ctx.dirs[i] = nxt_zalloc(str.length + 1);
memcpy(nxt_wasm_ctx.dirs[i], str.start, str.length);
}
out_init:
err = nxt_wops->init(&nxt_wasm_ctx);
if (err) {
exit(EXIT_FAILURE);

View File

@@ -110,6 +110,8 @@ struct nxt_wasm_ctx_s {
nxt_wasm_func_handler_t fh[NXT_WASM_FH_NR];
char **dirs;
nxt_unit_request_info_t *req;
uint8_t *baddr;