* [PATCH v5 1/5] selftests/landlock: Use an actual chardev for MAKE_CHAR audit test
2026-07-31 15:43 [PATCH v5 0/5] landlock: Restrict whiteout object creation Günther Noack
@ 2026-07-31 15:43 ` Günther Noack
2026-07-31 15:43 ` [PATCH v5 2/5] landlock: Require LANDLOCK_ACCESS_FS_MAKE_REG for whiteout creation Günther Noack
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Günther Noack @ 2026-07-31 15:43 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
By passing a (0, 0) device number, the audit test for
LANDLOCK_ACCESS_FS_MAKE_CHAR was accidentally creating a whiteout object
rather than a char device. In preparation to treating whiteout objects
differently, use an actual character device instead.
Signed-off-by: Günther Noack <gnoack@google.com>
---
tools/testing/selftests/landlock/fs_test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 86e08aa6e0a7..e82b56a74c5f 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -7436,7 +7436,7 @@ TEST_F(audit_layout1, make_char)
enforce_fs(_metadata, ACCESS_ALL, NULL);
- EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, 0));
+ EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, makedev(7, 0)));
EXPECT_EQ(EACCES, errno);
EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_char",
dir_s1d3));
--
2.55.0.508.g3f0d502094-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 2/5] landlock: Require LANDLOCK_ACCESS_FS_MAKE_REG for whiteout creation
2026-07-31 15:43 [PATCH v5 0/5] landlock: Restrict whiteout object creation Günther Noack
2026-07-31 15:43 ` [PATCH v5 1/5] selftests/landlock: Use an actual chardev for MAKE_CHAR audit test Günther Noack
@ 2026-07-31 15:43 ` Günther Noack
2026-07-31 15:43 ` [PATCH v5 3/5] selftests/landlock: Add tests for whiteout object creation Günther Noack
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Günther Noack @ 2026-07-31 15:43 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, stable
Whiteout objects are used in the upper layer of an OverlayFS to
indicate that the file with this name does not exist in the unified
view, even if it is present in one of the lower layer file systems.
For the userspace implementations of OverlayFS (fuse-overlayfs),
whiteout objects can be created from userspace as well:
* mknod(2) with S_IFCHR and makedev(0, 0)
* renameat2(2) with RENAME_WHITEOUT,
creating the whiteout in the old place of the moved file.
This commit guards whiteout creation in both of these cases with
LANDLOCK_ACCESS_FS_MAKE_REG. Whiteout objects are *not* considered
character devices and are not bound to a driver.
For the mknod(2) case, introduce a Landlock erratum. The creation of
whiteout objects through mknod(2) was previously guarded using
LANDLOCK_ACCESS_FS_MAKE_CHAR, and it is now guarded using
LANDLOCK_ACCESS_MAKE_REG.
For the renameat2(2) case, fix a bug: Before this commit, renameat2(2)
with RENAME_WHITEOUT would create a directory entry even when all
LANDLOCK_ACCESS_FS_MAKE_* rights were denied.
This does not affect normal renames within layered OverlayFS mounts:
When doing a regular rename() on a mounted fuse-overlayfs, it is the
fuse-overlayfs daemon that exercises renameat2() with RENAME_WHITEOUT,
and only the Landlock domain of that daemon is checked there.
Suggested-by: Christian Brauner <brauner@kernel.org>
Suggested-by: Mickaël Salaün <mic@digikod.net>
Cc: stable@vger.kernel.org
Fixes: cb2c7d1a1776 ("landlock: Support filesystem access-control")
Depends-on: 49c9e09d9610 ("landlock: Fix handling of disconnected directories")
Depends-on: fe72ce6710cb ("landlock: Add errata documentation section")
Signed-off-by: Günther Noack <gnoack@google.com>
---
include/uapi/linux/landlock.h | 1 +
security/landlock/errata/abi-1.h | 23 ++++++++++++++++++
security/landlock/fs.c | 41 +++++++++++++++++++++++++-------
3 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 7ffe2ef127ee..9c1102ebf06e 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -351,6 +351,7 @@ struct landlock_net_port_attr {
* device.
* - %LANDLOCK_ACCESS_FS_MAKE_DIR: Create (or rename) a directory.
* - %LANDLOCK_ACCESS_FS_MAKE_REG: Create (or rename or link) a regular file.
+ * This also guards the creation of whiteout objects as used in OverlayFS.
* - %LANDLOCK_ACCESS_FS_MAKE_SOCK: Create (or rename or link) a UNIX domain
* socket.
* - %LANDLOCK_ACCESS_FS_MAKE_FIFO: Create (or rename or link) a named pipe.
diff --git a/security/landlock/errata/abi-1.h b/security/landlock/errata/abi-1.h
index 3f099555f059..e0d543d9d508 100644
--- a/security/landlock/errata/abi-1.h
+++ b/security/landlock/errata/abi-1.h
@@ -22,3 +22,26 @@
* from their original mount points.
*/
LANDLOCK_ERRATUM(3)
+
+/**
+ * DOC: erratum_4
+ *
+ * Erratum 4: Creation of whiteout objects
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This fix changes the access rights required for the creation of whiteout
+ * objects through :manpage:`mknod(2)` or :manpage:`renameat2(2)`. Creating
+ * whiteout objects is now guarded by ``LANDLOCK_ACCESS_FS_MAKE_REG`` instead of
+ * ``LANDLOCK_ACCESS_FS_MAKE_CHAR``.
+ *
+ * Whiteout objects are used in OverlayFS to mark the absence of a file in an
+ * upper file system. Despite being created with ``S_IFCHR``, whiteout objects
+ * do not count as character devices.
+ *
+ * Impact:
+ *
+ * Sandboxed programs that create OverlayFS whiteouts (such as fuse-overlayfs)
+ * now require ``LANDLOCK_ACCESS_FS_MAKE_REG`` instead of
+ * ``LANDLOCK_ACCESS_FS_MAKE_CHAR``.
+ */
+LANDLOCK_ERRATUM(4)
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index f7e5e4ef9eac..c12af17cac9e 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -20,6 +20,7 @@
#include <linux/falloc.h>
#include <linux/fs.h>
#include <linux/init.h>
+#include <linux/kdev_t.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/list.h>
@@ -983,7 +984,8 @@ static int current_check_access_path(const struct path *const path,
return -EACCES;
}
-static __attribute_const__ access_mask_t get_mode_access(const umode_t mode)
+static __attribute_const__ access_mask_t get_mode_access(const umode_t mode,
+ const dev_t dev)
{
switch (mode & S_IFMT) {
case S_IFLNK:
@@ -991,6 +993,9 @@ static __attribute_const__ access_mask_t get_mode_access(const umode_t mode)
case S_IFDIR:
return LANDLOCK_ACCESS_FS_MAKE_DIR;
case S_IFCHR:
+ /* Whiteout objects are guarded with MAKE_REG. */
+ if (dev == WHITEOUT_DEV)
+ return LANDLOCK_ACCESS_FS_MAKE_REG;
return LANDLOCK_ACCESS_FS_MAKE_CHAR;
case S_IFBLK:
return LANDLOCK_ACCESS_FS_MAKE_BLOCK;
@@ -1007,6 +1012,13 @@ static __attribute_const__ access_mask_t get_mode_access(const umode_t mode)
}
}
+static __attribute_const__ access_mask_t
+get_dentry_access(const struct dentry *const dentry)
+{
+ return get_mode_access(d_backing_inode(dentry)->i_mode,
+ d_backing_inode(dentry)->i_rdev);
+}
+
static access_mask_t maybe_remove(const struct dentry *const dentry)
{
if (d_is_negative(dentry))
@@ -1093,6 +1105,7 @@ static bool collect_domain_accesses(const struct landlock_ruleset *const domain,
* @new_dentry: Destination file or directory.
* @removable: Sets to true if it is a rename operation.
* @exchange: Sets to true if it is a rename operation with RENAME_EXCHANGE.
+ * @whiteout: Sets to true if it is a rename operation with RENAME_WHITEOUT.
*
* Because of its unprivileged constraints, Landlock relies on file hierarchies
* (and not only inodes) to tie access rights to files. Being able to link or
@@ -1140,7 +1153,8 @@ static bool collect_domain_accesses(const struct landlock_ruleset *const domain,
static int current_check_refer_path(struct dentry *const old_dentry,
const struct path *const new_dir,
struct dentry *const new_dentry,
- const bool removable, const bool exchange)
+ const bool removable, const bool exchange,
+ const bool whiteout)
{
const struct landlock_cred_security *const subject =
landlock_get_applicable_subject(current_cred(), any_fs, NULL);
@@ -1159,18 +1173,25 @@ static int current_check_refer_path(struct dentry *const old_dentry,
if (exchange) {
if (unlikely(d_is_negative(new_dentry)))
return -ENOENT;
- access_request_parent1 =
- get_mode_access(d_backing_inode(new_dentry)->i_mode);
+ access_request_parent1 = get_dentry_access(new_dentry);
} else {
access_request_parent1 = 0;
}
- access_request_parent2 =
- get_mode_access(d_backing_inode(old_dentry)->i_mode);
+ access_request_parent2 = get_dentry_access(old_dentry);
if (removable) {
access_request_parent1 |= maybe_remove(old_dentry);
access_request_parent2 |= maybe_remove(new_dentry);
}
+ /*
+ * In case of renameat2(2) with RENAME_WHITEOUT, a whiteout object is
+ * created in the source location, so we require an additional access
+ * right there.
+ */
+ if (whiteout)
+ access_request_parent1 |=
+ get_mode_access(S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
+
/* The mount points are the same for old and new paths, cf. EXDEV. */
if (old_dentry->d_parent == new_dir->dentry) {
/*
@@ -1520,7 +1541,7 @@ static int hook_path_link(struct dentry *const old_dentry,
struct dentry *const new_dentry)
{
return current_check_refer_path(old_dentry, new_dir, new_dentry, false,
- false);
+ false, false);
}
static int hook_path_rename(const struct path *const old_dir,
@@ -1531,7 +1552,8 @@ static int hook_path_rename(const struct path *const old_dir,
{
/* old_dir refers to old_dentry->d_parent and new_dir->mnt */
return current_check_refer_path(old_dentry, new_dir, new_dentry, true,
- !!(flags & RENAME_EXCHANGE));
+ !!(flags & RENAME_EXCHANGE),
+ !!(flags & RENAME_WHITEOUT));
}
static int hook_path_mkdir(const struct path *const dir,
@@ -1544,7 +1566,8 @@ static int hook_path_mknod(const struct path *const dir,
struct dentry *const dentry, const umode_t mode,
const unsigned int dev)
{
- return current_check_access_path(dir, get_mode_access(mode));
+ return current_check_access_path(
+ dir, get_mode_access(mode, new_decode_dev(dev)));
}
static int hook_path_symlink(const struct path *const dir,
--
2.55.0.508.g3f0d502094-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 3/5] selftests/landlock: Add tests for whiteout object creation
2026-07-31 15:43 [PATCH v5 0/5] landlock: Restrict whiteout object creation Günther Noack
2026-07-31 15:43 ` [PATCH v5 1/5] selftests/landlock: Use an actual chardev for MAKE_CHAR audit test Günther Noack
2026-07-31 15:43 ` [PATCH v5 2/5] landlock: Require LANDLOCK_ACCESS_FS_MAKE_REG for whiteout creation Günther Noack
@ 2026-07-31 15:43 ` Günther Noack
2026-07-31 15:43 ` [PATCH v5 4/5] selftests/landlock: Test whiteout object behaviour in OverlayFS renames Günther Noack
2026-07-31 15:43 ` [PATCH v5 5/5] landlock: Link the erratum documentation for whiteout objects Günther Noack
4 siblings, 0 replies; 6+ messages in thread
From: Günther Noack @ 2026-07-31 15:43 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 whiteout object creation is guarded by
LANDLOCK_ACCESS_FS_MAKE_REG, in the cases where these are created from
userspace:
* Conventional creation with mknod()
* Linking or renaming an existing whiteout object
* renameat2() with RENAME_WHITEOUT,
which creates a new whiteout object in the source location
Signed-off-by: Günther Noack <gnoack@google.com>
---
tools/testing/selftests/landlock/fs_test.c | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index e82b56a74c5f..2701f00c79ae 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -2247,6 +2247,25 @@ TEST_F_FORK(layout1, rename_file)
RENAME_EXCHANGE));
}
+TEST_F_FORK(layout1, rename_whiteout_denied)
+{
+ /* The affected file is a FIFO. */
+ ASSERT_EQ(0, unlink(file1_s3d3));
+ ASSERT_EQ(0, mknod(file1_s3d3, S_IFIFO | 0600, 0));
+
+ /* Deny MAKE_REG, but allow MAKE_FIFO. */
+ enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, NULL);
+
+ /*
+ * Try to rename a file with RENAME_WHITEOUT.
+ * file1_s3d3 is in dir_s3d2 (tmpfs), so it supports RENAME_WHITEOUT.
+ * Denied, because whiteout creation is guarded with MAKE_REG.
+ */
+ 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[] = {
@@ -3270,6 +3289,13 @@ TEST_F_FORK(layout1, make_char)
makedev(1, 3));
}
+TEST_F_FORK(layout1, make_whiteout)
+{
+ /* Creates a whiteout object (creation guarded by MAKE_REG). */
+ test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFCHR,
+ makedev(0, 0));
+}
+
TEST_F_FORK(layout1, make_block)
{
/* Creates a /dev/loop0 device. */
--
2.55.0.508.g3f0d502094-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 4/5] selftests/landlock: Test whiteout object behaviour in OverlayFS renames
2026-07-31 15:43 [PATCH v5 0/5] landlock: Restrict whiteout object creation Günther Noack
` (2 preceding siblings ...)
2026-07-31 15:43 ` [PATCH v5 3/5] selftests/landlock: Add tests for whiteout object creation Günther Noack
@ 2026-07-31 15:43 ` Günther Noack
2026-07-31 15:43 ` [PATCH v5 5/5] landlock: Link the erratum documentation for whiteout objects Günther Noack
4 siblings, 0 replies; 6+ messages in thread
From: Günther Noack @ 2026-07-31 15:43 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_REG, a process
that renames non-regular files in an OverlayFS can do so without
having the LANDLOCK_ACCESS_FS_MAKE_REG 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 | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 2701f00c79ae..306f0164b5e2 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -6977,6 +6977,46 @@ TEST_F_FORK(layout2_overlay, same_content_different_file)
}
}
+TEST_F_FORK(layout2_overlay, rename_in_overlay_without_make_reg)
+{
+ struct stat st;
+ const char *merge_fl1_renamed = MERGE_DATA "/fl1_renamed";
+
+ if (self->skip_test)
+ SKIP(return, "overlayfs is not supported (test)");
+
+ /*
+ * In this test, merge_fl1 is a FIFO file. MAKE_REG is restricted, but
+ * MAKE_FIFO is allowed. Despite MAKE_REG being restricted, the rename
+ * on the OverlayFS works and creates a whiteout file in the underlying
+ * upper file system.
+ */
+ ASSERT_EQ(0, unlink(merge_fl1));
+ ASSERT_EQ(0, mknod(merge_fl1, S_IFIFO, 0));
+ enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, 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)
{
bool has_created_dir;
--
2.55.0.508.g3f0d502094-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v5 5/5] landlock: Link the erratum documentation for whiteout objects
2026-07-31 15:43 [PATCH v5 0/5] landlock: Restrict whiteout object creation Günther Noack
` (3 preceding siblings ...)
2026-07-31 15:43 ` [PATCH v5 4/5] selftests/landlock: Test whiteout object behaviour in OverlayFS renames Günther Noack
@ 2026-07-31 15:43 ` Günther Noack
4 siblings, 0 replies; 6+ messages in thread
From: Günther Noack @ 2026-07-31 15:43 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
The documentation embeds the canonical erratum documentation from the
header file, which is already a self-contained description of the issue.
Signed-off-by: Günther Noack <gnoack@google.com>
---
Documentation/userspace-api/landlock.rst | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index 5a63d4476c1c..df996ccaee34 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -556,6 +556,9 @@ in the running kernel.
.. kernel-doc:: security/landlock/errata/abi-1.h
:doc: erratum_3
+.. kernel-doc:: security/landlock/errata/abi-1.h
+ :doc: erratum_4
+
How to check for errata
~~~~~~~~~~~~~~~~~~~~~~~
--
2.55.0.508.g3f0d502094-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread