Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcjihrig <cjihrig@gmail.com>2020-01-22 06:33:24 +0300
committerRich Trott <rtrott@gmail.com>2020-01-23 16:22:25 +0300
commitc150f9da7e52701d48aa12c2c1930b490c097a7b (patch)
tree5dd99a74825858a0542615df318422cf5df1135f /deps/uvwasi
parent28bee2444e4d30b762a031958855a601aec27fe1 (diff)
deps: uvwasi: cherry-pick c3bef8e
Original commit message: prevent locking fd table while holding a mutex uvwasi_path_rename(), uvwasi_path_link(), uvwasi_path_open(), and uvwasi_fd_renumber() operate on multiple file descriptors. uvwasi_fd_renumber() has been updated prior to this commit, and is not relevant here. The other three functions would perform the following locking operations: - lock the file table - acquire a file descriptor mutex - unlock the file table - unlock the file table again - acquire another file descriptor mutex - unlock the file table - unlock the two mutexes Attempting to acquire the second mutex introduced the possibility of deadlock because another thread could attempt to acquire the first mutex while holding the file table lock. This commit ensures that multiple mutexes are either: - acquired in a single lock of the file table - or, only acquired after releasing previously held mutexes Fixes: https://github.com/cjihrig/uvwasi/issues/89 PR-URL: https://github.com/nodejs/node/pull/31432 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: David Carlier <devnexen@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Diffstat (limited to 'deps/uvwasi')
-rw-r--r--deps/uvwasi/include/fd_table.h9
-rw-r--r--deps/uvwasi/src/fd_table.c67
-rw-r--r--deps/uvwasi/src/uvwasi.c106
3 files changed, 113 insertions, 69 deletions
diff --git a/deps/uvwasi/include/fd_table.h b/deps/uvwasi/include/fd_table.h
index 23a3bf52f42..9d88628e22c 100644
--- a/deps/uvwasi/include/fd_table.h
+++ b/deps/uvwasi/include/fd_table.h
@@ -46,11 +46,16 @@ uvwasi_errno_t uvwasi_fd_table_insert_preopen(struct uvwasi_s* uvwasi,
const uv_file fd,
const char* path,
const char* real_path);
-uvwasi_errno_t uvwasi_fd_table_get(const struct uvwasi_fd_table_t* table,
+uvwasi_errno_t uvwasi_fd_table_get(struct uvwasi_fd_table_t* table,
const uvwasi_fd_t id,
struct uvwasi_fd_wrap_t** wrap,
uvwasi_rights_t rights_base,
uvwasi_rights_t rights_inheriting);
+uvwasi_errno_t uvwasi_fd_table_get_nolock(struct uvwasi_fd_table_t* table,
+ const uvwasi_fd_t id,
+ struct uvwasi_fd_wrap_t** wrap,
+ uvwasi_rights_t rights_base,
+ uvwasi_rights_t rights_inheriting);
uvwasi_errno_t uvwasi_fd_table_remove(struct uvwasi_s* uvwasi,
struct uvwasi_fd_table_t* table,
const uvwasi_fd_t id);
@@ -58,5 +63,7 @@ uvwasi_errno_t uvwasi_fd_table_renumber(struct uvwasi_s* uvwasi,
struct uvwasi_fd_table_t* table,
const uvwasi_fd_t dst,
const uvwasi_fd_t src);
+uvwasi_errno_t uvwasi_fd_table_lock(struct uvwasi_fd_table_t* table);
+uvwasi_errno_t uvwasi_fd_table_unlock(struct uvwasi_fd_table_t* table);
#endif /* __UVWASI_FD_TABLE_H__ */
diff --git a/deps/uvwasi/src/fd_table.c b/deps/uvwasi/src/fd_table.c
index e4897769d98..c15ea092575 100644
--- a/deps/uvwasi/src/fd_table.c
+++ b/deps/uvwasi/src/fd_table.c
@@ -252,44 +252,57 @@ uvwasi_errno_t uvwasi_fd_table_insert_preopen(uvwasi_t* uvwasi,
}
-uvwasi_errno_t uvwasi_fd_table_get(const struct uvwasi_fd_table_t* table,
+uvwasi_errno_t uvwasi_fd_table_get(struct uvwasi_fd_table_t* table,
const uvwasi_fd_t id,
struct uvwasi_fd_wrap_t** wrap,
uvwasi_rights_t rights_base,
uvwasi_rights_t rights_inheriting) {
- struct uvwasi_fd_wrap_t* entry;
uvwasi_errno_t err;
- if (table == NULL || wrap == NULL)
+ if (table == NULL)
return UVWASI_EINVAL;
- uv_rwlock_rdlock((uv_rwlock_t *)&table->rwlock);
+ uv_rwlock_wrlock(&table->rwlock);
+ err = uvwasi_fd_table_get_nolock(table,
+ id,
+ wrap,
+ rights_base,
+ rights_inheriting);
+ uv_rwlock_wrunlock(&table->rwlock);
+ return err;
+}
- if (id >= table->size) {
- err = UVWASI_EBADF;
- goto exit;
- }
+
+/* uvwasi_fd_table_get_nolock() retrieves a file descriptor and locks its mutex,
+ but does not lock the file descriptor table like uvwasi_fd_table_get() does.
+*/
+uvwasi_errno_t uvwasi_fd_table_get_nolock(struct uvwasi_fd_table_t* table,
+ const uvwasi_fd_t id,
+ struct uvwasi_fd_wrap_t** wrap,
+ uvwasi_rights_t rights_base,
+ uvwasi_rights_t rights_inheriting) {
+ struct uvwasi_fd_wrap_t* entry;
+
+ if (table == NULL || wrap == NULL)
+ return UVWASI_EINVAL;
+
+ if (id >= table->size)
+ return UVWASI_EBADF;
entry = table->fds[id];
- if (entry == NULL || entry->id != id) {
- err = UVWASI_EBADF;
- goto exit;
- }
+ if (entry == NULL || entry->id != id)
+ return UVWASI_EBADF;
/* Validate that the fd has the necessary rights. */
if ((~entry->rights_base & rights_base) != 0 ||
(~entry->rights_inheriting & rights_inheriting) != 0) {
- err = UVWASI_ENOTCAPABLE;
- goto exit;
+ return UVWASI_ENOTCAPABLE;
}
uv_mutex_lock(&entry->mutex);
*wrap = entry;
- err = UVWASI_ESUCCESS;
-exit:
- uv_rwlock_rdunlock((uv_rwlock_t *)&table->rwlock);
- return err;
+ return UVWASI_ESUCCESS;
}
@@ -389,3 +402,21 @@ exit:
uv_rwlock_wrunlock(&table->rwlock);
return err;
}
+
+
+uvwasi_errno_t uvwasi_fd_table_lock(struct uvwasi_fd_table_t* table) {
+ if (table == NULL)
+ return UVWASI_EINVAL;
+
+ uv_rwlock_wrlock(&table->rwlock);
+ return UVWASI_ESUCCESS;
+}
+
+
+uvwasi_errno_t uvwasi_fd_table_unlock(struct uvwasi_fd_table_t* table) {
+ if (table == NULL)
+ return UVWASI_EINVAL;
+
+ uv_rwlock_wrunlock(&table->rwlock);
+ return UVWASI_ESUCCESS;
+}
diff --git a/deps/uvwasi/src/uvwasi.c b/deps/uvwasi/src/uvwasi.c
index e4c2ac6e3b0..9fa4db8a521 100644
--- a/deps/uvwasi/src/uvwasi.c
+++ b/deps/uvwasi/src/uvwasi.c
@@ -1763,37 +1763,41 @@ uvwasi_errno_t uvwasi_path_link(uvwasi_t* uvwasi,
if (uvwasi == NULL || old_path == NULL || new_path == NULL)
return UVWASI_EINVAL;
- if (old_fd == new_fd) {
- err = uvwasi_fd_table_get(&uvwasi->fds,
- old_fd,
- &old_wrap,
- UVWASI_RIGHT_PATH_LINK_SOURCE |
- UVWASI_RIGHT_PATH_LINK_TARGET,
- 0);
- if (err != UVWASI_ESUCCESS)
- return err;
+ uvwasi_fd_table_lock(&uvwasi->fds);
+ if (old_fd == new_fd) {
+ err = uvwasi_fd_table_get_nolock(&uvwasi->fds,
+ old_fd,
+ &old_wrap,
+ UVWASI_RIGHT_PATH_LINK_SOURCE |
+ UVWASI_RIGHT_PATH_LINK_TARGET,
+ 0);
new_wrap = old_wrap;
} else {
- err = uvwasi_fd_table_get(&uvwasi->fds,
- old_fd,
- &old_wrap,
- UVWASI_RIGHT_PATH_LINK_SOURCE,
- 0);
- if (err != UVWASI_ESUCCESS)
- return err;
-
- err = uvwasi_fd_table_get(&uvwasi->fds,
- new_fd,
- &new_wrap,
- UVWASI_RIGHT_PATH_LINK_TARGET,
- 0);
+ err = uvwasi_fd_table_get_nolock(&uvwasi->fds,
+ old_fd,
+ &old_wrap,
+ UVWASI_RIGHT_PATH_LINK_SOURCE,
+ 0);
if (err != UVWASI_ESUCCESS) {
- uv_mutex_unlock(&old_wrap->mutex);
+ uvwasi_fd_table_unlock(&uvwasi->fds);
return err;
}
+
+ err = uvwasi_fd_table_get_nolock(&uvwasi->fds,
+ new_fd,
+ &new_wrap,
+ UVWASI_RIGHT_PATH_LINK_TARGET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ uv_mutex_unlock(&old_wrap->mutex);
}
+ uvwasi_fd_table_unlock(&uvwasi->fds);
+
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
err = uvwasi__resolve_path(uvwasi,
old_wrap,
old_path,
@@ -1922,12 +1926,11 @@ uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi,
}
r = uv_fs_open(NULL, &req, resolved_path, flags, 0666, NULL);
+ uv_mutex_unlock(&dirfd_wrap->mutex);
uv_fs_req_cleanup(&req);
- if (r < 0) {
- uv_mutex_unlock(&dirfd_wrap->mutex);
+ if (r < 0)
return uvwasi__translate_uv_error(r);
- }
/* Not all platforms support UV_FS_O_DIRECTORY, so get the file type and check
it here. */
@@ -1960,11 +1963,9 @@ uvwasi_errno_t uvwasi_path_open(uvwasi_t* uvwasi,
*fd = wrap->id;
uv_mutex_unlock(&wrap->mutex);
- uv_mutex_unlock(&dirfd_wrap->mutex);
return UVWASI_ESUCCESS;
close_file_and_error_exit:
- uv_mutex_unlock(&dirfd_wrap->mutex);
uv_fs_close(NULL, &req, r, NULL);
uv_fs_req_cleanup(&req);
return err;
@@ -2079,36 +2080,41 @@ uvwasi_errno_t uvwasi_path_rename(uvwasi_t* uvwasi,
if (uvwasi == NULL || old_path == NULL || new_path == NULL)
return UVWASI_EINVAL;
+ uvwasi_fd_table_lock(&uvwasi->fds);
+
if (old_fd == new_fd) {
- err = uvwasi_fd_table_get(&uvwasi->fds,
- old_fd,
- &old_wrap,
- UVWASI_RIGHT_PATH_RENAME_SOURCE |
- UVWASI_RIGHT_PATH_RENAME_TARGET,
- 0);
- if (err != UVWASI_ESUCCESS)
- return err;
+ err = uvwasi_fd_table_get_nolock(&uvwasi->fds,
+ old_fd,
+ &old_wrap,
+ UVWASI_RIGHT_PATH_RENAME_SOURCE |
+ UVWASI_RIGHT_PATH_RENAME_TARGET,
+ 0);
new_wrap = old_wrap;
} else {
- err = uvwasi_fd_table_get(&uvwasi->fds,
- old_fd,
- &old_wrap,
- UVWASI_RIGHT_PATH_RENAME_SOURCE,
- 0);
- if (err != UVWASI_ESUCCESS)
- return err;
-
- err = uvwasi_fd_table_get(&uvwasi->fds,
- new_fd,
- &new_wrap,
- UVWASI_RIGHT_PATH_RENAME_TARGET,
- 0);
+ err = uvwasi_fd_table_get_nolock(&uvwasi->fds,
+ old_fd,
+ &old_wrap,
+ UVWASI_RIGHT_PATH_RENAME_SOURCE,
+ 0);
if (err != UVWASI_ESUCCESS) {
- uv_mutex_unlock(&old_wrap->mutex);
+ uvwasi_fd_table_unlock(&uvwasi->fds);
return err;
}
+
+ err = uvwasi_fd_table_get_nolock(&uvwasi->fds,
+ new_fd,
+ &new_wrap,
+ UVWASI_RIGHT_PATH_RENAME_TARGET,
+ 0);
+ if (err != UVWASI_ESUCCESS)
+ uv_mutex_unlock(&old_wrap->mutex);
}
+ uvwasi_fd_table_unlock(&uvwasi->fds);
+
+ if (err != UVWASI_ESUCCESS)
+ return err;
+
err = uvwasi__resolve_path(uvwasi,
old_wrap,
old_path,