* [PATCH v4 6/6] landlock: Document design rationale for scoped access rights
From: Günther Noack @ 2026-02-08 23:10 UTC (permalink / raw)
To: Mickaël Salaün, John Johansen
Cc: Günther Noack, linux-security-module, Tingmao Wang,
Justin Suess, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi
In-Reply-To: <20260208231017.114343-1-gnoack3000@gmail.com>
Document the (possible future) interaction between scoped flags and
other access rights in struct landlock_ruleset_attr, and summarize the
rationale, as discussed in code review leading up to [1].
Link[1]: https://lore.kernel.org/all/20260205.8531e4005118@gnoack.org/
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
---
Documentation/security/landlock.rst | 38 +++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/Documentation/security/landlock.rst b/Documentation/security/landlock.rst
index 3e4d4d04cfae..49ef02d5e272 100644
--- a/Documentation/security/landlock.rst
+++ b/Documentation/security/landlock.rst
@@ -89,6 +89,44 @@ this is required to keep access controls consistent over the whole system, and
this avoids unattended bypasses through file descriptor passing (i.e. confused
deputy attack).
+Interaction between scoped flags and other access rights
+--------------------------------------------------------
+
+The ``scoped`` flags in ``struct landlock_ruleset_attr`` restrict the
+use of *outgoing* IPC from the created Landlock domain, while they
+permit reaching out to IPC endpoints *within* the created Landlock
+domain.
+
+In the future, scoped flags *may* interact with other access rights,
+e.g. so that abstract UNIX sockets can be allow-listed by name, or so
+that signals can be allow-listed by signal number or target process.
+
+When introducing ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``, we defined it to
+implicitly have the same scoping semantics as a
+``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` flag would have: connecting to
+UNIX sockets within the same domain (where
+``LANDLOCK_ACCESS_FS_RESOLVE_UNIX`` is used) is unconditionally
+allowed.
+
+The reasoning is:
+
+* Like other IPC mechanisms, connecting to named UNIX sockets in the
+ same domain should be expected and harmless. (If needed, users can
+ further refine their Landlock policies with nested domains or by
+ restricting ``LANDLOCK_ACCESS_FS_MAKE_SOCK``.)
+* We reserve the option to still introduce
+ ``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the future. (This would
+ be useful if we wanted to have a Landlock rule to permit IPC access
+ to other Landlock domains.)
+* But we can postpone the point in time when users have to deal with
+ two interacting flags visible in the userspace API. (In particular,
+ it is possible that it won't be needed in practice, in which case we
+ can avoid the second flag altogether.)
+* If we *do* introduce ``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the
+ future, setting this scoped flag in a ruleset does *not reduce* the
+ restrictions, because access within the same scope is already
+ allowed based on ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``.
+
Tests
=====
--
2.52.0
^ permalink raw reply related
* [PATCH v4 5/6] landlock: Document FS access right for pathname UNIX sockets
From: Günther Noack @ 2026-02-08 23:10 UTC (permalink / raw)
To: Mickaël Salaün, John Johansen
Cc: Günther Noack, Justin Suess, linux-security-module,
Tingmao Wang, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi
In-Reply-To: <20260208231017.114343-1-gnoack3000@gmail.com>
Cc: Justin Suess <utilityemal77@gmail.com>
Cc: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
---
Documentation/userspace-api/landlock.rst | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index 13134bccdd39..3ba73afcbc4b 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -77,7 +77,8 @@ to be explicit about the denied-by-default access rights.
LANDLOCK_ACCESS_FS_MAKE_SYM |
LANDLOCK_ACCESS_FS_REFER |
LANDLOCK_ACCESS_FS_TRUNCATE |
- LANDLOCK_ACCESS_FS_IOCTL_DEV,
+ LANDLOCK_ACCESS_FS_IOCTL_DEV |
+ LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
.handled_access_net =
LANDLOCK_ACCESS_NET_BIND_TCP |
LANDLOCK_ACCESS_NET_CONNECT_TCP,
@@ -127,6 +128,12 @@ version, and only use the available subset of access rights:
/* Removes LANDLOCK_SCOPE_* for ABI < 6 */
ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
LANDLOCK_SCOPE_SIGNAL);
+ __attribute__((fallthrough));
+ case 7:
+ __attribute__((fallthrough));
+ case 8:
+ /* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 8 */
+ ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_RESOLVE_UNIX;
}
This enables the creation of an inclusive ruleset that will contain our rules.
@@ -685,6 +692,13 @@ enforce Landlock rulesets across all threads of the calling process
using the ``LANDLOCK_RESTRICT_SELF_TSYNC`` flag passed to
sys_landlock_restrict_self().
+Pathname UNIX sockets (ABI < 9)
+-------------------------------
+
+Starting with the Landlock ABI version 9, it is possible to restrict
+connections to pathname UNIX domain sockets (:manpage:`unix(7)`) using
+the new ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX`` right.
+
.. _kernel_support:
Kernel support
--
2.52.0
^ permalink raw reply related
* [PATCH v4 4/6] landlock/selftests: Test named UNIX domain socket restrictions
From: Günther Noack @ 2026-02-08 23:10 UTC (permalink / raw)
To: Mickaël Salaün, John Johansen
Cc: Günther Noack, Justin Suess, linux-security-module,
Tingmao Wang, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi
In-Reply-To: <20260208231017.114343-1-gnoack3000@gmail.com>
* Exercise the access right for connect() and sendmsg() on named UNIX
domain sockets, in various combinations of Landlock domains and
socket types.
* Extract common helpers from an existing IOCTL test that
also uses pathname unix(7) sockets.
The tested combinations are the cross product of these sets of fixture
fields:
* {{.handled=RESOLVE_UNIX},
{.handled=RESOLVE_UNIX, .allowed=RESOLVE_UNIX}}
* {{.sock_type=SOCK_STREAM},
{.sock_type=SOCK_DGRAM},
{.sock_type=SOCK_DGRAM, .use_sendto=true},
{.sock_type=SOCK_SEQPACKET}}
* {{.server_in_same_domain=false},
{.server_in_same_domain=true}}
Some additional fixtures exercise scenarios with two nested domains.
Cc: Justin Suess <utilityemal77@gmail.com>
Cc: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
---
tools/testing/selftests/landlock/fs_test.c | 381 ++++++++++++++++++++-
1 file changed, 365 insertions(+), 16 deletions(-)
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index b318627e7561..9d3f5dab4567 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -4358,30 +4358,61 @@ TEST_F_FORK(layout1, named_pipe_ioctl)
ASSERT_EQ(child_pid, waitpid(child_pid, NULL, 0));
}
+/*
+ * set_up_named_unix_server - Create a pathname unix socket
+ *
+ * If the socket type is not SOCK_DGRAM, also invoke listen(2).
+ *
+ * Return: The listening FD - it is the caller responsibility to close it.
+ */
+static int set_up_named_unix_server(struct __test_metadata *const _metadata,
+ int type, const char *const path)
+{
+ int fd;
+ struct sockaddr_un addr = {
+ .sun_family = AF_UNIX,
+ };
+
+ fd = socket(AF_UNIX, type, 0);
+ ASSERT_LE(0, fd);
+
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+ ASSERT_EQ(0, bind(fd, (struct sockaddr *)&addr, sizeof(addr)));
+
+ if (type != SOCK_DGRAM)
+ ASSERT_EQ(0, listen(fd, 10 /* qlen */));
+ return fd;
+}
+
+/*
+ * test_connect_named_unix - connect to the given named UNIX socket
+ *
+ * Return: The errno from connect(), or 0
+ */
+static int test_connect_named_unix(int fd, const char *const path)
+{
+ struct sockaddr_un addr = {
+ .sun_family = AF_UNIX,
+ };
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
+ return errno;
+ return 0;
+}
+
/* For named UNIX domain sockets, no IOCTL restrictions apply. */
TEST_F_FORK(layout1, named_unix_domain_socket_ioctl)
{
const char *const path = file1_s1d1;
int srv_fd, cli_fd, ruleset_fd;
- struct sockaddr_un srv_un = {
- .sun_family = AF_UNIX,
- };
- struct sockaddr_un cli_un = {
- .sun_family = AF_UNIX,
- };
const struct landlock_ruleset_attr attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV,
};
/* Sets up a server */
ASSERT_EQ(0, unlink(path));
- srv_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- ASSERT_LE(0, srv_fd);
-
- strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path));
- ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, sizeof(srv_un)));
-
- ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */));
+ srv_fd = set_up_named_unix_server(_metadata, SOCK_STREAM, path);
/* Enables Landlock. */
ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
@@ -4393,9 +4424,7 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl)
cli_fd = socket(AF_UNIX, SOCK_STREAM, 0);
ASSERT_LE(0, cli_fd);
- strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path));
- ASSERT_EQ(0,
- connect(cli_fd, (struct sockaddr *)&cli_un, sizeof(cli_un)));
+ ASSERT_EQ(0, test_connect_named_unix(cli_fd, path));
/* FIONREAD and other IOCTLs should not be forbidden. */
EXPECT_EQ(0, test_fionread_ioctl(cli_fd));
@@ -4570,6 +4599,326 @@ TEST_F_FORK(ioctl, handle_file_access_file)
ASSERT_EQ(0, close(file_fd));
}
+/* clang-format off */
+FIXTURE(unix_socket) {};
+
+FIXTURE_SETUP(unix_socket) {};
+
+FIXTURE_TEARDOWN(unix_socket) {};
+/* clang-format on */
+
+FIXTURE_VARIANT(unix_socket)
+{
+ const __u64 handled;
+ const __u64 allowed;
+ const __u64 handled2;
+ const __u64 allowed2;
+ const int sock_type;
+ const int expected;
+ const bool use_sendto;
+ const bool server_in_same_domain;
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_handled_not_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_STREAM,
+ .expected = EACCES,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_handled_and_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_STREAM,
+ .expected = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_not_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_DGRAM,
+ .expected = EACCES,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_and_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_DGRAM,
+ .expected = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_not_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_DGRAM,
+ .use_sendto = true,
+ .expected = EACCES,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_and_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_DGRAM,
+ .use_sendto = true,
+ .expected = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_not_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_SEQPACKET,
+ .expected = EACCES,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_and_allowed)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_SEQPACKET,
+ .expected = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_handled_not_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_STREAM,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_handled_and_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_STREAM,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_not_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_DGRAM,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_handled_and_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_DGRAM,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_not_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_DGRAM,
+ .use_sendto = true,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, dgram_sendto_handled_and_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_DGRAM,
+ .use_sendto = true,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_not_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .sock_type = SOCK_SEQPACKET,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, seqpacket_handled_and_allowed_and_same_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_SEQPACKET,
+ .expected = 0,
+ .server_in_same_domain = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_scope_path)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .server_in_same_domain = true,
+ .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_STREAM,
+ .expected = 0,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_path_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .server_in_same_domain = true,
+ .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed2 = 0,
+ .sock_type = SOCK_STREAM,
+ .expected = EACCES,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_scope_scope)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = 0,
+ .server_in_same_domain = true,
+ .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed2 = 0,
+ .sock_type = SOCK_STREAM,
+ .expected = EACCES,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_nested_domains_path_path)
+{
+ /* clang-format on */
+ .handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .server_in_same_domain = true,
+ .handled2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .allowed2 = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ .sock_type = SOCK_STREAM,
+ .expected = 0,
+};
+
+/*
+ * test_sendto_named_unix - sendto to the given named UNIX socket
+ *
+ * sendto() is equivalent to sendmsg() in this respect.
+ *
+ * Return: The errno from sendto(), or 0
+ */
+static int test_sendto_named_unix(int fd, const char *const path)
+{
+ static const char buf[] = "dummy";
+ struct sockaddr_un addr = {
+ .sun_family = AF_UNIX,
+ };
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+
+ if (sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&addr,
+ sizeof(addr)) == -1)
+ return errno;
+ return 0;
+}
+
+TEST_F_FORK(unix_socket, test)
+{
+ const char *const path = "sock";
+ int cli_fd, srv_fd, ruleset_fd, res;
+ struct rule rules[] = {
+ {
+ .path = ".",
+ .access = variant->allowed,
+ },
+ {},
+ };
+
+ /* Sets up a server (in the case where the server is in the parent domain) */
+ if (!variant->server_in_same_domain)
+ srv_fd = set_up_named_unix_server(_metadata, variant->sock_type,
+ path);
+
+ /* Enables Landlock. */
+ ruleset_fd = create_ruleset(_metadata, variant->handled, rules);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+
+ /* Sets up a server (in the case where the server is in the same domain) */
+ if (variant->server_in_same_domain)
+ srv_fd = set_up_named_unix_server(_metadata, variant->sock_type,
+ path);
+
+ if (variant->handled2) {
+ /* Enables Landlock another time, if needed. */
+ rules[0].access = variant->allowed2;
+ ruleset_fd =
+ create_ruleset(_metadata, variant->handled2, rules);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ ASSERT_EQ(0, close(ruleset_fd));
+ }
+
+ /* Sets up a client connection to it */
+ cli_fd = socket(AF_UNIX, variant->sock_type, 0);
+ ASSERT_LE(0, cli_fd);
+
+ /* Connecting or sendto to the Unix socket is denied. */
+ if (variant->use_sendto)
+ res = test_sendto_named_unix(cli_fd, path);
+ else
+ res = test_connect_named_unix(cli_fd, path);
+ EXPECT_EQ(variant->expected, res);
+
+ /* Clean up. */
+ EXPECT_EQ(0, close(cli_fd));
+ EXPECT_EQ(0, close(srv_fd));
+ EXPECT_EQ(0, unlink(path));
+}
+
/* clang-format off */
FIXTURE(layout1_bind) {};
/* clang-format on */
--
2.52.0
^ permalink raw reply related
* [PATCH v4 3/6] samples/landlock: Add support for named UNIX domain socket restrictions
From: Günther Noack @ 2026-02-08 23:10 UTC (permalink / raw)
To: Mickaël Salaün, John Johansen
Cc: Günther Noack, Justin Suess, linux-security-module,
Tingmao Wang, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi
In-Reply-To: <20260208231017.114343-1-gnoack3000@gmail.com>
The access right for UNIX domain socket lookups is grouped with the
read-write rights in the sample tool. Rationale: In the general case,
any operations are possible through a UNIX domain socket, including
data-mutating operations.
Cc: Justin Suess <utilityemal77@gmail.com>
Cc: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
---
samples/landlock/sandboxer.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index e7af02f98208..0bbbc5c9ead6 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -111,7 +111,8 @@ static int parse_path(char *env_path, const char ***const path_list)
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_RESOLVE_UNIX)
/* clang-format on */
@@ -295,11 +296,12 @@ static bool check_ruleset_scope(const char *const env_var,
LANDLOCK_ACCESS_FS_MAKE_SYM | \
LANDLOCK_ACCESS_FS_REFER | \
LANDLOCK_ACCESS_FS_TRUNCATE | \
- LANDLOCK_ACCESS_FS_IOCTL_DEV)
+ LANDLOCK_ACCESS_FS_IOCTL_DEV | \
+ LANDLOCK_ACCESS_FS_RESOLVE_UNIX)
/* clang-format on */
-#define LANDLOCK_ABI_LAST 7
+#define LANDLOCK_ABI_LAST 9
#define XSTR(s) #s
#define STR(s) XSTR(s)
@@ -444,6 +446,13 @@ int main(const int argc, char *const argv[], char *const *const envp)
"provided by ABI version %d (instead of %d).\n",
LANDLOCK_ABI_LAST, abi);
__attribute__((fallthrough));
+ case 7:
+ __attribute__((fallthrough));
+ case 8:
+ /* Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX for ABI < 9 */
+ ruleset_attr.handled_access_fs &=
+ ~LANDLOCK_ACCESS_FS_RESOLVE_UNIX;
+ __attribute__((fallthrough));
case LANDLOCK_ABI_LAST:
break;
default:
--
2.52.0
^ permalink raw reply related
* [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
From: Günther Noack @ 2026-02-08 23:10 UTC (permalink / raw)
To: Mickaël Salaün, John Johansen
Cc: Günther Noack, Tingmao Wang, Justin Suess, Jann Horn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Tahera Fahimi
In-Reply-To: <20260208231017.114343-1-gnoack3000@gmail.com>
* Add a new access right LANDLOCK_ACCESS_FS_RESOLVE_UNIX, which
controls the look up operations for named UNIX domain sockets. The
resolution happens during connect() and sendmsg() (depending on
socket type).
* Hook into the path lookup in unix_find_bsd() in af_unix.c, using a
LSM hook. Make policy decisions based on the new access rights
* Increment the Landlock ABI version.
* Minor test adaptions to keep the tests working.
With this access right, access is granted if either of the following
conditions is met:
* The target socket's filesystem path was allow-listed using a
LANDLOCK_RULE_PATH_BENEATH rule, *or*:
* The target socket was created in the same Landlock domain in which
LANDLOCK_ACCESS_FS_RESOLVE_UNIX was restricted.
In case of a denial, connect() and sendmsg() return EACCES, which is
the same error as it is returned if the user does not have the write
bit in the traditional Unix file system permissions of that file.
This feature was created with substantial discussion and input from
Justin Suess, Tingmao Wang and Mickaël Salaün.
Cc: Tingmao Wang <m@maowtm.org>
Cc: Justin Suess <utilityemal77@gmail.com>
Cc: Mickaël Salaün <mic@digikod.net>
Suggested-by: Jann Horn <jannh@google.com>
Link: https://github.com/landlock-lsm/linux/issues/36
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
---
include/uapi/linux/landlock.h | 10 ++
security/landlock/access.h | 11 +-
security/landlock/audit.c | 1 +
security/landlock/fs.c | 107 ++++++++++++++++++-
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
tools/testing/selftests/landlock/base_test.c | 2 +-
tools/testing/selftests/landlock/fs_test.c | 5 +-
8 files changed, 133 insertions(+), 7 deletions(-)
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index f88fa1f68b77..3a8fc3af0d64 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -248,6 +248,15 @@ struct landlock_net_port_attr {
*
* This access right is available since the fifth version of the Landlock
* ABI.
+ * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX: Look up pathname UNIX domain sockets
+ * (:manpage:`unix(7)`). On UNIX domain sockets, this restricts both calls to
+ * :manpage:`connect(2)` as well as calls to :manpage:`sendmsg(2)` with an
+ * explicit recipient address.
+ *
+ * This access right only applies to connections to UNIX server sockets which
+ * were created outside of the newly created Landlock domain (e.g. from within
+ * a parent domain or from an unrestricted process). Newly created UNIX
+ * servers within the same Landlock domain continue to be accessible.
*
* 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
@@ -333,6 +342,7 @@ struct landlock_net_port_attr {
#define LANDLOCK_ACCESS_FS_REFER (1ULL << 13)
#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
#define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15)
+#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX (1ULL << 16)
/* clang-format on */
/**
diff --git a/security/landlock/access.h b/security/landlock/access.h
index 42c95747d7bd..9a2991688835 100644
--- a/security/landlock/access.h
+++ b/security/landlock/access.h
@@ -34,7 +34,7 @@
LANDLOCK_ACCESS_FS_IOCTL_DEV)
/* clang-format on */
-typedef u16 access_mask_t;
+typedef u32 access_mask_t;
/* Makes sure all filesystem access rights can be stored. */
static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS);
@@ -76,6 +76,15 @@ struct layer_access_masks {
access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
};
+static inline bool
+layer_access_masks_empty(const struct layer_access_masks *masks)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(masks->access); i++)
+ if (masks->access[i])
+ return false;
+ return true;
+}
+
/*
* Tracks domains responsible of a denied access. This avoids storing in each
* object the full matrix of per-layer unfulfilled access rights, which is
diff --git a/security/landlock/audit.c b/security/landlock/audit.c
index 60ff217ab95b..8d0edf94037d 100644
--- a/security/landlock/audit.c
+++ b/security/landlock/audit.c
@@ -37,6 +37,7 @@ static const char *const fs_access_strings[] = {
[BIT_INDEX(LANDLOCK_ACCESS_FS_REFER)] = "fs.refer",
[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",
};
static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index e764470f588c..053217048ac9 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -27,6 +27,7 @@
#include <linux/lsm_hooks.h>
#include <linux/mount.h>
#include <linux/namei.h>
+#include <linux/net.h>
#include <linux/path.h>
#include <linux/pid.h>
#include <linux/rcupdate.h>
@@ -314,7 +315,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
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_RESOLVE_UNIX)
/* clang-format on */
/*
@@ -1561,6 +1563,108 @@ static int hook_path_truncate(const struct path *const path)
return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
}
+/**
+ * unmask_scoped_access - Remove access right bits in @masks in all layers
+ * where @client and @server have the same domain
+ *
+ * This does the same as domain_is_scoped(), but unmasks bits in @masks.
+ * It can not return early as domain_is_scoped() does.
+ *
+ * @client: Client domain
+ * @server: Server domain
+ * @masks: Layer access masks to unmask
+ * @access: Access bit that controls scoping
+ */
+static void unmask_scoped_access(const struct landlock_ruleset *const client,
+ const struct landlock_ruleset *const server,
+ struct layer_access_masks *const masks,
+ const access_mask_t access)
+{
+ int client_layer, server_layer;
+ const struct landlock_hierarchy *client_walker, *server_walker;
+
+ if (WARN_ON_ONCE(!client))
+ return; /* should not happen */
+
+ if (!server)
+ return; /* server has no Landlock domain; nothing to clear */
+
+ client_layer = client->num_layers - 1;
+ client_walker = client->hierarchy;
+ server_layer = server->num_layers - 1;
+ server_walker = server->hierarchy;
+
+ /*
+ * Clears the access bits at all layers where the client domain is the
+ * same as the server domain. We start the walk at min(client_layer,
+ * server_layer). The layer bits until there can not be cleared because
+ * either the client or the server domain is missing.
+ */
+ for (; client_layer > server_layer; client_layer--)
+ client_walker = client_walker->parent;
+
+ for (; server_layer > client_layer; server_layer--)
+ server_walker = server_walker->parent;
+
+ for (; client_layer >= 0; client_layer--) {
+ if (masks->access[client_layer] & access &&
+ client_walker == server_walker)
+ masks->access[client_layer] &= ~access;
+
+ client_walker = client_walker->parent;
+ server_walker = server_walker->parent;
+ }
+}
+
+static int hook_unix_find(const struct path *const path, struct sock *other,
+ int flags)
+{
+ const struct landlock_ruleset *dom_other;
+ const struct landlock_cred_security *subject;
+ struct layer_access_masks layer_masks;
+ struct landlock_request request = {};
+ static const struct access_masks fs_resolve_unix = {
+ .fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
+ };
+ int type = other->sk_type;
+
+ /* Lookup for the purpose of saving coredumps is OK. */
+ if (flags & SOCK_COREDUMP)
+ return 0;
+
+ /* Only stream, dgram and seqpacket sockets are restricted. */
+ if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
+ return 0;
+
+ /* Access to the same (or a lower) domain is always allowed. */
+ subject = landlock_get_applicable_subject(current_cred(),
+ fs_resolve_unix, NULL);
+
+ if (!subject)
+ return 0;
+
+ if (!landlock_init_layer_masks(subject->domain, fs_resolve_unix.fs,
+ &layer_masks, LANDLOCK_KEY_INODE))
+ return 0;
+
+ /* Checks the layers in which we are connecting within the same domain. */
+ dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
+ unmask_scoped_access(subject->domain, dom_other, &layer_masks,
+ fs_resolve_unix.fs);
+
+ if (layer_access_masks_empty(&layer_masks))
+ return 0;
+
+ /* Checks the connections to allow-listed paths. */
+ if (is_access_to_paths_allowed(subject->domain, path,
+ fs_resolve_unix.fs, &layer_masks,
+ &request, NULL, 0, NULL, NULL, NULL))
+ return 0;
+
+ landlock_log_denial(subject, &request);
+ return -EACCES;
+}
+
/* File hooks */
/**
@@ -1838,6 +1942,7 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = {
LSM_HOOK_INIT(path_unlink, hook_path_unlink),
LSM_HOOK_INIT(path_rmdir, hook_path_rmdir),
LSM_HOOK_INIT(path_truncate, hook_path_truncate),
+ LSM_HOOK_INIT(unix_find, hook_unix_find),
LSM_HOOK_INIT(file_alloc_security, hook_file_alloc_security),
LSM_HOOK_INIT(file_open, hook_file_open),
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index eb584f47288d..b454ad73b15e 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_IOCTL_DEV
+#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_RESOLVE_UNIX
#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 0d66a68677b7..933902d43241 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -164,7 +164,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 = 8;
+const int landlock_abi_version = 9;
/**
* 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 0fea236ef4bd..30d37234086c 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(8, landlock_create_ruleset(NULL, 0,
+ ASSERT_EQ(9, landlock_create_ruleset(NULL, 0,
LANDLOCK_CREATE_RULESET_VERSION));
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 968a91c927a4..b318627e7561 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -575,9 +575,10 @@ 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_RESOLVE_UNIX)
-#define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV
+#define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX
#define ACCESS_ALL ( \
ACCESS_FILE | \
--
2.52.0
^ permalink raw reply related
* [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
From: Günther Noack @ 2026-02-08 23:10 UTC (permalink / raw)
To: Mickaël Salaün, John Johansen, Paul Moore, James Morris,
Serge E . Hallyn
Cc: Günther Noack, Tingmao Wang, Justin Suess,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi, Simon Horman, netdev,
Alexander Viro, Christian Brauner
In-Reply-To: <20260208231017.114343-1-gnoack3000@gmail.com>
From: Justin Suess <utilityemal77@gmail.com>
Add a LSM hook security_unix_find.
This hook is called to check the path of a named unix socket before a
connection is initiated. The peer socket may be inspected as well.
Why existing hooks are unsuitable:
Existing socket hooks, security_unix_stream_connect(),
security_unix_may_send(), and security_socket_connect() don't provide
TOCTOU-free / namespace independent access to the paths of sockets.
(1) We cannot resolve the path from the struct sockaddr in existing hooks.
This requires another path lookup. A change in the path between the
two lookups will cause a TOCTOU bug.
(2) We cannot use the struct path from the listening socket, because it
may be bound to a path in a different namespace than the caller,
resulting in a path that cannot be referenced at policy creation time.
Cc: Günther Noack <gnoack3000@gmail.com>
Cc: Tingmao Wang <m@maowtm.org>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
include/linux/lsm_hook_defs.h | 5 +++++
include/linux/security.h | 11 +++++++++++
net/unix/af_unix.c | 9 +++++++++
security/security.c | 20 ++++++++++++++++++++
4 files changed, 45 insertions(+)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 8c42b4bde09c..7a0fd3dbfa29 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
LSM_HOOK(int, 0, watch_key, struct key *key)
#endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
+ int flags)
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
#ifdef CONFIG_SECURITY_NETWORK
LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
struct sock *newsk)
diff --git a/include/linux/security.h b/include/linux/security.h
index 83a646d72f6f..99a33d8eb28d 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1931,6 +1931,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
}
#endif /* CONFIG_SECURITY_NETWORK */
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+
+int security_unix_find(const struct path *path, struct sock *other, int flags);
+
+#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+ return 0;
+}
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
#ifdef CONFIG_SECURITY_INFINIBAND
int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d0511225799b..db9d279b3883 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1226,10 +1226,19 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
if (!S_ISSOCK(inode->i_mode))
goto path_put;
+ err = -ECONNREFUSED;
sk = unix_find_socket_byinode(inode);
if (!sk)
goto path_put;
+ /*
+ * We call the hook because we know that the inode is a socket
+ * and we hold a valid reference to it via the path.
+ */
+ err = security_unix_find(&path, sk, flags);
+ if (err)
+ goto sock_put;
+
err = -EPROTOTYPE;
if (sk->sk_type == type)
touch_atime(&path);
diff --git a/security/security.c b/security/security.c
index 31a688650601..9e9515955098 100644
--- a/security/security.c
+++ b/security/security.c
@@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
#endif /* CONFIG_SECURITY_NETWORK */
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+/*
+ * security_unix_find() - Check if a named AF_UNIX socket can connect
+ * @path: path of the socket being connected to
+ * @other: peer sock
+ * @flags: flags associated with the socket
+ *
+ * This hook is called to check permissions before connecting to a named
+ * AF_UNIX socket.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+ return call_int_hook(unix_find, path, other, flags);
+}
+EXPORT_SYMBOL(security_unix_find);
+
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
#ifdef CONFIG_SECURITY_INFINIBAND
/**
* security_ib_pkey_access() - Check if access to an IB pkey is allowed
--
2.52.0
^ permalink raw reply related
* [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope
From: Günther Noack @ 2026-02-08 23:10 UTC (permalink / raw)
To: Mickaël Salaün, John Johansen, Paul Moore, James Morris,
Serge E . Hallyn
Cc: Günther Noack, linux-security-module, Tingmao Wang,
Justin Suess, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Jann Horn, Tahera Fahimi, Simon Horman, netdev,
Alexander Viro, Christian Brauner
Hello!
This patch set introduces a filesystem-based Landlock restriction
mechanism for connecting to UNIX domain sockets (or addressing them
with sendmsg(2)). It introduces the filesystem access right
LANDLOCK_ACCESS_FS_RESOLVE_UNIX.
For the connection-oriented SOCK_STREAM and SOCK_SEQPACKET type
sockets, the access right makes the connect(2) operation fail with
EACCES, if denied.
SOCK_DGRAM-type UNIX sockets can be used both with connect(2), or by
passing an explicit recipient address with every sendmsg(2)
invocation. In the latter case, the Landlock check is done when an
explicit recipient address is passed to sendmsg(2) and can make
sendmsg(2) return EACCES. When UNIX datagram sockets are connected
with connect(2), a fixed recipient address is associated with the
socket and the check happens during connect(2) and may return EACCES.
When LANDLOCK_ACCESS_FS_RESOLVE_UNIX is handled within a Landlock
domain, this domain will only allow connect(2) and sendmsg(2) to
server sockets that were created within the same domain. Or, to
phrase it the other way around: Unless it is allow-listed with a
LANDLOCK_PATH_BENEATH rule, the newly created domain denies connect(2)
and sendmsg(2) actions that are directed *outwards* of that domain.
In that regard, LANDLOCK_ACCESS_FS_RESOLVE_UNIX has the same semantics
as one of the "scoped" access rights.
== Motivation
Currently, landlocked processes can connect to named UNIX sockets
through the BSD socket API described in unix(7), by invoking socket(2)
followed by connect(2) with a suitable struct sockname_un holding the
socket's filename. This is a surprising gap in Landlock's sandboxing
capabilities for users (e.g. in [1]) and it can be used to escape a
sandbox when a Unix service offers command execution (various such
scenarios were listed by Tingmao Wang in [2]).
The original feature request is at [4].
== Alternatives and Related Work
=== Alternative: Use existing LSM hooks
We have carefully and seriously considered the use of existing LSM
hooks, but still came to the conclusion that a new LSM hook is better
suited in this case:
The existing hooks security_unix_stream_connect(),
security_unix_may_send() and security_socket_connect() do not give
access to the resolved filesystem path.
* Resolving the filesystem path in the struct sockaddr_un again within
a Landlock would produce a TOCTOU race, so this is not an option.
* We would therefore need to wire through the resolved struct path
from unix_find_bsd() to one of the existing LSM hooks which get
called later. This would be a more substantial change to af_unix.c.
The struct path that is available in the listening-side struct sock is
can be read through the existing hooks, but it is not an option to use
this information: As the listening socket may have been bound from
within a different namespace, the path that was used for that can is
in the general case not meaningful for a sandboxed process. In
particular, it is not possible to use this path (or prefixes thereof)
when constructing a sandbox policy in the client-side process.
Paul Moore also chimed in in support of adding a new hook, with the
rationale that the simplest change to the LSM hook interface has
traditionally proven to be the most robust. [11]
More details are on the Github issue at [6] and on the LKML at [9].
In a the discussion of the V2 review, started by Christian Brauner
[10], we have further explored the approach of reusing the existing
LSM hooks but still ended up leaning on the side of introducing a new
hook, with Paul Moore and me (gnoack) arguing for that option.
Further insights about the LSM hook were shared in the V3 review by
Tingmao Wang [12], who spotted additional requirements due to the two
approaches being merged into one patch set. The summary of that
discussion is in [13].
=== Related work: Scope Control for Pathname Unix Sockets
The motivation for this patch is the same as in Tingmao Wang's patch
set for "scoped" control for pathname Unix sockets [2], originally
proposed in the Github feature request [5].
In [14], we have settled on the decision to merge the two patch sets
into this one, whose primary way of controlling connect(2) is
LANDLOCK_ACCESS_FS_RESOLVE_UNIX, but where this flag additionally has
the semantics of only restricting this unix(7) IPC *outwards* of the
created Landlock domain, in line with the logic that exists for the
existing "scoped" flags already.
By having LANDLOCK_ACCESS_FS_RESOLVE_UNIX implement "scoping"
semantics, we can avoid introducing two separate interacting flags for
now, but we retain the option of introducing
LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET at a later point in time, should
such a flag be needed to express additional rules.
== Credits
The feature was originally suggested by Jann Horn in [7].
Tingmao Wang and Demi Marie Obenour have taken the initiative to
revive this discussion again in [1], [4] and [5].
Tingmao Wang has sent the patch set for the scoped access control for
pathname Unix sockets [2] and has contributed substantial insights
during the code review, shaping the form of the LSM hook and agreeing
to merge the pathname and scoped-flag patch sets.
Justin Suess has sent the patch for the LSM hook in [8] and
subsequently through this patch set.
Christian Brauner and Paul Moore have contributed to the design of the
new LSM hook, discussing the tradeoffs in [10].
Ryan Sullivan has started on an initial implementation and has brought
up relevant discussion points on the Github issue at [4].
As maintainer of Landlock, Mickaël Salaün has done the main review so
far and particularly pointed out ways in which the UNIX connect()
patch sets interact with each other and what we need to look for with
regards to UAPI consistency as Landlock evolves.
[1] https://lore.kernel.org/landlock/515ff0f4-2ab3-46de-8d1e-5c66a93c6ede@gmail.com/
[2] Tingmao Wang's "Implement scope control for pathname Unix sockets"
https://lore.kernel.org/all/cover.1767115163.git.m@maowtm.org/
[3] https://lore.kernel.org/all/20251230.bcae69888454@gnoack.org/
[4] Github issue for FS-based control for named Unix sockets:
https://github.com/landlock-lsm/linux/issues/36
[5] Github issue for scope-based restriction of named Unix sockets:
https://github.com/landlock-lsm/linux/issues/51
[6] https://github.com/landlock-lsm/linux/issues/36#issuecomment-2950632277
[7] https://lore.kernel.org/linux-security-module/CAG48ez3NvVnonOqKH4oRwRqbSOLO0p9djBqgvxVwn6gtGQBPcw@mail.gmail.com/
[8] Patch for the LSM hook:
https://lore.kernel.org/all/20251231213314.2979118-1-utilityemal77@gmail.com/
[9] https://lore.kernel.org/all/20260108.64bd7391e1ae@gnoack.org/
[10] https://lore.kernel.org/all/20260113-kerngesund-etage-86de4a21da24@brauner/
[11] https://lore.kernel.org/all/CAHC9VhQHZCe0LMx4xzSo-h1SWY489U4frKYnxu4YVrcJN3x7nA@mail.gmail.com/
[12] https://lore.kernel.org/all/e6b6b069-384c-4c45-a56b-fa54b26bc72a@maowtm.org/
[13] https://lore.kernel.org/all/aYMenaSmBkAsFowd@google.com/
[14] https://lore.kernel.org/all/20260205.Kiech3gupee1@digikod.net/
---
== Older versions of this patch set
V1: https://lore.kernel.org/all/20260101134102.25938-1-gnoack3000@gmail.com/
V2: https://lore.kernel.org/all/20260110143300.71048-2-gnoack3000@gmail.com/
V3: https://lore.kernel.org/all/20260119203457.97676-2-gnoack3000@gmail.com/
Changes in V4:
Since this version, this patch set subsumes the scoping semantics from
Tingmao Wang's "Scope Control" patch set [2], per discussion with
Tingmao Wang and Mickaël Salaün in [14] and in the thread leading up
to it.
Now, LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET only restricts connect(2) and
sendmsg(2) *outwards* of the domain where it is restricted, *with the
same semantics as a "scoped" flag*.
* Implement a layer-mask based version of domain_is_scoped():
unmask_scoped_access(). Rationale: domain_is_scoped() returns
early, which we can't do in the layer masks based variant. The two
variants are similar enough.
* LSM hook: Replace 'type' argument with 'sk' argument,
per discussion in [12] and [13].
* Bump ABI version to 9 (pessimistically assuming that we won't make
it for 7.0)
* Documentation fixes in header file and in Documentation/
* selftests: more test variants, now also parameterizing whether the
server socket gets created within the Landlock domain or before that
* selftests: use EXPECT_EQ() for test cleanup
Changes in V3:
* LSM hook: rename it to security_unix_find() (Justin Suess)
(resolving the previously open question about the LSM hook name)
Related discussions:
https://lore.kernel.org/all/20260112.Wufar9coosoo@digikod.net/
https://lore.kernel.org/all/CAHC9VhSRiHwLEWfFkQdPEwgB4AXKbXzw_+3u=9hPpvUTnu02Bg@mail.gmail.com/
* Reunite the three UNIX resolving access rights back into one
(resolving the previously open question about the access right
structuring) Related discussion:
https://lore.kernel.org/all/20260112.Wufar9coosoo@digikod.net/)
* Sample tool: Add new UNIX lookup access rights to ACCESS_FILE
Changes in V2:
* Send Justin Suess's LSM hook patch together with the Landlock
implementation
* LSM hook: Pass type and flags parameters to the hook, to make the
access right more generally usable across LSMs, per suggestion from
Paul Moore (Implemented by Justin)
* Split the access right into the three types of UNIX domain sockets:
SOCK_STREAM, SOCK_DGRAM and SOCK_SEQPACKET.
* selftests: More exhaustive tests.
* Removed a minor commit from V1 which adds a missing close(fd) to a
test (it is already in the mic-next branch)
Günther Noack (5):
landlock: Control pathname UNIX domain socket resolution by path
samples/landlock: Add support for named UNIX domain socket
restrictions
landlock/selftests: Test named UNIX domain socket restrictions
landlock: Document FS access right for pathname UNIX sockets
landlock: Document design rationale for scoped access rights
Justin Suess (1):
lsm: Add LSM hook security_unix_find
Documentation/security/landlock.rst | 38 ++
Documentation/userspace-api/landlock.rst | 16 +-
include/linux/lsm_hook_defs.h | 5 +
include/linux/security.h | 11 +
include/uapi/linux/landlock.h | 10 +
net/unix/af_unix.c | 9 +
samples/landlock/sandboxer.c | 15 +-
security/landlock/access.h | 11 +-
security/landlock/audit.c | 1 +
security/landlock/fs.c | 107 ++++-
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
security/security.c | 20 +
tools/testing/selftests/landlock/base_test.c | 2 +-
tools/testing/selftests/landlock/fs_test.c | 386 ++++++++++++++++++-
15 files changed, 608 insertions(+), 27 deletions(-)
--
2.52.0
^ permalink raw reply
* Re: [PATCH v2 0/6] Landlock: Implement scope control for pathname Unix sockets
From: Tingmao Wang @ 2026-02-08 20:48 UTC (permalink / raw)
To: Günther Noack
Cc: Mickaël Salaün, Günther Noack, Justin Suess,
Paul Moore, John Johansen, Demi Marie Obenour, Alyssa Ross,
Jann Horn, Tahera Fahimi, Matthieu Buffet, linux-security-module
In-Reply-To: <20260208.4600394b9da7@gnoack.org>
On 2/8/26 20:37, Günther Noack wrote:
> On Sun, Feb 08, 2026 at 02:57:10AM +0000, Tingmao Wang wrote:
>> On 2/5/26 10:27, Mickaël Salaün wrote:
>>> On Thu, Feb 05, 2026 at 09:02:19AM +0100, Günther Noack wrote:
>>>> [...]
>>>>
>>>> The implementation of this approach would be that we would have to
>>>> join the functionality from the scoped and FS-based patch set, but
>>>> without introducing the LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET flag in
>>>> the UAPI.
>>>
>>> Right, this looks good to me. We'll need to sync both patch series and
>>> remove the scope flag from UAPI. I'll let you and Tingmao work together
>>> for the next series. The "IPC scoping" documentation section should
>>> mention LANDLOCK_ACCESS_FS_RESOLVE_UNIX even if it's not a scope flag.
>>
>> This sounds good to me. I'm not sure how much code we can reuse out of
>> the existing LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET patchset - but I think
>> the selftest patches could still largely be useful (after changing e.g.
>> create_scoped_domain() to use the RESOLVE_UNIX fs access instead of the
>> scope bit for pathname sockets). The fs-based rules (i.e. "exceptions")
>> can then be tested separately from the scope tests (and would also check
>> for things like path being different across mount namespaces etc).
>>
>> Günther, feel free to take anything out of the existing scope series, if
>> you feel it would be useful. Also let me know if you would like me to
>> help with any part of the RESOLVE_UNIX series if you feel that would be
>> useful (but you don't have to if not).
>
> Thank you, Tingmao!
>
> So far, the selftests that I already had in fs_test.c were
> straightforward to extend so that they cover the new cases. I had a
> look at your patch set, but found the scoping tests difficult to port
> to fs_test.c
I was thinking that the tests in scoped_abstract_unix_test.c could be
extended to test scoping of pathname UNIX sockets as well (otherwise
wouldn't you have to write another instance of the scoped_domains test
based on scoped_base_variants.h, whether you put it in fs_test.c or
somewhere else?)
And if you think that is sensible, then I'm hoping that patch 4,5,6 of the
series would be mostly useful. But it's up to you :)
> , but I'll double check that we don't miss anything.
> Either way, I'll make sure that you'll get appropriate credit for
> it. :)
Thanks!
Tingmao
> ...
^ permalink raw reply
* Re: [PATCH v2 0/6] Landlock: Implement scope control for pathname Unix sockets
From: Günther Noack @ 2026-02-08 20:37 UTC (permalink / raw)
To: Tingmao Wang
Cc: Mickaël Salaün, Günther Noack, Justin Suess,
Paul Moore, John Johansen, Demi Marie Obenour, Alyssa Ross,
Jann Horn, Tahera Fahimi, Matthieu Buffet, linux-security-module
In-Reply-To: <ee38960f-8670-434b-9cf1-d95995b228da@maowtm.org>
On Sun, Feb 08, 2026 at 02:57:10AM +0000, Tingmao Wang wrote:
> On 2/5/26 10:27, Mickaël Salaün wrote:
> > On Thu, Feb 05, 2026 at 09:02:19AM +0100, Günther Noack wrote:
> >> [...]
> >>
> >> The implementation of this approach would be that we would have to
> >> join the functionality from the scoped and FS-based patch set, but
> >> without introducing the LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET flag in
> >> the UAPI.
> >
> > Right, this looks good to me. We'll need to sync both patch series and
> > remove the scope flag from UAPI. I'll let you and Tingmao work together
> > for the next series. The "IPC scoping" documentation section should
> > mention LANDLOCK_ACCESS_FS_RESOLVE_UNIX even if it's not a scope flag.
>
> This sounds good to me. I'm not sure how much code we can reuse out of
> the existing LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET patchset - but I think
> the selftest patches could still largely be useful (after changing e.g.
> create_scoped_domain() to use the RESOLVE_UNIX fs access instead of the
> scope bit for pathname sockets). The fs-based rules (i.e. "exceptions")
> can then be tested separately from the scope tests (and would also check
> for things like path being different across mount namespaces etc).
>
> Günther, feel free to take anything out of the existing scope series, if
> you feel it would be useful. Also let me know if you would like me to
> help with any part of the RESOLVE_UNIX series if you feel that would be
> useful (but you don't have to if not).
Thank you, Tingmao!
So far, the selftests that I already had in fs_test.c were
straightforward to extend so that they cover the new cases. I had a
look at your patch set, but found the scoping tests difficult to port
to fs_test.c, but I'll double check that we don't miss anything.
Either way, I'll make sure that you'll get appropriate credit for
it. :)
–Günther
(P.S. If this mail looks familiar, it's because I accidentally replied
with an earlier version of that to the wrong mail earlier today
(https://lore.kernel.org/all/20260208.b25c4105bc03@gnoack.org/) –
Replying here again so that this answer makes more sense.)
^ permalink raw reply
* Re: [PATCH v9 11/11] tpm-buf: Implement managed allocations
From: Jarkko Sakkinen @ 2026-02-08 14:09 UTC (permalink / raw)
To: linux-integrity
Cc: Jarkko Sakkinen, Ross Philipson, Stefan Berger, James Bottomley,
Mimi Zohar, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, open list:KEYS-TRUSTED,
open list:SECURITY SUBSYSTEM, open list
In-Reply-To: <20260125192526.782202-12-jarkko@kernel.org>
On Sun, Jan 25, 2026 at 09:25:21PM +0200, Jarkko Sakkinen wrote:
> From: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
>
> Decouple kzalloc from buffer creation, so that a managed allocation can be
> used:
>
> struct tpm_buf *buf __free(kfree) buf = kzalloc(TPM_BUFSIZE,
> GFP_KERNEL);
> if (!buf)
> return -ENOMEM;
>
> tpm_buf_init(buf, TPM_BUFSIZE);
>
> Alternatively, stack allocations are also possible:
>
> u8 buf_data[512];
> struct tpm_buf *buf = (struct tpm_buf *)buf_data;
> tpm_buf_init(buf, sizeof(buf_data));
>
> This is achieved by embedding buffer's header inside the allocated blob,
> instead of having an outer wrapper.
>
> Cc: Ross Philipson <ross.philipson@oracle.com>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@opinsys.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Since rest of the series does not seem to move forward maybe I should
rebase this to bottom and send it as a separate patch?
This patch eliminates a category of memory bugs and is that way useful.
It also starts to be pretty well stress tested.
BR, Jarkko
^ permalink raw reply
* Re: [PATCH v2 0/6] Landlock: Implement scope control for pathname Unix sockets
From: Günther Noack @ 2026-02-08 13:49 UTC (permalink / raw)
To: Tingmao Wang
Cc: Mickaël Salaün, Justin Suess, Günther Noack,
Demi Marie Obenour, Alyssa Ross, Jann Horn, Tahera Fahimi,
linux-security-module, Matthieu Buffet
In-Reply-To: <3f9d456f-8343-4b46-8770-38190f838dbe@maowtm.org>
On Sun, Feb 08, 2026 at 02:57:16AM +0000, Tingmao Wang wrote:
> On 2/5/26 19:15, Mickaël Salaün wrote:
> > On Thu, Feb 05, 2026 at 10:18:54AM -0500, Justin Suess wrote:
> >> On 2/4/26 13:28, Mickaël Salaün wrote:
> >>>> Tingmao:
> >>>>
> >>>> For connecting a pathname unix socket, the order of the hooks landlock sees is something like:
> >>>>
> >>>> 1. security_unix_find. (to look up the paths)
> >>>>
> >>>> 2. security_unix_may_send, security_unix_stream_connect (after the path is looked up)
>
> btw, ideally for pathname sockets we can leave all the checking in the
> security_unix_find() hook (as newly proposed, with the struct sock *other
> param), and not have to e.g. call domain_is_scoped() again in
> security_unix_may_send and security_unix_stream_connect, right?
>
> (Although if this changes error codes, we might have to "delay" the denial
> until the may_send/connect hooks...? Hopefully not but not checked.)
Thank you, Tingmao!
So far, the selftests that I already had in fs_test.c were
straightforward to extend so that they cover the new cases, but I'll
definitely have a look through your patch set and see if there are
parts that we can reuse or that I missed to cover. Either way, I'll
make sure that you'll get appropriate credit for it. :)
–Günther
^ permalink raw reply
* Re: [PATCH v2 0/6] Landlock: Implement scope control for pathname Unix sockets
From: Günther Noack @ 2026-02-08 13:44 UTC (permalink / raw)
To: Tingmao Wang, g
Cc: Mickaël Salaün, Justin Suess, Günther Noack,
Demi Marie Obenour, Alyssa Ross, Jann Horn, Tahera Fahimi,
linux-security-module, Matthieu Buffet
In-Reply-To: <3f9d456f-8343-4b46-8770-38190f838dbe@maowtm.org>
On Sun, Feb 08, 2026 at 02:57:16AM +0000, Tingmao Wang wrote:
> On 2/5/26 19:15, Mickaël Salaün wrote:
> > On Thu, Feb 05, 2026 at 10:18:54AM -0500, Justin Suess wrote:
> >> On 2/4/26 13:28, Mickaël Salaün wrote:
> >>>> Tingmao:
> >>>>
> >>>> For connecting a pathname unix socket, the order of the hooks landlock sees is something like:
> >>>>
> >>>> 1. security_unix_find. (to look up the paths)
> >>>>
> >>>> 2. security_unix_may_send, security_unix_stream_connect (after the path is looked up)
>
> btw, ideally for pathname sockets we can leave all the checking in the
> security_unix_find() hook (as newly proposed, with the struct sock *other
> param), and not have to e.g. call domain_is_scoped() again in
> security_unix_may_send and security_unix_stream_connect, right?
>
> (Although if this changes error codes, we might have to "delay" the denial
> until the may_send/connect hooks...? Hopefully not but not checked.)
Yes, absolutely. I have had a stab at it and will send it soon.
Justin adopted your suggestion from [1] and created an updated LSM
hook patch based on it. With that, I am doing both checks in the
security_unix_find() hook, based on the resulting struct sock.
[1] https://lore.kernel.org/all/e6b6b069-384c-4c45-a56b-fa54b26bc72a@maowtm.org/#t
–Günther
^ permalink raw reply
* Re: [PATCH v2 0/6] Landlock: Implement scope control for pathname Unix sockets
From: Tingmao Wang @ 2026-02-08 2:57 UTC (permalink / raw)
To: Mickaël Salaün, Justin Suess, Günther Noack
Cc: Günther Noack, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi, linux-security-module, Matthieu Buffet
In-Reply-To: <20260205.phohK6hajaih@digikod.net>
On 2/5/26 19:15, Mickaël Salaün wrote:
> On Thu, Feb 05, 2026 at 10:18:54AM -0500, Justin Suess wrote:
>>
>> On 2/4/26 13:28, Mickaël Salaün wrote:
>>
>>>> [...]
>>>> Tingmao:
>>>>
>>>> For connecting a pathname unix socket, the order of the hooks landlock sees is something like:
>>>>
>>>> 1. security_unix_find. (to look up the paths)
>>>>
>>>> 2. security_unix_may_send, security_unix_stream_connect (after the path is looked up)
btw, ideally for pathname sockets we can leave all the checking in the
security_unix_find() hook (as newly proposed, with the struct sock *other
param), and not have to e.g. call domain_is_scoped() again in
security_unix_may_send and security_unix_stream_connect, right?
(Although if this changes error codes, we might have to "delay" the denial
until the may_send/connect hooks...? Hopefully not but not checked.)
^ permalink raw reply
* Re: [PATCH v2 0/6] Landlock: Implement scope control for pathname Unix sockets
From: Tingmao Wang @ 2026-02-08 2:57 UTC (permalink / raw)
To: Mickaël Salaün, Günther Noack
Cc: Günther Noack, Justin Suess, Paul Moore, John Johansen,
Demi Marie Obenour, Alyssa Ross, Jann Horn, Tahera Fahimi,
Matthieu Buffet, linux-security-module
In-Reply-To: <20260205.Kiech3gupee1@digikod.net>
On 2/5/26 10:27, Mickaël Salaün wrote:
> On Thu, Feb 05, 2026 at 09:02:19AM +0100, Günther Noack wrote:
>> [...]
>>
>> The implementation of this approach would be that we would have to
>> join the functionality from the scoped and FS-based patch set, but
>> without introducing the LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET flag in
>> the UAPI.
>
> Right, this looks good to me. We'll need to sync both patch series and
> remove the scope flag from UAPI. I'll let you and Tingmao work together
> for the next series. The "IPC scoping" documentation section should
> mention LANDLOCK_ACCESS_FS_RESOLVE_UNIX even if it's not a scope flag.
This sounds good to me. I'm not sure how much code we can reuse out of
the existing LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET patchset - but I think
the selftest patches could still largely be useful (after changing e.g.
create_scoped_domain() to use the RESOLVE_UNIX fs access instead of the
scope bit for pathname sockets). The fs-based rules (i.e. "exceptions")
can then be tested separately from the scope tests (and would also check
for things like path being different across mount namespaces etc).
Günther, feel free to take anything out of the existing scope series, if
you feel it would be useful. Also let me know if you would like me to
help with any part of the RESOLVE_UNIX series if you feel that would be
useful (but you don't have to if not).
^ permalink raw reply
* [PATCH v1] mailmap: Add entry for Mickaël Salaün
From: Mickaël Salaün @ 2026-02-07 11:11 UTC (permalink / raw)
To: linux-kernel
Cc: Mickaël Salaün, linux-security-module,
Günther Noack, James Morris
My Microsoft address is no longer used. Add a mailmap entry to reflect
that.
Cc: Günther Noack <gnoack@google.com>
Cc: James Morris <jamorris@linux.microsoft.com>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---
.mailmap | 1 +
1 file changed, 1 insertion(+)
diff --git a/.mailmap b/.mailmap
index 22db8cfc18fc..2f2a06e8d3f9 100644
--- a/.mailmap
+++ b/.mailmap
@@ -558,6 +558,7 @@ Michel Dänzer <michel@tungstengraphics.com>
Michel Lespinasse <michel@lespinasse.org>
Michel Lespinasse <michel@lespinasse.org> <walken@google.com>
Michel Lespinasse <michel@lespinasse.org> <walken@zoy.org>
+Mickaël Salaün <mic@digikod.net> <mic@linux.microsoft.com>
Miguel Ojeda <ojeda@kernel.org> <miguel.ojeda.sandonis@gmail.com>
Mike Rapoport <rppt@kernel.org> <mike@compulab.co.il>
Mike Rapoport <rppt@kernel.org> <mike.rapoport@gmail.com>
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v3 3/3] landlock: transpose the layer masks data structure
From: Mickaël Salaün @ 2026-02-07 10:17 UTC (permalink / raw)
To: Günther Noack
Cc: linux-security-module, Tingmao Wang, Justin Suess,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Randy Dunlap
In-Reply-To: <20260206151154.97915-5-gnoack3000@gmail.com>
On Fri, Feb 06, 2026 at 04:11:55PM +0100, Günther Noack wrote:
> The layer masks data structure tracks the requested but unfulfilled
> access rights during an operation's security check. It stores one bit
> for each combination of access right and layer index. If the bit is
> set, that access right is not granted (yet) in the given layer and we
> have to traverse the path further upwards to grant it.
>
> Previously, the layer masks were stored as arrays mapping from access
> right indices to layer_mask_t. The layer_mask_t value then indicates
> all layers in which the given access right is still (tentatively)
> denied.
>
> This patch introduces struct layer_access_masks instead: This struct
> contains an array with the access_mask_t of each (tentatively) denied
> access right in that layer.
>
> The hypothesis of this patch is that this simplifies the code enough
> so that the resulting code will run faster:
>
> * We can use bitwise operations in multiple places where we previously
> looped over bits individually with macros. (Should require less
> branch speculation and lends itself to better loop unrolling.)
>
> * Code is ~75 lines smaller.
>
> Other noteworthy changes:
>
> * In no_more_access(), call a new helper function may_refer(), which
> only solves the asymmetric case. Previously, the code interleaved
> the checks for the two symmetric cases in RENAME_EXCHANGE. It feels
> that the code is clearer when renames without RENAME_EXCHANGE are
> more obviously the normal case.
>
> Tradeoffs:
>
> This change improves performance, at a slight size increase to the
> layer masks data structure.
>
> This fixes the size of the data structure at 32 bytes for all types of
> access rights. (64, once we introduce a 17th filesystem access right).
>
> For filesystem access rights, at the moment, the data structure has
> the same size as before, but once we introduce the 17th filesystem
> access right, it will double in size (from 32 to 64 bytes), as
> access_mask_t grows from 16 to 32 bit. [1]
>
> Link: https://lore.kernel.org/all/20260120.haeCh4li9Vae@digikod.net/ [1]
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
> security/landlock/access.h | 15 +-
> security/landlock/audit.c | 81 +++------
> security/landlock/audit.h | 3 +-
> security/landlock/domain.c | 45 ++---
> security/landlock/domain.h | 4 +-
> security/landlock/fs.c | 348 ++++++++++++++++--------------------
> security/landlock/net.c | 9 +-
> security/landlock/ruleset.c | 89 ++++-----
> security/landlock/ruleset.h | 21 ++-
> 9 files changed, 274 insertions(+), 341 deletions(-)
>
> diff --git a/security/landlock/access.h b/security/landlock/access.h
> index bab403470a6c..f0a9afeb4a2a 100644
> --- a/security/landlock/access.h
> +++ b/security/landlock/access.h
> @@ -61,14 +61,15 @@ union access_masks_all {
> static_assert(sizeof(typeof_member(union access_masks_all, masks)) ==
> sizeof(typeof_member(union access_masks_all, all)));
>
> -typedef u16 layer_mask_t;
> -
> -/* Makes sure all layers can be checked. */
> -static_assert(BITS_PER_TYPE(layer_mask_t) >= LANDLOCK_MAX_NUM_LAYERS);
> -
> /*
> - * Tracks domains responsible of a denied access. This is required to avoid
> - * storing in each object the full layer_masks[] required by update_request().
> + * Tracks domains responsible of a denied access. This avoids storing in each
> + * object the full matrix of per-layer unfulfilled access rights, which is
> + * required by update_request().
> + *
> + * Each nibble represents the layer index of the newest layer which denied a
> + * certain access right. For file system access rights, the upper four bits are
> + * the index of the layer which denies LANDLOCK_ACCESS_FS_IOCTL_DEV and the
> + * lower nibble represents LANDLOCK_ACCESS_FS_TRUNCATE.
> */
> typedef u8 deny_masks_t;
>
> diff --git a/security/landlock/domain.c b/security/landlock/domain.c
> index a647b68e8d06..d2a4354feeb4 100644
> --- a/security/landlock/domain.c
> +++ b/security/landlock/domain.c
> @@ -7,6 +7,7 @@
> * Copyright © 2024-2025 Microsoft Corporation
> */
>
> +#include "ruleset.h"
To avoid this new include (which makes a dependency on ruleset
definitions for domain-specific definitions), I moved the struct
layer_access_masks definition to access.h, which makes more sense
anyway.
> #include <kunit/test.h>
> #include <linux/bitops.h>
> #include <linux/bits.h>
> diff --git a/security/landlock/domain.h b/security/landlock/domain.h
> index 621f054c9a2b..227066d667f7 100644
> --- a/security/landlock/domain.h
> +++ b/security/landlock/domain.h
> @@ -10,6 +10,7 @@
> #ifndef _SECURITY_LANDLOCK_DOMAIN_H
> #define _SECURITY_LANDLOCK_DOMAIN_H
>
> +#include "ruleset.h"
> #include <linux/limits.h>
> #include <linux/mm.h>
> #include <linux/path.h>
> diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
> index 1a78cba662b2..1ceb5fd674c9 100644
> --- a/security/landlock/ruleset.h
> +++ b/security/landlock/ruleset.h
> @@ -301,15 +301,28 @@ landlock_get_scope_mask(const struct landlock_ruleset *const ruleset,
> return ruleset->access_masks[layer_level].scope;
> }
>
> +/**
> + * struct layer_access_masks - A boolean matrix of layers and access rights
> + *
> + * This has a bit for each combination of layer numbers and access rights.
> + * During access checks, it is used to represent the access rights for each
> + * layer which still need to be fulfilled. When all bits are 0, the access
> + * request is considered to be fulfilled.
> + */
> +struct layer_access_masks {
> + /**
> + * @access: The unfulfilled access rights for each layer.
> + */
> + access_mask_t access[LANDLOCK_MAX_NUM_LAYERS];
> +};
> +
> bool landlock_unmask_layers(const struct landlock_rule *const rule,
> - const access_mask_t access_request,
> - layer_mask_t (*const layer_masks)[],
> - const size_t masks_array_size);
> + struct layer_access_masks *masks);
>
> access_mask_t
> landlock_init_layer_masks(const struct landlock_ruleset *const domain,
> const access_mask_t access_request,
> - layer_mask_t (*const layer_masks)[],
> + struct layer_access_masks *masks,
> const enum landlock_key_type key_type);
>
> #endif /* _SECURITY_LANDLOCK_RULESET_H */
> --
> 2.52.0
>
>
^ permalink raw reply
* Re: [PATCH v5 3/3] ima: Use kstat.ctime as a fallback change detection for stacked fs
From: Frederick Lawler @ 2026-02-06 20:06 UTC (permalink / raw)
To: Mimi Zohar
Cc: Roberto Sassu, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
Paul Moore, James Morris, Serge E. Hallyn, Darrick J. Wong,
Christian Brauner, Josef Bacik, Jeff Layton, linux-kernel,
linux-integrity, linux-security-module, kernel-team
In-Reply-To: <6f82d5dc6b499ecd03c985d6de20de94fea04cfe.camel@linux.ibm.com>
On Wed, Feb 04, 2026 at 11:26:27PM -0500, Mimi Zohar wrote:
> On Wed, 2026-02-04 at 15:22 -0600, Frederick Lawler wrote:
> > That said, I think Mimi pointed out in an email [2] where multi-grain
> > file systems are impacted regardless of stacked fs or not due to the last
> > writer check.
> >
> > I don't recall coming across that in my tests, but perhaps I did that
> > specific test wrong? To be sure, I created the C program, and on the VM,
> > created a XFS disk, mounted it on loopback, ran the rdwr program on
> > "somefile" multiple times, and only got 1 audit log for it, until I
> > mutated it with touch, and only got 2 hits: original + after mutation
> > after running the program multiple times.
> >
> > I'm not sure what's going on there, so I'll look into that a bit more,
> > but so far the impact is stacked file systems & multigrain ctime AFAIK.
>
> Make sure you're testing without your patch set applied or at least the last
> patch.
>
I'm still not sure what went wrong with my test suite, but spinning up a
VM similar to Mimi's, I was able to reproduce the last writer issue. I
used patch 1 as a baseline because that's noop from base 6.19, and used
that function as a convenient trace point.
And, then running the attached example test for stacked FS works as
expected on both patches 1 (multiple log messages) & 3 (just one log
message).
I left out the dump_stack() in integrity_inode_attrs_stat_change()
for readability in these results. For Mimi's test, we just see
calls into ima_check_last_writer(), and for the attached sample
in 0/0, we get the calls straight from process_measurement() for
stacked fs. Running Mimi's and then attached in that order, I get
double the logs because the FILE_CHECK is hitting the last writer,
and we get the process_measurement() for the binary run.
Based on all of this, I can drop the stacked FS wording in the patch
descriptions, and keep it all focused that the change_cookie semantics
have been changed for multigrain file systems.
Results:
PATCH 1/3
[root@localhost ~]# ./mimi.sh
filename: /usr/bin/date-20260206140427
filename: /usr/bin/date-20260206140427
filename: /usr/bin/date-20260206140427
FAIL: Expected 1 audit event, but found 3.
[ 26.033572] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=0 change_cookie=0
[ 26.034372] ima: fred: ima_check_last_writer: must measure file: "/usr/bin/date-20260206140427"
[ 26.037453] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=0 change_cookie=0
[ 26.038425] ima: fred: ima_check_last_writer: must measure file: "/usr/bin/date-20260206140427"
[ 26.039821] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=0 change_cookie=0
[ 26.041383] ima: fred: ima_check_last_writer: must measure file: "/usr/bin/date-20260206140427"
[root@localhost fred-tests]# ./simple-fedora.sh
314572800 bytes (315 MB, 300 MiB) copied, 0.132908 s, 2.4 GB/s
Fri Feb 6 14:56:18 EST 2026
Fri Feb 6 14:56:18 EST 2026
Fri Feb 6 14:56:18 EST 2026
Fri Feb 6 14:56:18 EST 2026
FAIL: Expected 1 audit event, but found 4.
Note: Does not have dmesg output because this patch didn't put the trace
function into integrity_inode_attrs_changed().
PATCH 3/3
[root@localhost ~]# ./mimi.sh
filename: /usr/bin/date-20260206140141
filename: /usr/bin/date-20260206140141
filename: /usr/bin/date-20260206140141
PASS: Found exactly 1 audit event.
[ 17.191235] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=1770404501462431821 change_cookie=0
[ 17.192213] fred: integrity_inode_attrs_stat_changed result_mask=128 (ctime) version=1770404501462431821 ctime=1770404501462431821
[ 17.196325] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=1770404501462431821 change_cookie=0
[ 17.197380] fred: integrity_inode_attrs_stat_changed result_mask=128 (ctime) version=1770404501462431821 ctime=1770404501462431821
[ 17.199750] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=1770404501462431821 change_cookie=0
[ 17.200682] fred: integrity_inode_attrs_stat_changed result_mask=128 (ctime) version=1770404501462431821 ctime=1770404501462431821
[root@localhost fred-tests]# ./simple-fedora.sh
Fri Feb 6 14:53:30 EST 2026
Fri Feb 6 14:53:30 EST 2026
Fri Feb 6 14:53:30 EST 2026
Fri Feb 6 14:53:30 EST 2026
PASS: Found exactly 1 audit event.
[ 23.315358] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=1770407920086616962 change_cookie=0
[ 23.328978] fred: integrity_inode_attrs_stat_changed result_mask=128 (ctime) version=1770407920086616962 ctime=1770407920086616962
[ 23.332122] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=1770407920086616962 change_cookie=0
[ 23.347162] fred: integrity_inode_attrs_stat_changed result_mask=128 (ctime) version=1770407920086616962 ctime=1770407920086616962
[ 23.352931] fred: integrity_inode_attrs_stat_changed result_mask=0 (change cookie) version=1770407920086616962 change_cookie=0
[ 23.368026] fred: integrity_inode_attrs_stat_changed result_mask=128 (ctime) version=1770407920086616962 ctime=1770407920086616962
Note that the in stacked FS case, process_measurement() skipped the check
for attrs changed, and skipped to measuring. Subsequent calls into
process_measurement() hits the integrity_inode_attrs_stat_changed().
^ permalink raw reply
* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
From: Lorenzo Stoakes @ 2026-02-06 20:01 UTC (permalink / raw)
To: Andrew Morton
Cc: Pedro Falcato, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <20260206113153.c443545459474cdef6dfd7ea@linux-foundation.org>
On Fri, Feb 06, 2026 at 11:31:53AM -0800, Andrew Morton wrote:
> On Fri, 6 Feb 2026 17:46:36 +0000 Pedro Falcato <pfalcato@suse.de> wrote:
>
> > > -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> > > +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> > > + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
> >
> > as a sidenote, these flags are no longer constant expressions and thus
> >
> > static vma_flags_t flags = VMA_REMAP_FLAGS;
I mean this would be a code smell anyway :) but point taken.
> >
> > can't compile.
>
> Yup, that isn't nice. An all-caps thing with no () is a compile-time
> constant.
There is precedence for this, e.g. TASK_SIZE_MAX and other arch defines like
that:
error: initializer element is not a compile-time constant
3309 | static unsigned long task_max = TASK_SIZE_MAX;
| ^~~~~~~~~~~~~
And this will almost certainly (and certainly in everything I tested) become a
compile-time constant via the optimiser so to all intents and purposes it _is_
essentially compile-time.
But the point of doing it this way is to maintain, as much as possible,
one-to-one translation between the previous approach and the new with as little
noise/friction as possible.
Making this a function makes things really horrible honestly.
Because vma_remap_flags() suddenly because a vague thing - I'd assume this was a
function doing something. So now do we call it get_vma_remap_flags()? Suddenly
something nice-ish like:
if (vma_flags_test(flags, VMA_REMAP_FLAGS)) {
...
}
Become:
if (vma_flags_test(flags, get_vma_remap_flags())) {
...
}
And now it's SUPER ambiguous as to what you're doing there. I'd assume right
away that get_vma_remap_flags() was going off and doing something or referencing
a static variable or something.
Given the compile will treat the former _exactly_ as if it were a compile-time
constant it's just adding unnecessary ambiguity.
So is it something we can live with?
If it looks like a duck, walks like a duck and quacks like a duck, but isn't
there when the pond is first dug out, can we still call it a duck? ;)
>
> It looks like we can make this a nice inlined (commented!) lower-cased
> C function as a little low-priority cleanup.
>
> > Rest LGTM though.
> >
> > Acked-by: Pedro Falcato <pfalcato@suse.de>
>
> Great, thanks.
Cheers, Lorenzo
^ permalink raw reply
* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
From: Andrew Morton @ 2026-02-06 19:31 UTC (permalink / raw)
To: Pedro Falcato
Cc: Lorenzo Stoakes, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <hmc2or77xnhrdlncfzjsljljwljnp6zztqsvmgxspfilmzkyty@czxpjpdm66ov>
On Fri, 6 Feb 2026 17:46:36 +0000 Pedro Falcato <pfalcato@suse.de> wrote:
> > -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> > +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> > + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
>
> as a sidenote, these flags are no longer constant expressions and thus
>
> static vma_flags_t flags = VMA_REMAP_FLAGS;
>
> can't compile.
Yup, that isn't nice. An all-caps thing with no () is a compile-time
constant.
It looks like we can make this a nice inlined (commented!) lower-cased
C function as a little low-priority cleanup.
> Rest LGTM though.
>
> Acked-by: Pedro Falcato <pfalcato@suse.de>
Great, thanks.
^ permalink raw reply
* [RFC PATCH] fs/pidfs: Add permission check to pidfd_info()
From: danieldurning.work @ 2026-02-06 18:02 UTC (permalink / raw)
To: linux-fsdevel, linux-security-module, selinux
Cc: viro, brauner, jack, paul, stephen.smalley.work, omosnace
From: Daniel Durning <danieldurning.work@gmail.com>
Added a permission check to pidfd_info(). Originally, process info
could be retrieved with a pidfd even if proc was mounted with hidepid
enabled, allowing pidfds to be used to bypass those protections. We
now call ptrace_may_access() to perform some DAC checking as well
as call the appropriate LSM hook.
The downside to this approach is that there are now more restrictions
on accessing this info from a pidfd than when just using proc (without
hidepid). I am open to suggestions if anyone can think of a better way
to handle this.
I have also noticed that it is possible to use pidfds to poll on any
process regardless of whether the process is a child of the caller,
has a different UID, or has a different security context. Is this
also worth addressing? If so, what exactly should the DAC checks be?
Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
---
fs/pidfs.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/pidfs.c b/fs/pidfs.c
index dba703d4ce4a..058a7d798bca 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -365,6 +365,13 @@ static long pidfd_info(struct file *file, unsigned int cmd, unsigned long arg)
goto copy_out;
}
+ /*
+ * Do a filesystem cred ptrace check to verify access
+ * to the task's info.
+ */
+ if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
+ return -EACCES;
+
c = get_task_cred(task);
if (!c)
return -ESRCH;
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only
From: Pedro Falcato @ 2026-02-06 17:49 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <fd2a2938b246b4505321954062b1caba7acfc77a.1769097829.git.lorenzo.stoakes@oracle.com>
On Thu, Jan 22, 2026 at 04:06:19PM +0000, Lorenzo Stoakes wrote:
> Now we have eliminated all uses of vm_area_desc->vm_flags, eliminate this
> field, and have mmap_prepare users utilise the vma_flags_t
> vm_area_desc->vma_flags field only.
>
> As part of this change we alter is_shared_maywrite() to accept a
> vma_flags_t parameter, and introduce is_shared_maywrite_vm_flags() for use
> with legacy vm_flags_t flags.
>
> We also update struct mmap_state to add a union between vma_flags and
> vm_flags temporarily until the mmap logic is also converted to using
> vma_flags_t.
>
> Also update the VMA userland tests to reflect this change.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply
* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
From: Pedro Falcato @ 2026-02-06 17:46 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <fb1f55323799f09fe6a36865b31550c9ec67c225.1769097829.git.lorenzo.stoakes@oracle.com>
On Thu, Jan 22, 2026 at 04:06:18PM +0000, Lorenzo Stoakes wrote:
> We will be shortly removing the vm_flags_t field from vm_area_desc so we
> need to update all mmap_prepare users to only use the dessc->vma_flags
> field.
>
> This patch achieves that and makes all ancillary changes required to make
> this possible.
>
> This lays the groundwork for future work to eliminate the use of vm_flags_t
> in vm_area_desc altogether and more broadly throughout the kernel.
>
> While we're here, we take the opportunity to replace VM_REMAP_FLAGS with
> VMA_REMAP_FLAGS, the vma_flags_t equivalent.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> drivers/char/mem.c | 6 +++---
> drivers/dax/device.c | 10 +++++-----
> fs/aio.c | 2 +-
> fs/erofs/data.c | 5 +++--
> fs/ext4/file.c | 4 ++--
> fs/ntfs3/file.c | 2 +-
> fs/orangefs/file.c | 4 ++--
> fs/ramfs/file-nommu.c | 2 +-
> fs/resctrl/pseudo_lock.c | 2 +-
> fs/romfs/mmap-nommu.c | 2 +-
> fs/xfs/xfs_file.c | 4 ++--
> fs/zonefs/file.c | 3 ++-
> include/linux/dax.h | 8 ++++----
> include/linux/mm.h | 24 +++++++++++++++++++-----
> kernel/relay.c | 2 +-
> mm/memory.c | 17 ++++++++---------
> 16 files changed, 56 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/char/mem.c b/drivers/char/mem.c
> index 52039fae1594..cca4529431f8 100644
> --- a/drivers/char/mem.c
> +++ b/drivers/char/mem.c
> @@ -306,7 +306,7 @@ static unsigned zero_mmap_capabilities(struct file *file)
> /* can't do an in-place private mapping if there's no MMU */
> static inline int private_mapping_ok(struct vm_area_desc *desc)
> {
> - return is_nommu_shared_mapping(desc->vm_flags);
> + return is_nommu_shared_vma_flags(&desc->vma_flags);
> }
> #else
>
> @@ -360,7 +360,7 @@ static int mmap_mem_prepare(struct vm_area_desc *desc)
>
> desc->vm_ops = &mmap_mem_ops;
>
> - /* Remap-pfn-range will mark the range VM_IO. */
> + /* Remap-pfn-range will mark the range with the I/O flag. */
> mmap_action_remap_full(desc, desc->pgoff);
> /* We filter remap errors to -EAGAIN. */
> desc->action.error_hook = mmap_filter_error;
> @@ -520,7 +520,7 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
> #ifndef CONFIG_MMU
> return -ENOSYS;
> #endif
> - if (desc->vm_flags & VM_SHARED)
> + if (vma_desc_test_flags(desc, VMA_SHARED_BIT))
> return shmem_zero_setup_desc(desc);
>
> desc->action.success_hook = mmap_zero_private_success;
> diff --git a/drivers/dax/device.c b/drivers/dax/device.c
> index 22999a402e02..528e81240c4d 100644
> --- a/drivers/dax/device.c
> +++ b/drivers/dax/device.c
> @@ -13,7 +13,7 @@
> #include "dax-private.h"
> #include "bus.h"
>
> -static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
> +static int __check_vma(struct dev_dax *dev_dax, vma_flags_t flags,
> unsigned long start, unsigned long end, struct file *file,
> const char *func)
> {
> @@ -24,7 +24,7 @@ static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
> return -ENXIO;
>
> /* prevent private mappings from being established */
> - if ((vm_flags & VM_MAYSHARE) != VM_MAYSHARE) {
> + if (!vma_flags_test(&flags, VMA_MAYSHARE_BIT)) {
> dev_info_ratelimited(dev,
> "%s: %s: fail, attempted private mapping\n",
> current->comm, func);
> @@ -53,7 +53,7 @@ static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
> static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
> const char *func)
> {
> - return __check_vma(dev_dax, vma->vm_flags, vma->vm_start, vma->vm_end,
> + return __check_vma(dev_dax, vma->flags, vma->vm_start, vma->vm_end,
> vma->vm_file, func);
> }
>
> @@ -306,14 +306,14 @@ static int dax_mmap_prepare(struct vm_area_desc *desc)
> * fault time.
> */
> id = dax_read_lock();
> - rc = __check_vma(dev_dax, desc->vm_flags, desc->start, desc->end, filp,
> + rc = __check_vma(dev_dax, desc->vma_flags, desc->start, desc->end, filp,
> __func__);
> dax_read_unlock(id);
> if (rc)
> return rc;
>
> desc->vm_ops = &dax_vm_ops;
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> return 0;
> }
>
> diff --git a/fs/aio.c b/fs/aio.c
> index 0a23a8c0717f..59b67b8da1b2 100644
> --- a/fs/aio.c
> +++ b/fs/aio.c
> @@ -394,7 +394,7 @@ static const struct vm_operations_struct aio_ring_vm_ops = {
>
> static int aio_ring_mmap_prepare(struct vm_area_desc *desc)
> {
> - desc->vm_flags |= VM_DONTEXPAND;
> + vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT);
> desc->vm_ops = &aio_ring_vm_ops;
> return 0;
> }
> diff --git a/fs/erofs/data.c b/fs/erofs/data.c
> index bb13c4cb8455..e7bc29e764c6 100644
> --- a/fs/erofs/data.c
> +++ b/fs/erofs/data.c
> @@ -438,11 +438,12 @@ static int erofs_file_mmap_prepare(struct vm_area_desc *desc)
> if (!IS_DAX(file_inode(desc->file)))
> return generic_file_readonly_mmap_prepare(desc);
>
> - if ((desc->vm_flags & VM_SHARED) && (desc->vm_flags & VM_MAYWRITE))
> + if (vma_desc_test_flags(desc, VMA_SHARED_BIT) &&
> + vma_desc_test_flags(desc, VMA_MAYWRITE_BIT))
> return -EINVAL;
>
> desc->vm_ops = &erofs_dax_vm_ops;
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> return 0;
> }
> #else
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 7a8b30932189..dfd5f4fe1647 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -822,13 +822,13 @@ static int ext4_file_mmap_prepare(struct vm_area_desc *desc)
> * We don't support synchronous mappings for non-DAX files and
> * for DAX files if underneath dax_device is not synchronous.
> */
> - if (!daxdev_mapping_supported(desc->vm_flags, file_inode(file), dax_dev))
> + if (!daxdev_mapping_supported(desc, file_inode(file), dax_dev))
> return -EOPNOTSUPP;
>
> file_accessed(file);
> if (IS_DAX(file_inode(file))) {
> desc->vm_ops = &ext4_dax_vm_ops;
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> } else {
> desc->vm_ops = &ext4_file_vm_ops;
> }
> diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
> index 2e7b2e566ebe..2902fc6d9a85 100644
> --- a/fs/ntfs3/file.c
> +++ b/fs/ntfs3/file.c
> @@ -347,7 +347,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc)
> struct inode *inode = file_inode(file);
> struct ntfs_inode *ni = ntfs_i(inode);
> u64 from = ((u64)desc->pgoff << PAGE_SHIFT);
> - bool rw = desc->vm_flags & VM_WRITE;
> + const bool rw = vma_desc_test_flags(desc, VMA_WRITE_BIT);
> int err;
>
> /* Avoid any operation if inode is bad. */
> diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
> index 919f99b16834..c75aa3f419b1 100644
> --- a/fs/orangefs/file.c
> +++ b/fs/orangefs/file.c
> @@ -411,8 +411,8 @@ static int orangefs_file_mmap_prepare(struct vm_area_desc *desc)
> "orangefs_file_mmap: called on %pD\n", file);
>
> /* set the sequential readahead hint */
> - desc->vm_flags |= VM_SEQ_READ;
> - desc->vm_flags &= ~VM_RAND_READ;
> + vma_desc_set_flags(desc, VMA_SEQ_READ_BIT);
> + vma_desc_clear_flags(desc, VMA_RAND_READ_BIT);
>
> file_accessed(file);
> desc->vm_ops = &orangefs_file_vm_ops;
> diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
> index 77b8ca2757e0..0f8e838ece07 100644
> --- a/fs/ramfs/file-nommu.c
> +++ b/fs/ramfs/file-nommu.c
> @@ -264,7 +264,7 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
> */
> static int ramfs_nommu_mmap_prepare(struct vm_area_desc *desc)
> {
> - if (!is_nommu_shared_mapping(desc->vm_flags))
> + if (!is_nommu_shared_vma_flags(&desc->vma_flags))
> return -ENOSYS;
>
> file_accessed(desc->file);
> diff --git a/fs/resctrl/pseudo_lock.c b/fs/resctrl/pseudo_lock.c
> index 0bfc13c5b96d..e81d71abfe54 100644
> --- a/fs/resctrl/pseudo_lock.c
> +++ b/fs/resctrl/pseudo_lock.c
> @@ -1044,7 +1044,7 @@ static int pseudo_lock_dev_mmap_prepare(struct vm_area_desc *desc)
> * Ensure changes are carried directly to the memory being mapped,
> * do not allow copy-on-write mapping.
> */
> - if (!(desc->vm_flags & VM_SHARED)) {
> + if (!vma_desc_test_flags(desc, VMA_SHARED_BIT)) {
> mutex_unlock(&rdtgroup_mutex);
> return -EINVAL;
> }
> diff --git a/fs/romfs/mmap-nommu.c b/fs/romfs/mmap-nommu.c
> index 4b77c6dc4418..7c3a1a7fecee 100644
> --- a/fs/romfs/mmap-nommu.c
> +++ b/fs/romfs/mmap-nommu.c
> @@ -63,7 +63,7 @@ static unsigned long romfs_get_unmapped_area(struct file *file,
> */
> static int romfs_mmap_prepare(struct vm_area_desc *desc)
> {
> - return is_nommu_shared_mapping(desc->vm_flags) ? 0 : -ENOSYS;
> + return is_nommu_shared_vma_flags(&desc->vma_flags) ? 0 : -ENOSYS;
> }
>
> static unsigned romfs_mmap_capabilities(struct file *file)
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 7874cf745af3..1238ec018bc7 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -1974,14 +1974,14 @@ xfs_file_mmap_prepare(
> * We don't support synchronous mappings for non-DAX files and
> * for DAX files if underneath dax_device is not synchronous.
> */
> - if (!daxdev_mapping_supported(desc->vm_flags, file_inode(file),
> + if (!daxdev_mapping_supported(desc, file_inode(file),
> target->bt_daxdev))
> return -EOPNOTSUPP;
>
> file_accessed(file);
> desc->vm_ops = &xfs_file_vm_ops;
> if (IS_DAX(inode))
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> return 0;
> }
>
> diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c
> index c1e5e30e90a0..8a7161fc49e5 100644
> --- a/fs/zonefs/file.c
> +++ b/fs/zonefs/file.c
> @@ -333,7 +333,8 @@ static int zonefs_file_mmap_prepare(struct vm_area_desc *desc)
> * ordering between msync() and page cache writeback.
> */
> if (zonefs_inode_is_seq(file_inode(file)) &&
> - (desc->vm_flags & VM_SHARED) && (desc->vm_flags & VM_MAYWRITE))
> + vma_desc_test_flags(desc, VMA_SHARED_BIT) &&
> + vma_desc_test_flags(desc, VMA_MAYWRITE_BIT))
> return -EINVAL;
>
> file_accessed(file);
> diff --git a/include/linux/dax.h b/include/linux/dax.h
> index 9d624f4d9df6..bf103f317cac 100644
> --- a/include/linux/dax.h
> +++ b/include/linux/dax.h
> @@ -65,11 +65,11 @@ size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff,
> /*
> * Check if given mapping is supported by the file / underlying device.
> */
> -static inline bool daxdev_mapping_supported(vm_flags_t vm_flags,
> +static inline bool daxdev_mapping_supported(const struct vm_area_desc *desc,
> const struct inode *inode,
> struct dax_device *dax_dev)
> {
> - if (!(vm_flags & VM_SYNC))
> + if (!vma_desc_test_flags(desc, VMA_SYNC_BIT))
> return true;
> if (!IS_DAX(inode))
> return false;
> @@ -111,11 +111,11 @@ static inline void set_dax_nomc(struct dax_device *dax_dev)
> static inline void set_dax_synchronous(struct dax_device *dax_dev)
> {
> }
> -static inline bool daxdev_mapping_supported(vm_flags_t vm_flags,
> +static inline bool daxdev_mapping_supported(const struct vm_area_desc *desc,
> const struct inode *inode,
> struct dax_device *dax_dev)
> {
> - return !(vm_flags & VM_SYNC);
> + return !vma_desc_test_flags(desc, VMA_SYNC_BIT);
> }
> static inline size_t dax_recovery_write(struct dax_device *dax_dev,
> pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index fd93317193e0..e31f72a021ef 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -550,17 +550,18 @@ enum {
> /*
> * Physically remapped pages are special. Tell the
> * rest of the world about it:
> - * VM_IO tells people not to look at these pages
> + * IO tells people not to look at these pages
> * (accesses can have side effects).
> - * VM_PFNMAP tells the core MM that the base pages are just
> + * PFNMAP tells the core MM that the base pages are just
> * raw PFN mappings, and do not have a "struct page" associated
> * with them.
> - * VM_DONTEXPAND
> + * DONTEXPAND
> * Disable vma merging and expanding with mremap().
> - * VM_DONTDUMP
> + * DONTDUMP
> * Omit vma from core dump, even when VM_IO turned off.
> */
I don't think it's useful to erase the VM_ prefix off the flags. These still
exist, so maybe the alternative would be to rename them to e.g VMA_IO in
comments, etc. I think just saying "IO" or "the I/O flag" above is ambiguous.
> -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
as a sidenote, these flags are no longer constant expressions and thus
static vma_flags_t flags = VMA_REMAP_FLAGS;
can't compile.
Rest LGTM though.
Acked-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply
* Re: [PATCH v2 05/13] mm: add basic VMA flag operation helper functions
From: Pedro Falcato @ 2026-02-06 17:35 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <885d4897d67a6a57c0b07fa182a7055ad752df11.1769097829.git.lorenzo.stoakes@oracle.com>
On Thu, Jan 22, 2026 at 04:06:14PM +0000, Lorenzo Stoakes wrote:
> Now we have the mk_vma_flags() macro helper which permits easy
> specification of any number of VMA flags, add helper functions which
> operate with vma_flags_t parameters.
>
> This patch provides vma_flags_test[_mask](), vma_flags_set[_mask]() and
> vma_flags_clear[_mask]() respectively testing, setting and clearing flags
> with the _mask variants accepting vma_flag_t parameters, and the non-mask
> variants implemented as macros which accept a list of flags.
>
> This allows us to trivially test/set/clear aggregate VMA flag values as
> necessary, for instance:
>
> if (vma_flags_test(&flags, VMA_READ_BIT, VMA_WRITE_BIT))
> goto readwrite;
I'm not a huge fan of the _test ambiguity here, but more words makes it uglier :/
I think I can live with it though.
>
> vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
> vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
The variadic-ness here is very nice though.
> We also add a function for testing that ALL flags are set for convenience,
> e.g.:
>
> if (vma_flags_test_all(&flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) {
> /* Both READ and MAYREAD flags set */
> ...
> }
>
> The compiler generates optimal assembly for each such that they behave as
> if the caller were setting the bitmap flags manually.
>
> This is important for e.g. drivers which manipulate flag values rather than
> a VMA's specific flag values.
>
> We also add helpers for testing, setting and clearing flags for VMA's and
> VMA descriptors to reduce boilerplate.
>
> Also add the EMPTY_VMA_FLAGS define to aid initialisation of empty flags.
>
> Finally, update the userland VMA tests to add the helpers there so they can
> be utilised as part of userland testing.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply
* Re: [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper
From: Pedro Falcato @ 2026-02-06 17:14 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Christian Koenig, Huang Rui, Matthew Auld,
Matthew Brost, Alexander Viro, Christian Brauner, Jan Kara,
Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu, Jeffle Xu,
Sandeep Dhavale, Hongbo Li, Chunhai Guo, Theodore Ts'o,
Andreas Dilger, Muchun Song, Oscar Salvador, David Hildenbrand,
Konstantin Komarov, Mike Marshall, Martin Brandenburg, Tony Luck,
Reinette Chatre, Dave Martin, James Morse, Babu Moger,
Carlos Maiolino, Damien Le Moal, Naohiro Aota, Johannes Thumshirn,
Matthew Wilcox, Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In-Reply-To: <fde00df6ff7fb8c4b42cc0defa5a4924c7a1943a.1769097829.git.lorenzo.stoakes@oracle.com>
On Thu, Jan 22, 2026 at 04:06:12PM +0000, Lorenzo Stoakes wrote:
> This patch introduces the mk_vma_flags() macro helper to allow easy
> manipulation of VMA flags utilising the new bitmap representation
> implemented of VMA flags defined by the vma_flags_t type.
>
> It is a variadic macro which provides a bitwise-or'd representation of all
> of each individual VMA flag specified.
>
> Note that, while we maintain VM_xxx flags for backwards compatibility until
> the conversion is complete, we define VMA flags of type vma_flag_t using
> VMA_xxx_BIT to avoid confusing the two.
>
> This helper macro therefore can be used thusly:
>
> vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT);
>
> We allow for up to 5 flags to specified at a time which should accommodate
> all current kernel uses of combined VMA flags.
>
How do you allow up to 5 flags? I don't see any such limitation in the code?
> Testing has demonstrated that the compiler optimises this code such that it
> generates the same assembly utilising this macro as it does if the flags
> were specified manually, for instance:
>
> vma_flags_t get_flags(void)
> {
> return mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> }
>
> Generates the same code as:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
>
> vma_flags_clear_all(&flags);
> vma_flag_set(&flags, VMA_READ_BIT);
> vma_flag_set(&flags, VMA_WRITE_BIT);
> vma_flag_set(&flags, VMA_EXEC_BIT);
>
> return flags;
> }
>
> And:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
> unsigned long *bitmap = ACCESS_PRIVATE(&flags, __vma_flags);
>
> *bitmap = 1UL << (__force int)VMA_READ_BIT;
> *bitmap |= 1UL << (__force int)VMA_WRITE_BIT;
> *bitmap |= 1UL << (__force int)VMA_EXEC_BIT;
>
> return flags;
> }
>
> That is:
>
> get_flags:
> movl $7, %eax
> ret
>
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply
* Re: [PATCH v4 15/17] module: Introduce hash-based integrity checking
From: Nicolas Schier @ 2026-02-06 17:12 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Petr Pavlu, Nathan Chancellor, Arnd Bergmann, Luis Chamberlain,
Sami Tolvanen, Daniel Gomez, Paul Moore, James Morris,
Serge E. Hallyn, Jonathan Corbet, Madhavan Srinivasan,
Michael Ellerman, Nicholas Piggin, Naveen N Rao, Mimi Zohar,
Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Daniel Gomez,
Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
Xiu Jianfeng, Fabian Grünbichler, Arnout Engelen,
Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
Sebastian Andrzej Siewior, linux-kbuild, linux-kernel, linux-arch,
linux-modules, linux-security-module, linux-doc, linuxppc-dev,
linux-integrity
In-Reply-To: <28cf8d51-7530-41d5-a47b-cad5ecabd269@t-8ch.de>
On Tue, Feb 03, 2026 at 01:55:05PM +0100, Thomas Weißschuh wrote:
> On 2026-01-30 18:06:20+0100, Petr Pavlu wrote:
> > On 1/13/26 1:28 PM, Thomas Weißschuh wrote:
> > > Normally the .ko module files depend on a fully built vmlinux to be
> > > available for modpost validation and BTF generation. With
> > > CONFIG_MODULE_HASHES, vmlinux now depends on the modules
> > > to build a merkle tree. This introduces a dependency cycle which is
> > > impossible to satisfy. Work around this by building the modules during
> > > link-vmlinux.sh, after vmlinux is complete enough for modpost and BTF
> > > but before the final module hashes are
> >
> > I wonder if this dependency cycle could be resolved by utilizing the
> > split into vmlinux.unstripped and vmlinux that occurred last year.
> >
> > The idea is to create the following ordering: vmlinux.unstripped ->
> > modules -> vmlinux, and to patch in .module_hashes only when building
> > the final vmlinux.
> >
> > This would require the following:
> > * Split scripts/Makefile.vmlinux into two Makefiles, one that builds the
> > current vmlinux.unstripped and the second one that builds the final
> > vmlinux from it.
> > * Modify the top Makefile to recognize vmlinux.unstripped and update the
> > BTF generation rule 'modules: vmlinux' to
> > 'modules: vmlinux.unstripped'.
> > * Add the 'vmlinux: modules' ordering in the top Makefile for
> > CONFIG_MODULE_HASHES=y.
> > * Remove the patching of vmlinux.unstripped in scripts/link-vmlinux.sh
> > and instead move it into scripts/Makefile.vmlinux when running objcopy
> > to produce the final vmlinux.
> >
> > I think this approach has two main advantages:
> > * CONFIG_MODULE_HASHES can be made orthogonal to
> > CONFIG_DEBUG_INFO_BTF_MODULES.
> > * All dependencies are expressed at the Makefile level instead of having
> > scripts/link-vmlinux.sh invoke 'make -f Makefile modules'.
> >
> > Below is a rough prototype that applies on top of this series. It is a
> > bit verbose due to the splitting of part of scripts/Makefile.vmlinux
> > into scripts/Makefile.vmlinux_unstripped.
>
> That looks like a feasible alternative. Before adopting it, I'd like to
> hear the preference of the kbuild folks.
After the first run-through, the proposed alternative sounds good.
Unfortunately, I ran out of time for this week. I can give a more
founded reply in a few days.
Kind regards,
Nicolas
> > diff --git a/Makefile b/Makefile
> > index 841772a5a260..19a3beb82fa7 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -1259,7 +1259,7 @@ vmlinux_o: vmlinux.a $(KBUILD_VMLINUX_LIBS)
> > vmlinux.o modules.builtin.modinfo modules.builtin: vmlinux_o
> > @:
> >
> > -PHONY += vmlinux
> > +PHONY += vmlinux.unstripped vmlinux
> > # LDFLAGS_vmlinux in the top Makefile defines linker flags for the top vmlinux,
> > # not for decompressors. LDFLAGS_vmlinux in arch/*/boot/compressed/Makefile is
> > # unrelated; the decompressors just happen to have the same base name,
> > @@ -1270,9 +1270,11 @@ PHONY += vmlinux
> > # https://savannah.gnu.org/bugs/?61463
> > # For Make > 4.4, the following simple code will work:
> > # vmlinux: private export LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > -vmlinux: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > -vmlinux: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
> > -vmlinux: vmlinux.o $(KBUILD_LDS) modpost
> > +vmlinux.unstripped: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > +vmlinux.unstripped: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
> > +vmlinux.unstripped: vmlinux.o $(KBUILD_LDS) modpost
> > + $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux_unstripped
> > +vmlinux: vmlinux.unstripped
> > $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux
>
> Maybe we could keep them together in a single Makefile,
> and instead have different targets in it.
>
> (...)
>
> > @@ -98,70 +44,15 @@ remove-symbols := -w --strip-unneeded-symbol='__mod_device_table__*'
> > # To avoid warnings: "empty loadable segment detected at ..." from GNU objcopy,
> > # it is necessary to remove the PT_LOAD flag from the segment.
> > quiet_cmd_strip_relocs = OBJCOPY $@
> > - cmd_strip_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
> > - $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $@
> > + cmd_script_relocs = $(OBJCOPY) $(patsubst %,--set-section-flags %=noload,$(remove-section-y)) $< $@; \
> > + $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) \
> > + $(remove-symbols) \
> > + $(patch-module-hashes) $@
>
> cmd_script_relocs -> cmd_strip_relocs
>
> (...)
--
Nicolas
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox