selftests/landlock: Fully test file rename with "remove" access
authorMickaël Salaün <mic@digikod.net>
Fri, 6 May 2022 16:08:16 +0000 (18:08 +0200)
committerMickaël Salaün <mic@digikod.net>
Mon, 23 May 2022 11:27:50 +0000 (13:27 +0200)
These tests were missing to check the check_access_path() call with all
combinations of maybe_remove(old_dentry) and maybe_remove(new_dentry).

Extend layout1.link with a new complementary test and check that
REMOVE_FILE is not required to link a file.

Cc: Shuah Khan <shuah@kernel.org>
Link: https://lore.kernel.org/r/20220506160820.524344-7-mic@digikod.net
Cc: stable@vger.kernel.org
Signed-off-by: Mickaël Salaün <mic@digikod.net>
tools/testing/selftests/landlock/fs_test.c

index 75f9358..9165f6a 100644 (file)
@@ -1659,15 +1659,21 @@ TEST_F_FORK(layout1, execute)
 
 TEST_F_FORK(layout1, link)
 {
-       const struct rule rules[] = {
+       const struct rule layer1[] = {
                {
                        .path = dir_s1d2,
                        .access = LANDLOCK_ACCESS_FS_MAKE_REG,
                },
                {},
        };
-       const int ruleset_fd =
-               create_ruleset(_metadata, rules[0].access, rules);
+       const struct rule layer2[] = {
+               {
+                       .path = dir_s1d3,
+                       .access = LANDLOCK_ACCESS_FS_REMOVE_FILE,
+               },
+               {},
+       };
+       int ruleset_fd = create_ruleset(_metadata, layer1[0].access, layer1);
 
        ASSERT_LE(0, ruleset_fd);
 
@@ -1680,14 +1686,30 @@ TEST_F_FORK(layout1, link)
 
        ASSERT_EQ(-1, link(file2_s1d1, file1_s1d1));
        ASSERT_EQ(EACCES, errno);
+
        /* Denies linking because of reparenting. */
        ASSERT_EQ(-1, link(file1_s2d1, file1_s1d2));
        ASSERT_EQ(EXDEV, errno);
        ASSERT_EQ(-1, link(file2_s1d2, file1_s1d3));
        ASSERT_EQ(EXDEV, errno);
+       ASSERT_EQ(-1, link(file2_s1d3, file1_s1d2));
+       ASSERT_EQ(EXDEV, errno);
 
        ASSERT_EQ(0, link(file2_s1d2, file1_s1d2));
        ASSERT_EQ(0, link(file2_s1d3, file1_s1d3));
+
+       /* Prepares for next unlinks. */
+       ASSERT_EQ(0, unlink(file2_s1d2));
+       ASSERT_EQ(0, unlink(file2_s1d3));
+
+       ruleset_fd = create_ruleset(_metadata, layer2[0].access, layer2);
+       ASSERT_LE(0, ruleset_fd);
+       enforce_ruleset(_metadata, ruleset_fd);
+       ASSERT_EQ(0, close(ruleset_fd));
+
+       /* Checks that linkind doesn't require the ability to delete a file. */
+       ASSERT_EQ(0, link(file1_s1d2, file2_s1d2));
+       ASSERT_EQ(0, link(file1_s1d3, file2_s1d3));
 }
 
 TEST_F_FORK(layout1, rename_file)
@@ -1708,7 +1730,6 @@ TEST_F_FORK(layout1, rename_file)
 
        ASSERT_LE(0, ruleset_fd);
 
-       ASSERT_EQ(0, unlink(file1_s1d1));
        ASSERT_EQ(0, unlink(file1_s1d2));
 
        enforce_ruleset(_metadata, ruleset_fd);
@@ -1744,9 +1765,15 @@ TEST_F_FORK(layout1, rename_file)
        ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s2d2, AT_FDCWD, file1_s2d1,
                                RENAME_EXCHANGE));
        ASSERT_EQ(EACCES, errno);
+       /* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */
+       ASSERT_EQ(-1, rename(dir_s2d2, file1_s2d1));
+       ASSERT_EQ(EACCES, errno);
        ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s2d1, AT_FDCWD, dir_s2d2,
                                RENAME_EXCHANGE));
        ASSERT_EQ(EACCES, errno);
+       /* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */
+       ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
+       ASSERT_EQ(EACCES, errno);
 
        /* Renames files with different parents. */
        ASSERT_EQ(-1, rename(file1_s2d2, file1_s1d2));
@@ -1809,9 +1836,15 @@ TEST_F_FORK(layout1, rename_dir)
        ASSERT_EQ(-1, renameat2(AT_FDCWD, dir_s1d1, AT_FDCWD, dir_s2d1,
                                RENAME_EXCHANGE));
        ASSERT_EQ(EACCES, errno);
+       /* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */
+       ASSERT_EQ(-1, rename(dir_s1d2, file1_s1d1));
+       ASSERT_EQ(EACCES, errno);
        ASSERT_EQ(-1, renameat2(AT_FDCWD, file1_s1d1, AT_FDCWD, dir_s1d2,
                                RENAME_EXCHANGE));
        ASSERT_EQ(EACCES, errno);
+       /* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */
+       ASSERT_EQ(-1, rename(file1_s1d1, dir_s1d2));
+       ASSERT_EQ(EACCES, errno);
 
        /*
         * Exchanges and renames directory to the same parent, which allows