mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-06-18 02:59:21 +00:00
Add support for closing/renumbering preopen fds (#2578)
There doesn't appear to be a clear reason not to support this behavior.
It seems it was disallowed previously as a precaution. See
67e2e57b02
for more context.
This commit is contained in:
parent
94f276eab0
commit
913a1414ad
|
@ -339,7 +339,7 @@ fd_prestats_init(struct fd_prestats *pt)
|
||||||
|
|
||||||
// Grows the preopened resource table to a required lower bound and a
|
// Grows the preopened resource table to a required lower bound and a
|
||||||
// minimum number of free preopened resource table entries.
|
// minimum number of free preopened resource table entries.
|
||||||
static bool
|
static __wasi_errno_t
|
||||||
fd_prestats_grow(struct fd_prestats *pt, size_t min, size_t incr)
|
fd_prestats_grow(struct fd_prestats *pt, size_t min, size_t incr)
|
||||||
REQUIRES_EXCLUSIVE(pt->lock)
|
REQUIRES_EXCLUSIVE(pt->lock)
|
||||||
{
|
{
|
||||||
|
@ -353,7 +353,7 @@ fd_prestats_grow(struct fd_prestats *pt, size_t min, size_t incr)
|
||||||
struct fd_prestat *prestats =
|
struct fd_prestat *prestats =
|
||||||
wasm_runtime_malloc((uint32)(sizeof(*prestats) * size));
|
wasm_runtime_malloc((uint32)(sizeof(*prestats) * size));
|
||||||
if (prestats == NULL)
|
if (prestats == NULL)
|
||||||
return false;
|
return __WASI_ENOMEM;
|
||||||
|
|
||||||
if (pt->prestats && pt->size > 0) {
|
if (pt->prestats && pt->size > 0) {
|
||||||
bh_memcpy_s(prestats, (uint32)(sizeof(*prestats) * size),
|
bh_memcpy_s(prestats, (uint32)(sizeof(*prestats) * size),
|
||||||
|
@ -369,27 +369,39 @@ fd_prestats_grow(struct fd_prestats *pt, size_t min, size_t incr)
|
||||||
pt->prestats = prestats;
|
pt->prestats = prestats;
|
||||||
pt->size = size;
|
pt->size = size;
|
||||||
}
|
}
|
||||||
return true;
|
return __WASI_ESUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __wasi_errno_t
|
||||||
|
fd_prestats_insert_locked(struct fd_prestats *pt, const char *dir,
|
||||||
|
__wasi_fd_t fd)
|
||||||
|
{
|
||||||
|
// Grow the preopened resource table if needed.
|
||||||
|
__wasi_errno_t error = fd_prestats_grow(pt, fd, 1);
|
||||||
|
|
||||||
|
if (error != __WASI_ESUCCESS) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
pt->prestats[fd].dir = bh_strdup(dir);
|
||||||
|
|
||||||
|
if (pt->prestats[fd].dir == NULL)
|
||||||
|
return __WASI_ENOMEM;
|
||||||
|
|
||||||
|
return __WASI_ESUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserts a preopened resource record into the preopened resource table.
|
// Inserts a preopened resource record into the preopened resource table.
|
||||||
bool
|
bool
|
||||||
fd_prestats_insert(struct fd_prestats *pt, const char *dir, __wasi_fd_t fd)
|
fd_prestats_insert(struct fd_prestats *pt, const char *dir, __wasi_fd_t fd)
|
||||||
{
|
{
|
||||||
// Grow the preopened resource table if needed.
|
|
||||||
rwlock_wrlock(&pt->lock);
|
rwlock_wrlock(&pt->lock);
|
||||||
if (!fd_prestats_grow(pt, fd, 1)) {
|
|
||||||
rwlock_unlock(&pt->lock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pt->prestats[fd].dir = bh_strdup(dir);
|
__wasi_errno_t error = fd_prestats_insert_locked(pt, dir, fd);
|
||||||
|
|
||||||
rwlock_unlock(&pt->lock);
|
rwlock_unlock(&pt->lock);
|
||||||
|
|
||||||
if (pt->prestats[fd].dir == NULL)
|
return error == __WASI_ESUCCESS;
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Looks up a preopened resource table entry by number.
|
// Looks up a preopened resource table entry by number.
|
||||||
|
@ -408,6 +420,24 @@ fd_prestats_get_entry(struct fd_prestats *pt, __wasi_fd_t fd,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove a preopened resource record from the preopened resource table by
|
||||||
|
// number
|
||||||
|
static __wasi_errno_t
|
||||||
|
fd_prestats_remove_entry(struct fd_prestats *pt, __wasi_fd_t fd)
|
||||||
|
{
|
||||||
|
// Test for file descriptor existence.
|
||||||
|
if (fd >= pt->size)
|
||||||
|
return __WASI_EBADF;
|
||||||
|
struct fd_prestat *prestat = &pt->prestats[fd];
|
||||||
|
|
||||||
|
if (prestat->dir != NULL) {
|
||||||
|
wasm_runtime_free((void *)prestat->dir);
|
||||||
|
prestat->dir = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __WASI_ESUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
struct fd_object {
|
struct fd_object {
|
||||||
struct refcount refcount;
|
struct refcount refcount;
|
||||||
__wasi_filetype_t type;
|
__wasi_filetype_t type;
|
||||||
|
@ -837,25 +867,15 @@ __wasi_errno_t
|
||||||
wasmtime_ssp_fd_close(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
wasmtime_ssp_fd_close(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
||||||
struct fd_prestats *prestats, __wasi_fd_t fd)
|
struct fd_prestats *prestats, __wasi_fd_t fd)
|
||||||
{
|
{
|
||||||
// Don't allow closing a pre-opened resource.
|
|
||||||
// TODO: Eventually, we do want to permit this, once libpreopen in
|
|
||||||
// userspace is capable of removing entries from its tables as well.
|
|
||||||
{
|
|
||||||
rwlock_rdlock(&prestats->lock);
|
|
||||||
struct fd_prestat *prestat;
|
|
||||||
__wasi_errno_t error = fd_prestats_get_entry(prestats, fd, &prestat);
|
|
||||||
rwlock_unlock(&prestats->lock);
|
|
||||||
if (error == 0) {
|
|
||||||
return __WASI_ENOTSUP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the file descriptor.
|
// Validate the file descriptor.
|
||||||
struct fd_table *ft = curfds;
|
struct fd_table *ft = curfds;
|
||||||
rwlock_wrlock(&ft->lock);
|
rwlock_wrlock(&ft->lock);
|
||||||
|
rwlock_wrlock(&prestats->lock);
|
||||||
|
|
||||||
struct fd_entry *fe;
|
struct fd_entry *fe;
|
||||||
__wasi_errno_t error = fd_table_get_entry(ft, fd, 0, 0, &fe);
|
__wasi_errno_t error = fd_table_get_entry(ft, fd, 0, 0, &fe);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
rwlock_unlock(&prestats->lock);
|
||||||
rwlock_unlock(&ft->lock);
|
rwlock_unlock(&ft->lock);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -863,9 +883,20 @@ wasmtime_ssp_fd_close(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
||||||
// Remove it from the file descriptor table.
|
// Remove it from the file descriptor table.
|
||||||
struct fd_object *fo;
|
struct fd_object *fo;
|
||||||
fd_table_detach(ft, fd, &fo);
|
fd_table_detach(ft, fd, &fo);
|
||||||
|
|
||||||
|
// Remove it from the preopened resource table if it exists
|
||||||
|
error = fd_prestats_remove_entry(prestats, fd);
|
||||||
|
|
||||||
|
rwlock_unlock(&prestats->lock);
|
||||||
rwlock_unlock(&ft->lock);
|
rwlock_unlock(&ft->lock);
|
||||||
fd_object_release(exec_env, fo);
|
fd_object_release(exec_env, fo);
|
||||||
return 0;
|
|
||||||
|
// Ignore the error if there is no preopen associated with this fd
|
||||||
|
if (error == __WASI_EBADF) {
|
||||||
|
return __WASI_ESUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up a file descriptor object in a locked file descriptor table
|
// Look up a file descriptor object in a locked file descriptor table
|
||||||
|
@ -1081,33 +1112,21 @@ wasmtime_ssp_fd_renumber(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
||||||
struct fd_prestats *prestats, __wasi_fd_t from,
|
struct fd_prestats *prestats, __wasi_fd_t from,
|
||||||
__wasi_fd_t to)
|
__wasi_fd_t to)
|
||||||
{
|
{
|
||||||
// Don't allow renumbering over a pre-opened resource.
|
|
||||||
// TODO: Eventually, we do want to permit this, once libpreopen in
|
|
||||||
// userspace is capable of removing entries from its tables as well.
|
|
||||||
{
|
|
||||||
rwlock_rdlock(&prestats->lock);
|
|
||||||
struct fd_prestat *prestat;
|
|
||||||
__wasi_errno_t error = fd_prestats_get_entry(prestats, to, &prestat);
|
|
||||||
if (error != 0) {
|
|
||||||
error = fd_prestats_get_entry(prestats, from, &prestat);
|
|
||||||
}
|
|
||||||
rwlock_unlock(&prestats->lock);
|
|
||||||
if (error == 0) {
|
|
||||||
return __WASI_ENOTSUP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fd_table *ft = curfds;
|
struct fd_table *ft = curfds;
|
||||||
rwlock_wrlock(&ft->lock);
|
rwlock_wrlock(&ft->lock);
|
||||||
|
rwlock_wrlock(&prestats->lock);
|
||||||
|
|
||||||
struct fd_entry *fe_from;
|
struct fd_entry *fe_from;
|
||||||
__wasi_errno_t error = fd_table_get_entry(ft, from, 0, 0, &fe_from);
|
__wasi_errno_t error = fd_table_get_entry(ft, from, 0, 0, &fe_from);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
rwlock_unlock(&prestats->lock);
|
||||||
rwlock_unlock(&ft->lock);
|
rwlock_unlock(&ft->lock);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
struct fd_entry *fe_to;
|
struct fd_entry *fe_to;
|
||||||
error = fd_table_get_entry(ft, to, 0, 0, &fe_to);
|
error = fd_table_get_entry(ft, to, 0, 0, &fe_to);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
rwlock_unlock(&prestats->lock);
|
||||||
rwlock_unlock(&ft->lock);
|
rwlock_unlock(&ft->lock);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -1124,8 +1143,53 @@ wasmtime_ssp_fd_renumber(wasm_exec_env_t exec_env, struct fd_table *curfds,
|
||||||
fd_object_release(exec_env, fo);
|
fd_object_release(exec_env, fo);
|
||||||
--ft->used;
|
--ft->used;
|
||||||
|
|
||||||
|
// Handle renumbering of any preopened resources
|
||||||
|
struct fd_prestat *prestat_from;
|
||||||
|
__wasi_errno_t prestat_from_error =
|
||||||
|
fd_prestats_get_entry(prestats, from, &prestat_from);
|
||||||
|
|
||||||
|
struct fd_prestat *prestat_to;
|
||||||
|
__wasi_errno_t prestat_to_error =
|
||||||
|
fd_prestats_get_entry(prestats, to, &prestat_to);
|
||||||
|
|
||||||
|
// Renumbering over two preopened resources.
|
||||||
|
if (prestat_from_error == __WASI_ESUCCESS
|
||||||
|
&& prestat_to_error == __WASI_ESUCCESS) {
|
||||||
|
(void)fd_prestats_remove_entry(prestats, to);
|
||||||
|
|
||||||
|
error = fd_prestats_insert_locked(prestats, prestat_from->dir, to);
|
||||||
|
|
||||||
|
if (error == __WASI_ESUCCESS) {
|
||||||
|
(void)fd_prestats_remove_entry(prestats, from);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(void)fd_prestats_remove_entry(prestats, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Renumbering from a non-preopened fd to a preopened fd. In this case, we
|
||||||
|
// can't a keep the destination fd entry in the preopened table so remove
|
||||||
|
// it entirely.
|
||||||
|
else if (prestat_from_error != __WASI_ESUCCESS
|
||||||
|
&& prestat_to_error == __WASI_ESUCCESS) {
|
||||||
|
(void)fd_prestats_remove_entry(prestats, to);
|
||||||
|
}
|
||||||
|
// Renumbering from a preopened fd to a non-preopened fd
|
||||||
|
else if (prestat_from_error == __WASI_ESUCCESS
|
||||||
|
&& prestat_to_error != __WASI_ESUCCESS) {
|
||||||
|
error = fd_prestats_insert_locked(prestats, prestat_from->dir, to);
|
||||||
|
|
||||||
|
if (error == __WASI_ESUCCESS) {
|
||||||
|
(void)fd_prestats_remove_entry(prestats, from);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(void)fd_prestats_remove_entry(prestats, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rwlock_unlock(&prestats->lock);
|
||||||
rwlock_unlock(&ft->lock);
|
rwlock_unlock(&ft->lock);
|
||||||
return 0;
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
__wasi_errno_t
|
__wasi_errno_t
|
||||||
|
|
Loading…
Reference in New Issue
Block a user