[PATCH 3/5] selftests/landlock: add tests for chmod and chown restrictions

Jeffrey Bencteux
2026-04-12T10:08:39Z

This patch adds basic tests for the support of chmod and chown system
calls restriction in landlock.

Signed-off-by: Jeffrey Bencteux <jeff@bencteux.fr>
---
tools/testing/selftests/landlock/fs_test.c | 99 +++++++++++++++++++++-
1 file changed, 98 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index e5898dc7e53e..13d276558146 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -578,7 +578,9 @@ TEST_F_FORK(layout1, inval)
LANDLOCK_ACCESS_FS_WRITE_FILE | \
LANDLOCK_ACCESS_FS_READ_FILE | \
LANDLOCK_ACCESS_FS_TRUNCATE | \
- LANDLOCK_ACCESS_FS_IOCTL_DEV)
+ LANDLOCK_ACCESS_FS_IOCTL_DEV | \
+ LANDLOCK_ACCESS_FS_CHMOD | \
+ LANDLOCK_ACCESS_FS_CHOWN)

#define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV

@@ -4111,6 +4113,101 @@ TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes)
ASSERT_EQ(0, close(socket_fds[1]));
}

+static int test_chmod(const char *path, mode_t mode)
+{
+ if (chmod(path, mode) == -1)
+ return errno;
+ return 0;
+}
+
+TEST_F_FORK(layout1, chmod_file)
+{
+ const char *const file_rw_no_chmod = file1_s1d1;
+ const char *const file_chmod = file1_s1d2;
+
+ const struct rule rules[] = {
+ {
+ .path = file_rw_no_chmod,
+ .access = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE,
+ },
+ {
+ .path = file_chmod,
+ .access = LANDLOCK_ACCESS_FS_CHMOD,
+ },
+ {},
+ };
+
+ const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE |
+ LANDLOCK_ACCESS_FS_CHMOD;
+ int ruleset_fd;
+
+ /* Enables Landlock. */
+ ruleset_fd = create_ruleset(_metadata, handled, rules);
+
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /* Checks chmod rights when it is not allowed, mode is arbitrary */
+ EXPECT_EQ(EACCES, test_chmod(file_rw_no_chmod, 777));
+
+ /* Checks chmod rights when it is allowed, mode is arbitrary */
+ EXPECT_EQ(0, test_chmod(file_chmod, 777));
+}
+
+static int test_chown(const char *path, uid_t owner, gid_t group)
+{
+ if (chown(path, owner, group) == -1)
+ return errno;
+ return 0;
+}
+
+TEST_F_FORK(layout1, chown_file)
+{
+ const char *const file_rw_no_chown = file1_s1d1;
+ const char *const file_chown = file1_s1d2;
+
+ const struct rule rules[] = {
+ {
+ .path = file_rw_no_chown,
+ .access = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE,
+ },
+ {
+ .path = file_chown,
+ .access = LANDLOCK_ACCESS_FS_CHOWN,
+ },
+ {},
+ };
+
+ const __u64 handled = LANDLOCK_ACCESS_FS_READ_FILE |
+ LANDLOCK_ACCESS_FS_WRITE_FILE |
+ LANDLOCK_ACCESS_FS_CHOWN;
+ int ruleset_fd;
+
+ /* Enables Landlock. */
+ ruleset_fd = create_ruleset(_metadata, handled, rules);
+
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /*
+ * Checks chown rights when it is not allowed, owner and group are
+ * arbitrary.
+ */
+ EXPECT_EQ(EACCES, test_chown(file_rw_no_chown, 0, 0));
+
+ /*
+ * Checks chown rights when it is allowed, owner and group are
+ * arbitrary.
+ */
+ EXPECT_EQ(0, test_chown(file_chown, 0, 0));
+}
+
+
/* Invokes the FS_IOC_GETFLAGS IOCTL and returns its errno or 0. */
static int test_fs_ioc_getflags_ioctl(int fd)
{
--
2.53.0