* [PATCH v3 0/5] landlock: Pathname-based UNIX connect() control
@ 2026-01-19 20:34 Günther Noack
2026-01-19 20:34 ` [PATCH v3 1/5] lsm: Add hook security_unix_find Günther Noack
0 siblings, 1 reply; 5+ messages in thread
From: Günther Noack @ 2026-01-19 20:34 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.
== 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].
The most comprehensive discussion happened in a discussion started in
the V2 review by Christian Brauner [10], where 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.
=== 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 my reply to this patch set [3], I have discussed the differences
between these two approaches. On the related discussions on Github
[4] and [5], there was consensus that the scope-based control is
complimentary to the filesystem based control, but does not replace
it. Mickael's opening remark on [5] says:
> This scoping would be complementary to #36 which would mainly be
> about allowing a sandboxed process to connect to a more privileged
> service (identified with a path).
== 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] and Tingmao Wang has
sent the patch set for the scoped access control for pathname Unix
sockets [2].
Justin Suess has sent the patch for the LSM hook in [8] and
subsequently through this patch set.
Ryan Sullivan has started on an initial implementation and has brought
up relevant discussion points on the Github issue at [4] that lead to
the current approach.
Christian Brauner and Paul Moore have contributed to the design of the
new LSM hook, discussing the tradeoffs in [10].
[1] https://lore.kernel.org/landlock/515ff0f4-2ab3-46de-8d1e-5c66a93c6ede@gmail.com/
[2] Tingmao Wang's "Implemnet 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/
---
== 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/
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 (4):
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
Justin Suess (1):
lsm: Add hook security_unix_find
Documentation/userspace-api/landlock.rst | 14 +-
include/linux/lsm_hook_defs.h | 4 +
include/linux/security.h | 11 +
include/uapi/linux/landlock.h | 5 +
net/unix/af_unix.c | 9 +
samples/landlock/sandboxer.c | 13 +-
security/landlock/access.h | 2 +-
security/landlock/audit.c | 1 +
security/landlock/fs.c | 18 +-
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 | 223 +++++++++++++++++--
14 files changed, 299 insertions(+), 27 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v3 1/5] lsm: Add hook security_unix_find 2026-01-19 20:34 [PATCH v3 0/5] landlock: Pathname-based UNIX connect() control Günther Noack @ 2026-01-19 20:34 ` Günther Noack 2026-02-04 10:25 ` Günther Noack 0 siblings, 1 reply; 5+ messages in thread From: Günther Noack @ 2026-01-19 20:34 UTC (permalink / raw) To: Mickaël Salaün, John Johansen, Paul Moore, James Morris, Serge E . Hallyn 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, Simon Horman, netdev, Alexander Viro, Christian Brauner From: Justin Suess <utilityemal77@gmail.com> Add an LSM hook security_unix_find. This hook is called to check the path of a named unix socket before a connection is initiated. 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. Why existing hooks are unsuitable: (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> Signed-off-by: Justin Suess <utilityemal77@gmail.com> --- include/linux/lsm_hook_defs.h | 4 ++++ include/linux/security.h | 11 +++++++++++ net/unix/af_unix.c | 9 +++++++++ security/security.c | 20 ++++++++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 8c42b4bde09c..84c1fac3ada6 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -317,6 +317,10 @@ 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, int type, 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..cdcd340b085c 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, int type, int flags); + +#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */ +static inline int security_unix_find(const struct path *path, int type, 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..227467236930 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1226,6 +1226,15 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len, if (!S_ISSOCK(inode->i_mode)) 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, type, flags); + if (err) + goto path_put; + + err = -ECONNREFUSED; sk = unix_find_socket_byinode(inode); if (!sk) goto path_put; diff --git a/security/security.c b/security/security.c index 31a688650601..df4e3f99de7d 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 + * @type: type of the socket + * @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, int type, int flags) +{ + return call_int_hook(unix_find, path, type, 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] 5+ messages in thread
* Re: [PATCH v3 1/5] lsm: Add hook security_unix_find 2026-01-19 20:34 ` [PATCH v3 1/5] lsm: Add hook security_unix_find Günther Noack @ 2026-02-04 10:25 ` Günther Noack 2026-02-05 10:36 ` Mickaël Salaün 2026-02-09 17:09 ` Paul Moore 0 siblings, 2 replies; 5+ messages in thread From: Günther Noack @ 2026-02-04 10:25 UTC (permalink / raw) To: Günther Noack, Paul Moore, John Johansen, Tingmao Wang Cc: Mickaël Salaün, James Morris, Serge E . Hallyn, 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 Hello! John: Friendly ping; as Paul said in [1], we would appreciate a look from the AppArmor side whether this path-based LSM hook makes sense for you. Everyone: In [2], we are currently discussing how the UNIX restriction feature would work in the bigger scheme in Landlock, and the current plan is that long-term we would like to support semantics where a UNIX connection attempt is allowed if EITHER: (a) the path is allow-listed in the policy, OR (b) the server side we connect to is part of the same Landlock sandbox ("domain") With the currently proposed hook, (a) can be checked in the security_unix_find() hook, and (b) can be checked in the security_hook_socket_connect() hook. Unfortunately, it also would mean that if the (a) check fails, we would have to store that information on the side (struct sock LSM blob?), return 0 from (a) and then later use that information in hook (b), so that we can check whether maybe the second possible condition is met. Q: The passing of information across multiple LSM hooks is slightly more complicated than I had hoped; is this an approach that is recommended? Therefore, in [2], Tingmao is suggesting that we change the security_unix_find() hook and pass the "other" struct sock instead of the type. There is obviously a balance between hooks that are very generic and usable across multiple LSMs and hooks that are convenient to use for every LSM. Paul: You have previously said that you would like hooks to be generic and ideally reflect the arguments of the same function that they are called from [3]. Q: Would it be acceptable to change the hook arguments, if we can then avoid passing additional data between hooks through that side-storage? You can see Tingmao's proposal for that in [2]. TL;DR: It moves the call to security_unix_find() just after the place where the sk variable ("other"-side socket) is looked up and then calls the hook with the sk as argument instead of with the type. That way, we can do both check (a) and (b) from above in the same hook and do not need to store data on the side. Is that an acceptable trade-off for the LSM interface? Thanks, —Günther [1] https://lore.kernel.org/all/CAHC9VhQZ_J9316Us0squV_f-MjYXPcex34BnJ14vEBxS9Jyjbg@mail.gmail.com/ [2] https://lore.kernel.org/all/e6b6b069-384c-4c45-a56b-fa54b26bc72a@maowtm.org/ [3] https://lore.kernel.org/all/CAHC9VhQ234xihpndTs4e5ToNJ3tGCsP7AVtXuz8GajG-_jn3Ow@mail.gmail.com/ ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 1/5] lsm: Add hook security_unix_find 2026-02-04 10:25 ` Günther Noack @ 2026-02-05 10:36 ` Mickaël Salaün 2026-02-09 17:09 ` Paul Moore 1 sibling, 0 replies; 5+ messages in thread From: Mickaël Salaün @ 2026-02-05 10:36 UTC (permalink / raw) To: Günther Noack Cc: Günther Noack, Paul Moore, John Johansen, Tingmao Wang, James Morris, Serge E . Hallyn, 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 Wed, Feb 04, 2026 at 11:25:33AM +0100, Günther Noack wrote: > Hello! > > > John: > > Friendly ping; as Paul said in [1], we would appreciate a look from > the AppArmor side whether this path-based LSM hook makes sense for > you. FYI, we plan to merge this patch series with another one where this new LSM hook will be used as Günther explained: > > > Everyone: > > In [2], we are currently discussing how the UNIX restriction feature > would work in the bigger scheme in Landlock, and the current plan is > that long-term we would like to support semantics where a UNIX > connection attempt is allowed if EITHER: > > (a) the path is allow-listed in the policy, OR > (b) the server side we connect to is part of the same Landlock > sandbox ("domain") > > > With the currently proposed hook, (a) can be checked in the > security_unix_find() hook, and (b) can be checked in the > security_hook_socket_connect() hook. Unfortunately, it also would > mean that if the (a) check fails, we would have to store that > information on the side (struct sock LSM blob?), return 0 from (a) and > then later use that information in hook (b), so that we can check > whether maybe the second possible condition is met. > > Q: The passing of information across multiple LSM hooks is slightly > more complicated than I had hoped; is this an approach that is > recommended? > > Therefore, in [2], Tingmao is suggesting that we change the > security_unix_find() hook and pass the "other" struct sock instead of > the type. This new approach is much more generic and should please any LSM wishing to use it. > > There is obviously a balance between hooks that are very generic and > usable across multiple LSMs and hooks that are convenient to use for > every LSM. > > Paul: > > You have previously said that you would like hooks to be generic and > ideally reflect the arguments of the same function that they are > called from [3]. > > Q: Would it be acceptable to change the hook arguments, if we can then > avoid passing additional data between hooks through that side-storage? > You can see Tingmao's proposal for that in [2]. TL;DR: It moves the > call to security_unix_find() just after the place where the sk > variable ("other"-side socket) is looked up and then calls the hook > with the sk as argument instead of with the type. That way, we can do > both check (a) and (b) from above in the same hook and do not need to > store data on the side. Is that an acceptable trade-off for the LSM > interface? I think it's a good interface because it let any LSM check both the resolved path and the resolved socket (without race condition), which makes sense and align with most other hooks. > > Thanks, > —Günther > > [1] https://lore.kernel.org/all/CAHC9VhQZ_J9316Us0squV_f-MjYXPcex34BnJ14vEBxS9Jyjbg@mail.gmail.com/ > [2] https://lore.kernel.org/all/e6b6b069-384c-4c45-a56b-fa54b26bc72a@maowtm.org/ > [3] https://lore.kernel.org/all/CAHC9VhQ234xihpndTs4e5ToNJ3tGCsP7AVtXuz8GajG-_jn3Ow@mail.gmail.com/ > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3 1/5] lsm: Add hook security_unix_find 2026-02-04 10:25 ` Günther Noack 2026-02-05 10:36 ` Mickaël Salaün @ 2026-02-09 17:09 ` Paul Moore 1 sibling, 0 replies; 5+ messages in thread From: Paul Moore @ 2026-02-09 17:09 UTC (permalink / raw) To: Günther Noack Cc: Günther Noack, John Johansen, Tingmao Wang, Mickaël Salaün, James Morris, Serge E . Hallyn, 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 Wed, Feb 4, 2026 at 5:25 AM Günther Noack <gnoack@google.com> wrote: > > Paul: > > You have previously said that you would like hooks to be generic and > ideally reflect the arguments of the same function that they are > called from [3]. To clarify, I didn't say that it is generally ideal for the LSM hook to reflect the arguments of the calling function; while that might be a good starting point, we have plenty of examples where that is not desirable. In this particular case I said it seems like it would be a good idea to pass the "type" and "flags" parameters from the caller to the LSM hook. > Q: Would it be acceptable to change the hook arguments, if we can then > avoid passing additional data between hooks through that side-storage? If you're passing the sock, I think we can skip passing the type, however, I could envision someone wanting the path in addition to just the sock, but let's wait to hear back from the AppArmor folks. -- paul-moore.com ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-02-09 17:09 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-19 20:34 [PATCH v3 0/5] landlock: Pathname-based UNIX connect() control Günther Noack 2026-01-19 20:34 ` [PATCH v3 1/5] lsm: Add hook security_unix_find Günther Noack 2026-02-04 10:25 ` Günther Noack 2026-02-05 10:36 ` Mickaël Salaün 2026-02-09 17:09 ` Paul Moore
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox