[PATCH RFC -next 08/12] landlock: Add READ_METADATA and WRITE_METADATA access rights
From: Cai Xinchen
Date: Thu Sep 24 2026 - 06:42:29 EST
Add two new filesystem access rights to control file metadata access:
- LANDLOCK_ACCESS_FS_READ_METADATA: Read file or directory metadata
(e.g. inode attributes, extended attributes and POSIX ACLs) through
stat(2), fstat(2), lstat(2), newfstatat(2), getxattr(2) and
friends, listxattr(2) and friends, and the POSIX ACL read
operations.
- LANDLOCK_ACCESS_FS_WRITE_METADATA: Change file or directory
metadata through chmod(2) and friends, chown(2) and friends,
utimensat(2) and friends, setxattr(2) and friends, removexattr(2)
and friends, and the POSIX ACL set and remove operations.
This follows the coarse-grained grouping approach discussed in the
mailing list [1], where file metadata operations are grouped by
security relevance rather than by individual syscall.
Remove stat(2), chmod(2), chown(2), setxattr(2) and utime(2) from the
list of file-related actions that cannot be restricted yet, and add
the names of the new rights to _LANDLOCK_ACCESS_FS_NAMES in
include/linux/landlock.h, which is shared by audit records and trace
events, so that denied accesses can be reported with a human-readable
name and the static assertion on fs_access_strings in
security/landlock/audit.c stays valid.
Increment the Landlock ABI version from 11 to 12, and update the ABI
version check in tools/testing/selftests/landlock/base_test.c
accordingly.
[1]
https://lore.kernel.org/all/abc960a1-e66e-792e-6869-cfd201c29dbe@xxxxxxxxxxx/
Assisted-by: opencode: glm-5.3
Signed-off-by: Cai Xinchen <caixinchen1@xxxxxxxxxx>
---
include/linux/landlock.h | 4 ++-
include/uapi/linux/landlock.h | 26 +++++++++++++++++---
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
tools/testing/selftests/landlock/base_test.c | 2 +-
5 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/include/linux/landlock.h b/include/linux/landlock.h
index 004cbd0b9298..86fc2181ab24 100644
--- a/include/linux/landlock.h
+++ b/include/linux/landlock.h
@@ -39,7 +39,9 @@
_LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_FS_REFER, "refer"), \
_LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_FS_TRUNCATE, "truncate"), \
_LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_FS_IOCTL_DEV, "ioctl_dev"), \
- _LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_FS_RESOLVE_UNIX, "resolve_unix")
+ _LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_FS_RESOLVE_UNIX, "resolve_unix"), \
+ _LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_FS_READ_METADATA, "read_metadata"), \
+ _LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_FS_WRITE_METADATA, "write_metadata")
#define _LANDLOCK_ACCESS_NET_NAMES \
_LANDLOCK_NAME_ENTRY(LANDLOCK_ACCESS_NET_BIND_TCP, "bind_tcp"), \
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index cceda3b3b961..40d64e8b5e2d 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -343,6 +343,24 @@ struct landlock_net_port_attr {
*
* The rationale for this design is described in
* :ref:`Documentation/security/landlock.rst <scoped-flags-interaction>`.
+ * - %LANDLOCK_ACCESS_FS_READ_METADATA: Read file or directory metadata (e.g.
+ * inode attributes, extended attributes, and POSIX ACLs) through
+ * :manpage:`stat(2)`, :manpage:`fstat(2)`, :manpage:`lstat(2)`,
+ * :manpage:`newfstatat(2)`, :manpage:`getxattr(2)`, and
+ * :manpage:`listxattr(2)`.
+ *
+ * This access right is available since the twelfth version of the Landlock
+ * ABI.
+ * - %LANDLOCK_ACCESS_FS_WRITE_METADATA: Change file or directory metadata
+ * (e.g. inode attributes, extended attributes, and POSIX ACLs) through
+ * :manpage:`chmod(2)`, :manpage:`chown(2)`, :manpage:`utimensat(2)`,
+ * :manpage:`setxattr(2)`, and :manpage:`removexattr(2)`, as well as related
+ * system calls. Implicit metadata changes performed by the kernel (e.g.
+ * timestamp updates with :manpage:`write(2)`) are not restricted by this
+ * access right.
+ *
+ * This access right is available since the twelfth version of the Landlock
+ * ABI.
*
* Whether an opened file can be truncated with :manpage:`ftruncate(2)` or used
* with `ioctl(2)` is determined during :manpage:`open(2)`, in the same way as
@@ -406,10 +424,8 @@ struct landlock_net_port_attr {
* .. warning::
*
* It is currently not possible to restrict some file-related actions
- * accessible through these syscall families: :manpage:`chdir(2)`,
- * :manpage:`stat(2)`, :manpage:`flock(2)`, :manpage:`chmod(2)`,
- * :manpage:`chown(2)`, :manpage:`setxattr(2)`, :manpage:`utime(2)`,
- * :manpage:`fcntl(2)`, :manpage:`access(2)`.
+ * accessible through these syscall families: :manpage:`chdir(2)',
+ * :manpage:`flock(2)', :manpage:`fcntl(2)', :manpage:`access(2)'.
* Future Landlock evolutions will enable to restrict them.
*/
/* clang-format off */
@@ -430,6 +446,8 @@ 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_READ_METADATA (1ULL << 17)
+#define LANDLOCK_ACCESS_FS_WRITE_METADATA (1ULL << 18)
/* clang-format on */
/**
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 1a7c5fb8f6fd..665ff238bd27 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_WRITE_METADATA
#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 400a2f928de3..205d64c534d7 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -172,7 +172,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 = 11;
+const int landlock_abi_version = 12;
/**
* 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 d20ab8f0862c..58fe322d8637 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -76,7 +76,7 @@ TEST(abi_version)
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
};
- ASSERT_EQ(11, landlock_create_ruleset(NULL, 0,
+ ASSERT_EQ(12, landlock_create_ruleset(NULL, 0,
LANDLOCK_CREATE_RULESET_VERSION));
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
--
2.18.0.huawei.25