Procházet zdrojové kódy

Ext2FS: Don't allow creating new files in removed directories

Also don't uncache inodes when they reach i_links_count==0 unless they
also have no ref counts other than the +1 from the inode cache.
This prevents the FS from deleting the on-disk inode too soon.
Andreas Kling před 5 roky
rodič
revize
9e54c7c17f
2 změnil soubory, kde provedl 29 přidání a 1 odebrání
  1. 7 1
      Kernel/FileSystem/Ext2FileSystem.cpp
  2. 22 0
      Userland/test_io.cpp

+ 7 - 1
Kernel/FileSystem/Ext2FileSystem.cpp

@@ -1333,6 +1333,12 @@ RefPtr<Inode> Ext2FS::create_inode(InodeIdentifier parent_id, const String& name
     LOCKER(m_lock);
     ASSERT(parent_id.fsid() == fsid());
     auto parent_inode = get_inode(parent_id);
+    ASSERT(parent_inode);
+
+    if (static_cast<const Ext2FSInode&>(*parent_inode).m_raw_inode.i_links_count == 0) {
+        error = -ENOENT;
+        return nullptr;
+    }
 
 #ifdef EXT2_DEBUG
     dbgprintf("Ext2FS: Adding inode '%s' (mode %o) to parent directory %u:\n", name.characters(), mode, parent_inode->identifier().index());
@@ -1491,7 +1497,7 @@ int Ext2FSInode::decrement_link_count()
         return -EROFS;
     ASSERT(m_raw_inode.i_links_count);
     --m_raw_inode.i_links_count;
-    if (m_raw_inode.i_links_count == 0)
+    if (ref_count() == 1 && m_raw_inode.i_links_count == 0)
         fs().uncache_inode(index());
     set_metadata_dirty(true);
     return 0;

+ 22 - 0
Userland/test_io.cpp

@@ -3,6 +3,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #define EXPECT_ERROR_2(err, syscall, arg1, arg2)                                                                                                                          \
@@ -208,6 +209,26 @@ void test_eoverflow()
     close(fd);
 }
 
+void test_rmdir_while_inside_dir()
+{
+    int rc = mkdir("/home/anon/testdir", 0700);
+    ASSERT(rc == 0);
+
+    rc = chdir("/home/anon/testdir");
+    ASSERT(rc == 0);
+
+    rc = rmdir("/home/anon/testdir");
+    ASSERT(rc == 0);
+
+    int fd = open("x", O_CREAT | O_RDWR, 0600);
+    if (fd >= 0 || errno != ENOENT) {
+        fprintf(stderr, "Expected ENOENT when trying to create a file inside a deleted directory. Got %d with errno=%d\n", fd, errno);
+    }
+
+    rc = chdir("/home/anon");
+    ASSERT(rc == 0);
+}
+
 int main(int, char**)
 {
     int rc;
@@ -232,6 +253,7 @@ int main(int, char**)
     test_open_create_device();
     test_unlink_symlink();
     test_eoverflow();
+    test_rmdir_while_inside_dir();
 
     return 0;
 }