From c8b7710e5d8280d596bbfa35a18a36e108407bad Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 23 Sep 2019 18:27:46 +0200 Subject: [PATCH] libc: improve dup/dup2 in vfs_plugin This patch replaces the naive dup2 implementation (that merely duplicated the context pointer) by the replication of the original FD state by re-opening the same file with the same flags and seek position. This prevents a potential double release of the VFS handle (the FD context). It also implements 'dup'. Fixes #3505 Fixes #3477 --- .../libports/src/lib/libc/file_operations.cc | 2 +- .../src/lib/libc/internal/vfs_plugin.h | 1 + repos/libports/src/lib/libc/vfs_plugin.cc | 50 +++++++++++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/repos/libports/src/lib/libc/file_operations.cc b/repos/libports/src/lib/libc/file_operations.cc index 72d74c545..4b467baa7 100644 --- a/repos/libports/src/lib/libc/file_operations.cc +++ b/repos/libports/src/lib/libc/file_operations.cc @@ -268,7 +268,7 @@ extern "C" int dup2(int libc_fd, int new_libc_fd) close(new_libc_fd); new_fd = file_descriptor_allocator()->alloc(fd->plugin, 0, new_libc_fd); - new_fd->path(fd->fd_path); + /* new_fd->context must be assigned by the plugin implementing 'dup2' */ return fd->plugin->dup2(fd, new_fd); } diff --git a/repos/libports/src/lib/libc/internal/vfs_plugin.h b/repos/libports/src/lib/libc/internal/vfs_plugin.h index 47b887014..47e6d0875 100644 --- a/repos/libports/src/lib/libc/internal/vfs_plugin.h +++ b/repos/libports/src/lib/libc/internal/vfs_plugin.h @@ -86,6 +86,7 @@ class Libc::Vfs_plugin : public Plugin int access(char const *, int) override; int close(File_descriptor *) override; + File_descriptor *dup(File_descriptor *) override; int dup2(File_descriptor *, File_descriptor *) override; int fcntl(File_descriptor *, int, long) override; int fstat(File_descriptor *, struct stat *) override; diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index 1a0f755b9..0e324bb2b 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -425,11 +425,55 @@ int Libc::Vfs_plugin::close(File_descriptor *fd) int Libc::Vfs_plugin::dup2(File_descriptor *fd, File_descriptor *new_fd) { - new_fd->context = fd->context; + Vfs::Vfs_handle *handle = nullptr; + + typedef Vfs::Directory_service::Open_result Result; + + if (VFS_THREAD_SAFE(_root_dir.open(fd->fd_path, fd->flags, &handle, _alloc)) + != Result::OPEN_OK) { + + warning("dup2 failed for path ", fd->fd_path); + return Errno(EBADF); + } + + handle->seek(vfs_handle(fd)->seek()); + handle->handler(&_response_handler); + + new_fd->context = vfs_context(handle); + new_fd->flags = fd->flags; + new_fd->path(fd->fd_path); + return new_fd->libc_fd; } +Libc::File_descriptor *Libc::Vfs_plugin::dup(File_descriptor *fd) +{ + Vfs::Vfs_handle *handle = nullptr; + + typedef Vfs::Directory_service::Open_result Result; + + if (VFS_THREAD_SAFE(_root_dir.open(fd->fd_path, fd->flags, &handle, _alloc)) + != Result::OPEN_OK) { + + warning("dup failed for path ", fd->fd_path); + errno = EBADF; + return nullptr; + } + + handle->seek(vfs_handle(fd)->seek()); + handle->handler(&_response_handler); + + File_descriptor * const new_fd = + file_descriptor_allocator()->alloc(this, vfs_context(handle)); + + new_fd->flags = fd->flags; + new_fd->path(fd->fd_path); + + return new_fd; +} + + int Libc::Vfs_plugin::fstat(File_descriptor *fd, struct stat *buf) { Vfs::Vfs_handle *handle = vfs_handle(fd); @@ -990,13 +1034,11 @@ int Libc::Vfs_plugin::fcntl(File_descriptor *fd, int cmd, long arg) file_descriptor_allocator()->alloc(this, 0); if (!new_fd) return Errno(EMFILE); - new_fd->path(fd->fd_path); - /* * Use new allocated number as name of file descriptor * duplicate. */ - if (dup2(fd, new_fd) == -1) { + if (Vfs_plugin::dup2(fd, new_fd) == -1) { error("Plugin::fcntl: dup2 unexpectedly failed"); return Errno(EINVAL); }