* [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope
@ 2026-02-08 23:10 Günther Noack
2026-02-08 23:10 ` [PATCH v4 1/6] lsm: Add LSM hook security_unix_find Günther Noack
` (5 more replies)
0 siblings, 6 replies; 19+ messages in thread
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 [flat|nested] 19+ messages in thread
* [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
2026-02-08 23:10 [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope Günther Noack
@ 2026-02-08 23:10 ` Günther Noack
2026-02-09 17:51 ` Mickaël Salaün
2026-02-08 23:10 ` [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
` (4 subsequent siblings)
5 siblings, 1 reply; 19+ messages in thread
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
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 [flat|nested] 19+ messages in thread
* [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
2026-02-08 23:10 [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope Günther Noack
2026-02-08 23:10 ` [PATCH v4 1/6] lsm: Add LSM hook security_unix_find Günther Noack
@ 2026-02-08 23:10 ` Günther Noack
2026-02-09 10:21 ` Günther Noack
2026-02-08 23:10 ` [PATCH v4 3/6] samples/landlock: Add support for named UNIX domain socket restrictions Günther Noack
` (3 subsequent siblings)
5 siblings, 1 reply; 19+ messages in thread
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
* 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 [flat|nested] 19+ messages in thread
* [PATCH v4 3/6] samples/landlock: Add support for named UNIX domain socket restrictions
2026-02-08 23:10 [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope Günther Noack
2026-02-08 23:10 ` [PATCH v4 1/6] lsm: Add LSM hook security_unix_find Günther Noack
2026-02-08 23:10 ` [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
@ 2026-02-08 23:10 ` Günther Noack
2026-02-08 23:10 ` [PATCH v4 4/6] landlock/selftests: Test " Günther Noack
` (2 subsequent siblings)
5 siblings, 0 replies; 19+ messages in thread
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
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 [flat|nested] 19+ messages in thread
* [PATCH v4 4/6] landlock/selftests: Test named UNIX domain socket restrictions
2026-02-08 23:10 [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope Günther Noack
` (2 preceding siblings ...)
2026-02-08 23:10 ` [PATCH v4 3/6] samples/landlock: Add support for named UNIX domain socket restrictions Günther Noack
@ 2026-02-08 23:10 ` Günther Noack
2026-02-09 17:29 ` Mickaël Salaün
2026-02-08 23:10 ` [PATCH v4 5/6] landlock: Document FS access right for pathname UNIX sockets Günther Noack
2026-02-08 23:10 ` [PATCH v4 6/6] landlock: Document design rationale for scoped access rights Günther Noack
5 siblings, 1 reply; 19+ messages in thread
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
* 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 [flat|nested] 19+ messages in thread
* [PATCH v4 5/6] landlock: Document FS access right for pathname UNIX sockets
2026-02-08 23:10 [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope Günther Noack
` (3 preceding siblings ...)
2026-02-08 23:10 ` [PATCH v4 4/6] landlock/selftests: Test " Günther Noack
@ 2026-02-08 23:10 ` Günther Noack
2026-02-08 23:10 ` [PATCH v4 6/6] landlock: Document design rationale for scoped access rights Günther Noack
5 siblings, 0 replies; 19+ messages in thread
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
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 [flat|nested] 19+ messages in thread
* [PATCH v4 6/6] landlock: Document design rationale for scoped access rights
2026-02-08 23:10 [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope Günther Noack
` (4 preceding siblings ...)
2026-02-08 23:10 ` [PATCH v4 5/6] landlock: Document FS access right for pathname UNIX sockets Günther Noack
@ 2026-02-08 23:10 ` Günther Noack
5 siblings, 0 replies; 19+ messages in thread
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
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 [flat|nested] 19+ messages in thread
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
2026-02-08 23:10 ` [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
@ 2026-02-09 10:21 ` Günther Noack
2026-02-09 13:11 ` Justin Suess
` (2 more replies)
0 siblings, 3 replies; 19+ messages in thread
From: Günther Noack @ 2026-02-09 10:21 UTC (permalink / raw)
To: Günther Noack
Cc: Mickaël Salaün, John Johansen, 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
On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> +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;
FYI: This is a (highly speculative) safeguard, because these three
socket types are the only ones that exist in AF_UNIX (compare unix(7),
2nd paragraph).
In the (highly unlikely) case that someone adds a fourth AF_UNIX
socket type, this means that Landlock will start permitting
connections to these sockets unconditionally.
I am unsure whether the safeguard is useful, or whether we should
rather group that (highly unlikely) future socket type together with
the existing ones. *If you have opinions, I'd be interested.*
The fact that these are the only existing AF_UNIX socket types is also
the reason why it does not matter that we are now (in v4) taking the
type value from the server-side sk instead of the client socket. The
check will either way always pass as long as only these three types
are the only ones.
For now (and probably for another few decades :)), as long as these
are the only AF_UNIX types, it does not make a difference though
whether the check is there or not.
—Günther
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
2026-02-09 10:21 ` Günther Noack
@ 2026-02-09 13:11 ` Justin Suess
2026-02-10 23:04 ` Günther Noack
2026-02-09 17:28 ` Mickaël Salaün
2026-02-09 18:03 ` Mickaël Salaün
2 siblings, 1 reply; 19+ messages in thread
From: Justin Suess @ 2026-02-09 13:11 UTC (permalink / raw)
To: Günther Noack, Günther Noack
Cc: Mickaël Salaün, John Johansen, Tingmao Wang, Jann Horn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Tahera Fahimi
On 2/9/26 05:21, Günther Noack wrote:
> On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
>> +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;
if (unlikely(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;
if (unlikely(type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET))
return 0;
> FYI: This is a (highly speculative) safeguard, because these three
> socket types are the only ones that exist in AF_UNIX (compare unix(7),
> 2nd paragraph).
>
> In the (highly unlikely) case that someone adds a fourth AF_UNIX
> socket type, this means that Landlock will start permitting
> connections to these sockets unconditionally.
>
> I am unsure whether the safeguard is useful, or whether we should
> rather group that (highly unlikely) future socket type together with
> the existing ones. *If you have opinions, I'd be interested.*
In that case, a new access right could be added for that new socket type.
So we should only handle the ones we expect for now, and reserve the option for future rights
to expand the capability.
>
> The fact that these are the only existing AF_UNIX socket types is also
> the reason why it does not matter that we are now (in v4) taking the
> type value from the server-side sk instead of the client socket. The
> check will either way always pass as long as only these three types
> are the only ones.
Last time a new socket type for UDS (seqpacket) was added was 2.6.4.
UDS are also part of POSIX, so they're pretty standardized and not exactly likely to change.
>
> For now (and probably for another few decades :)), as long as these
> are the only AF_UNIX types, it does not make a difference though
> whether the check is there or not.
I think this is the correct choice.
>
> —Günther
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
2026-02-09 10:21 ` Günther Noack
2026-02-09 13:11 ` Justin Suess
@ 2026-02-09 17:28 ` Mickaël Salaün
2026-02-10 23:09 ` Günther Noack
2026-02-09 18:03 ` Mickaël Salaün
2 siblings, 1 reply; 19+ messages in thread
From: Mickaël Salaün @ 2026-02-09 17:28 UTC (permalink / raw)
To: Günther Noack
Cc: Günther Noack, John Johansen, 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
On Mon, Feb 09, 2026 at 11:21:57AM +0100, Günther Noack wrote:
> On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> > +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;
>
> FYI: This is a (highly speculative) safeguard, because these three
> socket types are the only ones that exist in AF_UNIX (compare unix(7),
> 2nd paragraph).
>
> In the (highly unlikely) case that someone adds a fourth AF_UNIX
> socket type, this means that Landlock will start permitting
> connections to these sockets unconditionally.
>
> I am unsure whether the safeguard is useful, or whether we should
> rather group that (highly unlikely) future socket type together with
> the existing ones. *If you have opinions, I'd be interested.*
>
> The fact that these are the only existing AF_UNIX socket types is also
> the reason why it does not matter that we are now (in v4) taking the
> type value from the server-side sk instead of the client socket. The
> check will either way always pass as long as only these three types
> are the only ones.
>
> For now (and probably for another few decades :)), as long as these
> are the only AF_UNIX types, it does not make a difference though
> whether the check is there or not.
You can remove these type checks. We're building Landlock access
control wrt to the (moving) current state of Linux, and the goal is to
cover most/useful access types that currently make sense. Once access
type is implemented, it should handle (by default) future features
related to the kernel object to make sure a sandbox is well covered.
This LANDLOCK_ACCESS_FS_RESOLVE_UNIX right is really about UNIX sockets
that can be resolved through the filesystem, so this should handle
current and potential future UNIX sockets as well.
If a new named UNIX socket type is created, Landlock should handle that
with this access right, unless there is a specific semantic (e.g.
coredump), in which case we'll update the access right, and potentially
add a new one if it makes sense.
I was thinking about calling WARN_ON_ONCE() but this is not worth it.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 4/6] landlock/selftests: Test named UNIX domain socket restrictions
2026-02-08 23:10 ` [PATCH v4 4/6] landlock/selftests: Test " Günther Noack
@ 2026-02-09 17:29 ` Mickaël Salaün
2026-02-15 3:01 ` Tingmao Wang
0 siblings, 1 reply; 19+ messages in thread
From: Mickaël Salaün @ 2026-02-09 17:29 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, 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
On Mon, Feb 09, 2026 at 12:10:14AM +0100, Günther Noack wrote:
> * 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}}
It would improve test clarity to follow the same approach as Tingmao to
check the scope, especially to use the scoped_base_variant.h:
https://lore.kernel.org/all/88de5bed60b06ba97088d87803f7bb3dbcc9a808.1767115163.git.m@maowtm.org/
Even if there is no more explicit scoped flag anymore, this test suite
is still relevant.
The fs_test.c part would then mostly check the
LANDLOCK_ACCESS_FS_RESOLVE_UNIX rules/exceptions.
>
> 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 [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
2026-02-08 23:10 ` [PATCH v4 1/6] lsm: Add LSM hook security_unix_find Günther Noack
@ 2026-02-09 17:51 ` Mickaël Salaün
2026-02-09 18:33 ` Tingmao Wang
2026-02-10 13:02 ` Justin Suess
0 siblings, 2 replies; 19+ messages in thread
From: Mickaël Salaün @ 2026-02-09 17:51 UTC (permalink / raw)
To: Günther Noack
Cc: John Johansen, Paul Moore, James Morris, Serge E . Hallyn,
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
On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
> 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;
We don't see it in this patch but err is already set to -ECONNREFUSED.
This line might be confusing, and unrelated to the goal of this patch,
so we should remove it.
> 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.
This comment can be alligned with 80 columns.
> + */
> + err = security_unix_find(&path, sk, flags);
This hook makes sense and is quite generic.
> + 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)
> +/*
This should be a docstring like other hooks: /**
> + * 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 [flat|nested] 19+ messages in thread
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
2026-02-09 10:21 ` Günther Noack
2026-02-09 13:11 ` Justin Suess
2026-02-09 17:28 ` Mickaël Salaün
@ 2026-02-09 18:03 ` Mickaël Salaün
2 siblings, 0 replies; 19+ messages in thread
From: Mickaël Salaün @ 2026-02-09 18:03 UTC (permalink / raw)
To: Günther Noack
Cc: Günther Noack, John Johansen, 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
On Mon, Feb 09, 2026 at 11:21:57AM +0100, Günther Noack wrote:
> On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> > +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;
We should test this case too.
tools/testing/selftests/coredump/coredump_socket_* should help.
> > +
> > + /* Only stream, dgram and seqpacket sockets are restricted. */
> > + if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
> > + return 0;
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
2026-02-09 17:51 ` Mickaël Salaün
@ 2026-02-09 18:33 ` Tingmao Wang
2026-02-09 19:53 ` Tingmao Wang
2026-02-10 13:02 ` Justin Suess
1 sibling, 1 reply; 19+ messages in thread
From: Tingmao Wang @ 2026-02-09 18:33 UTC (permalink / raw)
To: Mickaël Salaün, Justin Suess, Günther Noack
Cc: John Johansen, Paul Moore, James Morris, Serge E . Hallyn,
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
On 2/9/26 17:51, Mickaël Salaün wrote:
> On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
>> [...]
>> 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;
>
> We don't see it in this patch but err is already set to -ECONNREFUSED.
> This line might be confusing, and unrelated to the goal of this patch,
> so we should remove it.
I will confess that in a side conversation with Justin previously I
suggested that for blocks like these it might be better to always assign
to err, and let the compiler optimize it away, so that when this block is
moved there is less chances of mistake. (This was relevant in the
previous context where a move of this hook caused err to be reset,
resulting in a NULL deference from syzbot)
But of course if the convention in this file is to not do it, or if I have
missed some reason against doing this, then that's also fine (even though,
IMHO, personally I think this is better).
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
2026-02-09 18:33 ` Tingmao Wang
@ 2026-02-09 19:53 ` Tingmao Wang
0 siblings, 0 replies; 19+ messages in thread
From: Tingmao Wang @ 2026-02-09 19:53 UTC (permalink / raw)
To: Mickaël Salaün, Justin Suess, Günther Noack
Cc: John Johansen, Paul Moore, James Morris, Serge E . Hallyn,
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
On 2/9/26 18:33, Tingmao Wang wrote:
> On 2/9/26 17:51, Mickaël Salaün wrote:
>> On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
>>> [...]
>>> 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;
>>
>> We don't see it in this patch but err is already set to -ECONNREFUSED.
>> This line might be confusing, and unrelated to the goal of this patch,
>> so we should remove it.
>
> I will confess that in a side conversation with Justin previously I
> suggested that for blocks like these it might be better to always assign
> to err, and let the compiler optimize it away, so that when this block is
> moved there is less chances of mistake. (This was relevant in the
> previous context where a move of this hook caused err to be reset,
> resulting in a NULL deference from syzbot)
>
> But of course if the convention in this file is to not do it, or if I have
> missed some reason against doing this, then that's also fine (even though,
> IMHO, personally I think this is better).
>
Actually, looking at this more carefully, Mickaël is right that this
single line addition doesn't have anything to do with the patch itself
(unlike in the diff in the other thread [1] where it is part of a moved
block), so I guess it makes sense to not add this in this patch.
Apologies for any conversation derailment caused here :)
[1]: https://lore.kernel.org/all/e6b6b069-384c-4c45-a56b-fa54b26bc72a@maowtm.org/
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 1/6] lsm: Add LSM hook security_unix_find
2026-02-09 17:51 ` Mickaël Salaün
2026-02-09 18:33 ` Tingmao Wang
@ 2026-02-10 13:02 ` Justin Suess
1 sibling, 0 replies; 19+ messages in thread
From: Justin Suess @ 2026-02-10 13:02 UTC (permalink / raw)
To: mic
Cc: brauner, demiobenour, fahimitahera, gnoack3000, hi, horms,
ivanov.mikhail1, jannh, jmorris, john.johansen,
konstantin.meskhidze, linux-security-module, m, matthieu, netdev,
paul, samasth.norway.ananda, serge, utilityemal77, viro
> On Mon, Feb 09, 2026 at 12:10:11AM +0100, Günther Noack wrote:
> > 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;
>
> We don't see it in this patch but err is already set to -ECONNREFUSED.
> This line might be confusing, and unrelated to the goal of this patch,
> so we should remove it.
Done. I debated keeping it, but it seems more appropriate to follow the
convention. Thanks for the catch.
>
>
> > 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.
>
> This comment can be alligned with 80 columns.
Done.
> > + */
> > + err = security_unix_find(&path, sk, flags);
>
> This hook makes sense and is quite generic.
Indeed, I suspect it will be useful for other path-based LSM.
> > + 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)
> > +/*
>
> This should be a docstring like other hooks: /**
Done.
>
> > + * 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
> >
> >
>
Below follows revised lsm hook patch based on feedback.
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..369812b79dd8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1230,6 +1230,14 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
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..eaf8f8fdf0c2 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
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
2026-02-09 13:11 ` Justin Suess
@ 2026-02-10 23:04 ` Günther Noack
0 siblings, 0 replies; 19+ messages in thread
From: Günther Noack @ 2026-02-10 23:04 UTC (permalink / raw)
To: Justin Suess
Cc: Günther Noack, Mickaël Salaün, John Johansen,
Tingmao Wang, Jann Horn, linux-security-module,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross,
Tahera Fahimi
On Mon, Feb 09, 2026 at 08:11:18AM -0500, Justin Suess wrote:
> On 2/9/26 05:21, Günther Noack wrote:
> > On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> >> + /* Lookup for the purpose of saving coredumps is OK. */
> >> + if (flags & SOCK_COREDUMP)
> >> + return 0;
> if (unlikely(flags & SOCK_COREDUMP))
> return 0;
Done.
> >> +
> >> + /* Only stream, dgram and seqpacket sockets are restricted. */
> >> + if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET)
> >> + return 0;
> if (unlikely(type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET))
> return 0;
Not applicable any more, as I dropped the check per Mickaël's review
in the adjacent mail (I do not think it makes a big difference either
way, TBH.)
–Günther
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path
2026-02-09 17:28 ` Mickaël Salaün
@ 2026-02-10 23:09 ` Günther Noack
0 siblings, 0 replies; 19+ messages in thread
From: Günther Noack @ 2026-02-10 23:09 UTC (permalink / raw)
To: Mickaël Salaün
Cc: Günther Noack, John Johansen, 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
On Mon, Feb 09, 2026 at 06:28:24PM +0100, Mickaël Salaün wrote:
> On Mon, Feb 09, 2026 at 11:21:57AM +0100, Günther Noack wrote:
> > On Mon, Feb 09, 2026 at 12:10:12AM +0100, Günther Noack wrote:
> > > +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;
> >
> > [...]
>
> You can remove these type checks. We're building Landlock access
> control wrt to the (moving) current state of Linux, and the goal is to
> cover most/useful access types that currently make sense. Once access
> type is implemented, it should handle (by default) future features
> related to the kernel object to make sure a sandbox is well covered.
> This LANDLOCK_ACCESS_FS_RESOLVE_UNIX right is really about UNIX sockets
> that can be resolved through the filesystem, so this should handle
> current and potential future UNIX sockets as well.
>
> If a new named UNIX socket type is created, Landlock should handle that
> with this access right, unless there is a specific semantic (e.g.
> coredump), in which case we'll update the access right, and potentially
> add a new one if it makes sense.
>
> I was thinking about calling WARN_ON_ONCE() but this is not worth it.
Sounds good, removed the check for the next version.
The possibility of a new UNIX socket type seems anyway pretty
theoretical, and even if an additional type were added, it's not
entirely unthinkable that we would actually want to have it covered
under the same access right.
–Günther
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 4/6] landlock/selftests: Test named UNIX domain socket restrictions
2026-02-09 17:29 ` Mickaël Salaün
@ 2026-02-15 3:01 ` Tingmao Wang
0 siblings, 0 replies; 19+ messages in thread
From: Tingmao Wang @ 2026-02-15 3:01 UTC (permalink / raw)
To: Günther Noack
Cc: Mickaël Salaün, Justin Suess, linux-security-module
On 2/9/26 17:29, Mickaël Salaün wrote:
> On Mon, Feb 09, 2026 at 12:10:14AM +0100, Günther Noack wrote:
>> * 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}}
>
> It would improve test clarity to follow the same approach as Tingmao to
> check the scope, especially to use the scoped_base_variant.h:
> https://lore.kernel.org/all/88de5bed60b06ba97088d87803f7bb3dbcc9a808.1767115163.git.m@maowtm.org/
> Even if there is no more explicit scoped flag anymore, this test suite
> is still relevant.
>
> The fs_test.c part would then mostly check the
> LANDLOCK_ACCESS_FS_RESOLVE_UNIX rules/exceptions.
>
Günther, if you have not already started working on this but agrees with
the suggestion here, I'm happy to take a stab at rebasing the relevant
selftests patches in the scope series to test this new series.
Kind regards,
Tingmao
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-02-15 3:01 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-08 23:10 [PATCH v4 0/6] landlock: UNIX connect() control by pathname and scope Günther Noack
2026-02-08 23:10 ` [PATCH v4 1/6] lsm: Add LSM hook security_unix_find Günther Noack
2026-02-09 17:51 ` Mickaël Salaün
2026-02-09 18:33 ` Tingmao Wang
2026-02-09 19:53 ` Tingmao Wang
2026-02-10 13:02 ` Justin Suess
2026-02-08 23:10 ` [PATCH v4 2/6] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
2026-02-09 10:21 ` Günther Noack
2026-02-09 13:11 ` Justin Suess
2026-02-10 23:04 ` Günther Noack
2026-02-09 17:28 ` Mickaël Salaün
2026-02-10 23:09 ` Günther Noack
2026-02-09 18:03 ` Mickaël Salaün
2026-02-08 23:10 ` [PATCH v4 3/6] samples/landlock: Add support for named UNIX domain socket restrictions Günther Noack
2026-02-08 23:10 ` [PATCH v4 4/6] landlock/selftests: Test " Günther Noack
2026-02-09 17:29 ` Mickaël Salaün
2026-02-15 3:01 ` Tingmao Wang
2026-02-08 23:10 ` [PATCH v4 5/6] landlock: Document FS access right for pathname UNIX sockets Günther Noack
2026-02-08 23:10 ` [PATCH v4 6/6] landlock: Document design rationale for scoped access rights Günther Noack
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox