From c943ca95c454a7c3996231be5af007d3e47dcc8e Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 2 Jan 2021 19:19:06 -0700 Subject: [PATCH] Kernel: Fix ProcFS returning Inodes that are being deleted There is a window between dropping the last reference and removing a ProcFSInode from the lookup map. So, when looking up we need to check if that Inode is being destructed. --- Kernel/FileSystem/ProcFS.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 5739287656..4c457c3a21 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -1101,12 +1101,20 @@ RefPtr ProcFS::get_inode(InodeIdentifier inode_id) const LOCKER(m_inodes_lock); auto it = m_inodes.find(inode_id.index()); - if (it == m_inodes.end()) { - auto inode = adopt(*new ProcFSInode(const_cast(*this), inode_id.index())); - m_inodes.set(inode_id.index(), inode.ptr()); - return inode; + if (it != m_inodes.end()) { + // It's possible that the ProcFSInode ref count was dropped to 0 or + // the ~ProcFSInode destructor is even running already, but blocked + // from removing it from this map. So we need to *try* to ref it, + // and if that fails we cannot return this instance anymore and just + // create a new one. + if (it->value->try_ref()) + return adopt(*it->value); + // We couldn't ref it, so just create a new one and replace the entry } - return (*it).value; + auto inode = adopt(*new ProcFSInode(const_cast(*this), inode_id.index())); + auto result = m_inodes.set(inode_id.index(), inode.ptr()); + ASSERT(result == ((it == m_inodes.end()) ? AK::HashSetResult::InsertedNewEntry : AK::HashSetResult::ReplacedExistingEntry)); + return inode; } ProcFSInode::ProcFSInode(ProcFS& fs, unsigned index) @@ -1117,7 +1125,9 @@ ProcFSInode::ProcFSInode(ProcFS& fs, unsigned index) ProcFSInode::~ProcFSInode() { LOCKER(fs().m_inodes_lock); - fs().m_inodes.remove(index()); + auto it = fs().m_inodes.find(index()); + if (it != fs().m_inodes.end() && it->value == this) + fs().m_inodes.remove(it); } InodeMetadata ProcFSInode::metadata() const