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.
This commit is contained in:
Augustin Cavalier
2018-12-12 19:05:14 -05:00
parent 64d1636fea
commit bee962a25e
2 changed files with 18 additions and 14 deletions
+2 -1
View File
@@ -428,7 +428,8 @@ dup2_fd(int oldfd, int newfd, bool kernel)
// the table size could be changed) // the table size could be changed)
if ((uint32)oldfd >= context->table_size if ((uint32)oldfd >= context->table_size
|| (uint32)newfd >= 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); mutex_unlock(&context->io_mutex);
return B_FILE_ERROR; return B_FILE_ERROR;
} }
+16 -13
View File
@@ -1955,21 +1955,23 @@ disconnect_mount_or_vnode_fds(struct fs_mount* mount,
sRoot, false); sRoot, false);
for (uint32 i = 0; i < context->table_size; i++) { for (uint32 i = 0; i < context->table_size; i++) {
if (struct file_descriptor* descriptor = context->fds[i]) { struct file_descriptor* descriptor = context->fds[i];
inc_fd_ref_count(descriptor); if (descriptor == NULL || (descriptor->open_mode & O_DISCONNECTED) != 0)
continue;
// if this descriptor points at this mount, we inc_fd_ref_count(descriptor);
// need to disconnect it to be able to unmount
struct vnode* vnode = fd_vnode(descriptor); // if this descriptor points at this mount, we
if (vnodeToDisconnect != NULL) { // need to disconnect it to be able to unmount
if (vnode == vnodeToDisconnect) struct vnode* vnode = fd_vnode(descriptor);
disconnect_fd(descriptor); if (vnodeToDisconnect != NULL) {
} else if ((vnode != NULL && vnode->mount == mount) if (vnode == vnodeToDisconnect)
|| (vnode == NULL && descriptor->u.mount == mount))
disconnect_fd(descriptor); 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++) { for (i = 0; i < tableSize; i++) {
struct file_descriptor* descriptor = parentContext->fds[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); bool closeOnExec = fd_close_on_exec(parentContext, i);
if (closeOnExec && purgeCloseOnExec) if (closeOnExec && purgeCloseOnExec)
continue; continue;