From bee962a25eca79801ba4b4d2b157a5d16d61e187 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Wed, 12 Dec 2018 19:03:11 -0500 Subject: [PATCH] kernel/fs: Consumers of context->fds[] must check O_DISCONNECTED. Since these do not go through get_fd, which would check for them, we need to do these checks manually in the relevant locations. Some of these changes were broken out from axeld's original commit, and some were found by my own auditing. --- src/system/kernel/fs/fd.cpp | 3 ++- src/system/kernel/fs/vfs.cpp | 29 ++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp index 838ae1fa78..df3af83434 100644 --- a/src/system/kernel/fs/fd.cpp +++ b/src/system/kernel/fs/fd.cpp @@ -428,7 +428,8 @@ dup2_fd(int oldfd, int newfd, bool kernel) // the table size could be changed) if ((uint32)oldfd >= context->table_size || (uint32)newfd >= context->table_size - || context->fds[oldfd] == NULL) { + || context->fds[oldfd] == NULL + || (context->fds[oldfd]->open_mode & O_DISCONNECTED) != 0) { mutex_unlock(&context->io_mutex); return B_FILE_ERROR; } diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 3993058c57..64d29413ad 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -1955,21 +1955,23 @@ disconnect_mount_or_vnode_fds(struct fs_mount* mount, sRoot, false); for (uint32 i = 0; i < context->table_size; i++) { - if (struct file_descriptor* descriptor = context->fds[i]) { - inc_fd_ref_count(descriptor); + struct file_descriptor* descriptor = context->fds[i]; + if (descriptor == NULL || (descriptor->open_mode & O_DISCONNECTED) != 0) + continue; - // if this descriptor points at this mount, we - // need to disconnect it to be able to unmount - struct vnode* vnode = fd_vnode(descriptor); - if (vnodeToDisconnect != NULL) { - if (vnode == vnodeToDisconnect) - disconnect_fd(descriptor); - } else if ((vnode != NULL && vnode->mount == mount) - || (vnode == NULL && descriptor->u.mount == mount)) + inc_fd_ref_count(descriptor); + + // if this descriptor points at this mount, we + // need to disconnect it to be able to unmount + struct vnode* vnode = fd_vnode(descriptor); + if (vnodeToDisconnect != NULL) { + if (vnode == vnodeToDisconnect) disconnect_fd(descriptor); + } else if ((vnode != NULL && vnode->mount == mount) + || (vnode == NULL && descriptor->u.mount == mount)) + disconnect_fd(descriptor); - put_fd(descriptor); - } + put_fd(descriptor); } } } @@ -4990,7 +4992,8 @@ vfs_new_io_context(io_context* parentContext, bool purgeCloseOnExec) for (i = 0; i < tableSize; i++) { struct file_descriptor* descriptor = parentContext->fds[i]; - if (descriptor != NULL) { + if (descriptor != NULL + && (descriptor->open_mode & O_DISCONNECTED) == 0) { bool closeOnExec = fd_close_on_exec(parentContext, i); if (closeOnExec && purgeCloseOnExec) continue;