* [PATCH v2 0/3] landlock: Restrict renameat2 with RENAME_WHITEOUT
@ 2026-05-13 16:05 Günther Noack
2026-05-13 16:05 ` [PATCH v2 1/3] landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT Günther Noack
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
Hello!
As discussed in [1], the renameat2() syscall's RENAME_WHITEOUT flag allows
the creation of chardev directory entries with major=minor=0 as "whiteout
objects" in the location of the rename source file [2].
This functionality is available even without having any OverlayFS mounted
and can be invoked with the regular renameat2(2) syscall [3].
In V1 [5], it was discussed that whiteout objects are not the same as
character devices, and should therefore be guarded with a separate access
right. We are therefore guarding the operation with the new access right
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT now.
By introducing a new access right, that change is also exposed by
incrementing the ABI level and does not require a Landlock erratum.
Motivation
==========
The RENAME_WHITEOUT flag side-steps all of the existing Landlock access
rights, which are designed to restrict the creation of directory entries.
It is desirable to restrict that.
This patch set fixes that by adding a check in Landlock's path_rename hook.
Tradeoffs considered in the implementation
==========================================
* Should the access right check be merged into the longer
current_check_refer_path() function?
I am leaning towards keeping it as a special case earlier. This means
that we traverse the source path twice, but as we have seen in Debian
Code Search, there are apparently no legitimate callers of renameat2()
with RENAME_WHITEOUT who are calling this from within a Landlock domain.
(fuse-overlayfs is legitimate, but is not landlocked)
It doesn't seem worth complicating our common rename code for a corner
case that doesn't happen in practice.
[1] https://lore.kernel.org/all/adUBCQXrt7kmgqJT@google.com/
[2] https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories
[3] https://man7.org/linux/man-pages/man2/renameat2.2.html#DESCRIPTION
[4] https://codesearch.debian.net/search?q=rename.*RENAME_WHITEOUT&literal=0
[5] https://lore.kernel.org/all/20260411090944.3131168-2-gnoack@google.com/
Changelog
=========
v2:
- Introduce LANDLOCK_ACCESS_FS_MAKE_WHITEOUT access right
and guard it with that.
- Bump ABI version
v1:
- initial version
https://lore.kernel.org/all/20260411090944.3131168-2-gnoack@google.com/
Günther Noack (3):
landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT
selftests/landlock: Add test for RENAME_WHITEOUT denial
selftests/landlock: Test OverlayFS renames w/o
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
include/uapi/linux/landlock.h | 3 ++
security/landlock/audit.c | 1 +
security/landlock/fs.c | 15 ++++++
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
tools/testing/selftests/landlock/base_test.c | 4 +-
tools/testing/selftests/landlock/fs_test.c | 50 +++++++++++++++++++-
7 files changed, 71 insertions(+), 6 deletions(-)
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/3] landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT
2026-05-13 16:05 [PATCH v2 0/3] landlock: Restrict renameat2 with RENAME_WHITEOUT Günther Noack
@ 2026-05-13 16:05 ` Günther Noack
2026-05-13 16:05 ` [PATCH v2 2/3] selftests/landlock: Add test for RENAME_WHITEOUT denial Günther Noack
2026-05-13 16:05 ` [PATCH v2 3/3] selftests/landlock: Test OverlayFS renames w/o LANDLOCK_ACCESS_FS_MAKE_WHITEOUT Günther Noack
2 siblings, 0 replies; 4+ messages in thread
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
renameat2(2) with the RENAME_WHITEOUT flag places a whiteout character
device file in the source file location in place of the moved file.
This creates a directory entry even in cases where all
LANDLOCK_ACCESS_FS_MAKE_* rights are denied.
Introduce the LANDLOCK_ACCESS_FS_MAKE_WHITEOUT right, which is checked
for the origin directory if RENAME_WHITEOUT is passed.
This does not affect normal renames within layered OverlayFS mounts:
When OverlayFS invokes rename with RENAME_WHITEOUT as part of a
"normal" rename operation, it does so in ovl_rename() using the
credentials that were set at the time of mounting the OverlayFS.
Bump the Landlock ABI version to 10.
Suggested-by: Christian Brauner <brauner@kernel.org>
Suggested-by: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Günther Noack <gnoack@google.com>
---
include/uapi/linux/landlock.h | 3 +++
security/landlock/audit.c | 1 +
security/landlock/fs.c | 15 +++++++++++++++
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
tools/testing/selftests/landlock/base_test.c | 4 ++--
tools/testing/selftests/landlock/fs_test.c | 5 +++--
7 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 10a346e55e95..1f8a1d6d25f1 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -328,6 +328,8 @@ struct landlock_net_port_attr {
*
* If multiple requirements are not met, the ``EACCES`` error code takes
* precedence over ``EXDEV``.
+ * - %LANDLOCK_ACCESS_FS_MAKE_WHITEOUT: Create a whiteout object through
+ * :manpage:`rename(2)` with ``RENAME_WHITEOUT``.
*
* .. warning::
*
@@ -356,6 +358,7 @@ struct landlock_net_port_attr {
#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
#define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15)
#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX (1ULL << 16)
+#define LANDLOCK_ACCESS_FS_MAKE_WHITEOUT (1ULL << 17)
/* clang-format on */
/**
diff --git a/security/landlock/audit.c b/security/landlock/audit.c
index 8d0edf94037d..09c97083f599 100644
--- a/security/landlock/audit.c
+++ b/security/landlock/audit.c
@@ -38,6 +38,7 @@ static const char *const fs_access_strings[] = {
[BIT_INDEX(LANDLOCK_ACCESS_FS_TRUNCATE)] = "fs.truncate",
[BIT_INDEX(LANDLOCK_ACCESS_FS_IOCTL_DEV)] = "fs.ioctl_dev",
[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX)] = "fs.resolve_unix",
+ [BIT_INDEX(LANDLOCK_ACCESS_FS_MAKE_WHITEOUT)] = "fs.make_whiteout",
};
static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index c1ecfe239032..09de6ba5c3a3 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1519,6 +1519,21 @@ static int hook_path_rename(const struct path *const old_dir,
const unsigned int flags)
{
/* old_dir refers to old_dentry->d_parent and new_dir->mnt */
+ if (flags & RENAME_WHITEOUT) {
+ int err;
+
+ /*
+ * Rename with RENAME_WHITEOUT creates a whiteout object in the
+ * old location, so we check the access right for creating that.
+ *
+ * See Documentation/filesystems/overlayfs.rst and renameat2(2).
+ */
+ err = current_check_access_path(
+ old_dir, LANDLOCK_ACCESS_FS_MAKE_WHITEOUT);
+ if (err)
+ return err;
+ }
+
return current_check_refer_path(old_dentry, new_dir, new_dentry, true,
!!(flags & RENAME_EXCHANGE));
}
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index b454ad73b15e..e59378e8e897 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -19,7 +19,7 @@
#define LANDLOCK_MAX_NUM_LAYERS 16
#define LANDLOCK_MAX_NUM_RULES U32_MAX
-#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_RESOLVE_UNIX
+#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index accfd2e5a0cd..d45469d5d464 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -166,7 +166,7 @@ static const struct file_operations ruleset_fops = {
* If the change involves a fix that requires userspace awareness, also update
* the errata documentation in Documentation/userspace-api/landlock.rst .
*/
-const int landlock_abi_version = 9;
+const int landlock_abi_version = 10;
/**
* sys_landlock_create_ruleset - Create a new ruleset
diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
index 30d37234086c..6c8113c2ded1 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -76,8 +76,8 @@ TEST(abi_version)
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
};
- ASSERT_EQ(9, landlock_create_ruleset(NULL, 0,
- LANDLOCK_CREATE_RULESET_VERSION));
+ ASSERT_EQ(10, landlock_create_ruleset(NULL, 0,
+ LANDLOCK_CREATE_RULESET_VERSION));
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
LANDLOCK_CREATE_RULESET_VERSION));
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index cdb47fc1fc0a..53d1b659849f 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -579,7 +579,7 @@ TEST_F_FORK(layout1, inval)
LANDLOCK_ACCESS_FS_IOCTL_DEV | \
LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
-#define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX
+#define ACCESS_LAST LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
#define ACCESS_ALL ( \
ACCESS_FILE | \
@@ -593,7 +593,8 @@ TEST_F_FORK(layout1, inval)
LANDLOCK_ACCESS_FS_MAKE_FIFO | \
LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
LANDLOCK_ACCESS_FS_MAKE_SYM | \
- LANDLOCK_ACCESS_FS_REFER)
+ LANDLOCK_ACCESS_FS_REFER | \
+ LANDLOCK_ACCESS_FS_MAKE_WHITEOUT)
/* clang-format on */
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] selftests/landlock: Add test for RENAME_WHITEOUT denial
2026-05-13 16:05 [PATCH v2 0/3] landlock: Restrict renameat2 with RENAME_WHITEOUT Günther Noack
2026-05-13 16:05 ` [PATCH v2 1/3] landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT Günther Noack
@ 2026-05-13 16:05 ` Günther Noack
2026-05-13 16:05 ` [PATCH v2 3/3] selftests/landlock: Test OverlayFS renames w/o LANDLOCK_ACCESS_FS_MAKE_WHITEOUT Günther Noack
2 siblings, 0 replies; 4+ messages in thread
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
Add a test to check that renames with RENAME_WHITEOUT are guarded by
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT.
Signed-off-by: Günther Noack <gnoack@google.com>
---
tools/testing/selftests/landlock/fs_test.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 53d1b659849f..bdad92195f62 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -2248,6 +2248,19 @@ TEST_F_FORK(layout1, rename_file)
RENAME_EXCHANGE));
}
+TEST_F_FORK(layout1, rename_whiteout_denied)
+{
+ enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_WHITEOUT, NULL);
+
+ /*
+ * Try to rename a file with RENAME_WHITEOUT.
+ * file1_s3d3 is in dir_s3d2 (tmpfs), so it supports RENAME_WHITEOUT.
+ */
+ EXPECT_EQ(-1, renameat2(AT_FDCWD, file1_s3d3, AT_FDCWD,
+ TMP_DIR "/s3d1/s3d2/s3d3/f2", RENAME_WHITEOUT));
+ EXPECT_EQ(EACCES, errno);
+}
+
TEST_F_FORK(layout1, rename_dir)
{
const struct rule rules[] = {
@@ -6950,6 +6963,7 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
}
}
+
FIXTURE(layout3_fs)
{
bool has_created_dir;
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] selftests/landlock: Test OverlayFS renames w/o LANDLOCK_ACCESS_FS_MAKE_WHITEOUT
2026-05-13 16:05 [PATCH v2 0/3] landlock: Restrict renameat2 with RENAME_WHITEOUT Günther Noack
2026-05-13 16:05 ` [PATCH v2 1/3] landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT Günther Noack
2026-05-13 16:05 ` [PATCH v2 2/3] selftests/landlock: Add test for RENAME_WHITEOUT denial Günther Noack
@ 2026-05-13 16:05 ` Günther Noack
2 siblings, 0 replies; 4+ messages in thread
From: Günther Noack @ 2026-05-13 16:05 UTC (permalink / raw)
To: Mickaël Salaün, Christian Brauner
Cc: linux-security-module, Paul Moore, Amir Goldstein, Miklos Szeredi,
Serge Hallyn, Stephen Smalley, Günther Noack
Even though OverlayFS uses vfs_rename() with RENAME_WHITEOUT, and even
though RENAME_WHITEOUT requires LANDLOCK_ACCESS_FS_MAKE_WHITEOUT, a process
that renames files in an OverlayFS can do so without having the
LANDLOCK_ACCESS_FS_MAKE_WHITEOUT right in that location.
This works, and is supposed to work, because OverlayFS uses the credentials
determined at mount time for the internal vfs_rename() operation. -- The
rename happens with the credentials of the user who mounted the OverlayFS.
Signed-off-by: Günther Noack <gnoack@google.com>
---
tools/testing/selftests/landlock/fs_test.c | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index bdad92195f62..0c29887278d0 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -6963,6 +6963,37 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
}
}
+TEST_F_FORK(layout2_overlay, rename_in_overlay_without_make_whiteout)
+{
+ struct stat st;
+ const char *merge_fl1_renamed = MERGE_DATA "/fl1_renamed";
+
+ if (self->skip_test)
+ SKIP(return, "overlayfs is not supported (test)");
+
+ enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_WHITEOUT, NULL);
+
+ /*
+ * Execute a regular file rename within OverlayFS.
+ * merge_fl1 originates from lower layer, so this triggers a copy-up
+ * and creation of a whiteout in the upper layer.
+ */
+ EXPECT_EQ(0, rename(merge_fl1, merge_fl1_renamed));
+
+ /* Check that the rename worked. */
+ EXPECT_EQ(0, stat(merge_fl1_renamed, &st));
+ EXPECT_EQ(-1, stat(merge_fl1, &st));
+ EXPECT_EQ(ENOENT, errno);
+
+ /*
+ * Check that the whiteout object on the underlying "upper" filesystem
+ * exists after the rename. This is OK because it was done with the
+ * credentials of the OverlayFS.
+ */
+ EXPECT_EQ(0, stat(UPPER_DATA "/fl1", &st));
+ EXPECT_TRUE(S_ISCHR(st.st_mode));
+ EXPECT_EQ(0, st.st_rdev);
+}
FIXTURE(layout3_fs)
{
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-05-13 16:06 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-13 16:05 [PATCH v2 0/3] landlock: Restrict renameat2 with RENAME_WHITEOUT Günther Noack
2026-05-13 16:05 ` [PATCH v2 1/3] landlock: Require LANDLOCK_ACCESS_FS_MAKE_WHITEOUT for RENAME_WHITEOUT Günther Noack
2026-05-13 16:05 ` [PATCH v2 2/3] selftests/landlock: Add test for RENAME_WHITEOUT denial Günther Noack
2026-05-13 16:05 ` [PATCH v2 3/3] selftests/landlock: Test OverlayFS renames w/o LANDLOCK_ACCESS_FS_MAKE_WHITEOUT Günther Noack
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox