Преглед изворни кода

Kernel/FS: Fix check-then-act concurrency bug in FileSystem/Inode

When the FileSystem does a sync, it gathers up all the inodes with
dirty metadata into a vector. The inode mutex is not held while
checking the inode dirty bit, which can lead to a kernel panic
due to concurrent inode modifications.

Fixes: #21796
Blake Smith пре 1 година
родитељ
комит
e346331424
2 измењених фајлова са 4 додато и 3 уклоњено
  1. 3 0
      Kernel/FileSystem/Ext2FS/Inode.cpp
  2. 1 3
      Kernel/FileSystem/Inode.cpp

+ 3 - 0
Kernel/FileSystem/Ext2FS/Inode.cpp

@@ -494,6 +494,9 @@ InodeMetadata Ext2FSInode::metadata() const
 ErrorOr<void> Ext2FSInode::flush_metadata()
 ErrorOr<void> Ext2FSInode::flush_metadata()
 {
 {
     MutexLocker locker(m_inode_lock);
     MutexLocker locker(m_inode_lock);
+    if (!is_metadata_dirty())
+        return {};
+
     dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::flush_metadata(): Flushing inode", identifier());
     dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::flush_metadata(): Flushing inode", identifier());
     TRY(fs().write_ext2_inode(index(), m_raw_inode));
     TRY(fs().write_ext2_inode(index(), m_raw_inode));
     if (is_directory()) {
     if (is_directory()) {

+ 1 - 3
Kernel/FileSystem/Inode.cpp

@@ -39,15 +39,13 @@ void Inode::sync_all()
     });
     });
 
 
     for (auto& inode : inodes) {
     for (auto& inode : inodes) {
-        VERIFY(inode->is_metadata_dirty());
         (void)inode->flush_metadata();
         (void)inode->flush_metadata();
     }
     }
 }
 }
 
 
 void Inode::sync()
 void Inode::sync()
 {
 {
-    if (is_metadata_dirty())
-        (void)flush_metadata();
+    (void)flush_metadata();
     auto result = fs().flush_writes();
     auto result = fs().flush_writes();
     if (result.is_error()) {
     if (result.is_error()) {
         // TODO: Figure out how to propagate error to a higher function.
         // TODO: Figure out how to propagate error to a higher function.