public inbox for linux-security-module@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control
@ 2026-01-10 14:32 Günther Noack
  2026-01-10 14:32 ` [PATCH v2 1/5] lsm: Add hook unix_path_connect Günther Noack
                   ` (5 more replies)
  0 siblings, 6 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-10 14:32 UTC (permalink / raw)
  To: Mickaël Salaün, 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 a file system access right for each
type of UNIX domain socket:

 * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM
 * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM
 * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET

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 can come as a surprise for users (e.g. in
[1]) and it can be used to escape a sandbox when a Unix service offers
command execution (some scenarios were listed by Tingmao Wang in [2]).

The original feature request is at [4].

## Alternatives and Related Work

### Alternative: Use existing LSM hooks

The existing hooks security_unix_stream_connect(),
security_unix_may_send() and security_socket_connect() do not give
access to the resolved file system path.

Resolving the file system path again within Landlock would in my
understanding produce a TOCTOU race, so making the decision based on
the struct sockaddr_un contents is not an option.

It is tempting to use the struct path that the listening socket is
bound to, which can be acquired through the existing hooks.
Unfortunately, the listening socket may have been bound from within a
different namespace, and it is therefore a path that can not actually
be referenced by the sandboxed program at the time of constructing the
Landlock policy.  (More details are on the Github issue at [6] and on
the LKML at [9]).

### 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 file system 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).

## Open questions in V2

Seeking feedback on:

- Feedback on the LSM hook name would be appreciated. We realize that
  not all invocations of the LSM hook are related to connect(2) as the
  name suggests, but some also happen during sendmsg(2).
- Feedback on the structuring of the Landlock access rights, splitting
  them up by socket type.  (Also naming; they are now consistently
  called "RESOLVE", but could be named "CONNECT" in the stream and
  seqpacket cases?)

## 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].

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.

[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/

---

## Older versions of this patch set

V1: https://lore.kernel.org/all/20260101134102.25938-1-gnoack3000@gmail.com/

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 rights for pathname UNIX sockets

Justin Suess (1):
  lsm: Add hook unix_path_connect

 Documentation/userspace-api/landlock.rst     |  25 ++-
 include/linux/lsm_hook_defs.h                |   4 +
 include/linux/security.h                     |  11 +
 include/uapi/linux/landlock.h                |  10 +
 net/unix/af_unix.c                           |   9 +
 samples/landlock/sandboxer.c                 |  18 +-
 security/landlock/access.h                   |   2 +-
 security/landlock/audit.c                    |   6 +
 security/landlock/fs.c                       |  34 ++-
 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   | 225 +++++++++++++++++--
 14 files changed, 344 insertions(+), 26 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-10 14:32 [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Günther Noack
@ 2026-01-10 14:32 ` Günther Noack
  2026-01-10 16:45   ` Justin Suess
  2026-01-13  9:34   ` Christian Brauner
  2026-01-10 14:32 ` [PATCH v2 2/5] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-10 14:32 UTC (permalink / raw)
  To: Mickaël Salaün, 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>

Adds an LSM hook unix_path_connect.

This hook is called to check the path of a named unix socket before a
connection is initiated.

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..1dee5d8d52d2 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_path_connect, 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..382612af27a6 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_path_connect(const struct path *path, int type, int flags);
+
+#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+static inline int security_unix_path_connect(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 55cdebfa0da0..3aabe2d489ae 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_path_connect(&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..0cee3502db83 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_path_connect() - 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_path_connect(const struct path *path, int type, int flags)
+{
+	return call_int_hook(unix_path_connect, path, type, flags);
+}
+EXPORT_SYMBOL(security_unix_path_connect);
+
+#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] 23+ messages in thread

* [PATCH v2 2/5] landlock: Control pathname UNIX domain socket resolution by path
  2026-01-10 14:32 [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Günther Noack
  2026-01-10 14:32 ` [PATCH v2 1/5] lsm: Add hook unix_path_connect Günther Noack
@ 2026-01-10 14:32 ` Günther Noack
  2026-01-12 15:38   ` Justin Suess
  2026-01-10 14:33 ` [PATCH v2 3/5] samples/landlock: Add support for named UNIX domain socket restrictions Günther Noack
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: Günther Noack @ 2026-01-10 14:32 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: Günther Noack, Justin Suess, Jann Horn,
	linux-security-module, Tingmao Wang, Samasth Norway Ananda,
	Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
	Demi Marie Obenour, Alyssa Ross, Tahera Fahimi

* Add new access rights which control the look up operations for named
  UNIX domain sockets.  The resolution happens during connect() and
  sendmsg() (depending on socket type).
  * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM
  * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM
  * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET
* 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.

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                   |  2 +-
 security/landlock/audit.c                    |  6 ++++
 security/landlock/fs.c                       | 34 +++++++++++++++++++-
 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   |  7 ++--
 8 files changed, 58 insertions(+), 7 deletions(-)

diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index f030adc462ee..455edc241c12 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -216,6 +216,13 @@ struct landlock_net_port_attr {
  *   :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with
  *   ``O_TRUNC``.  This access right is available since the third version of the
  *   Landlock ABI.
+ * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM: Connect to named
+ *   :manpage:`unix(7)` ``SOCK_STREAM`` sockets.
+ * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM: Send messages to named
+ *   :manpage:`unix(7)` ``SOCK_DGRAM`` sockets or connect to them using
+ *   :manpage:`connect(2)`.
+ * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET: Connect to named
+ *   :manpage:`unix(7)` ``SOCK_SEQPACKET`` sockets.
  *
  * 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
@@ -321,6 +328,9 @@ 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_STREAM		(1ULL << 16)
+#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM		(1ULL << 17)
+#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET	(1ULL << 18)
 /* clang-format on */
 
 /**
diff --git a/security/landlock/access.h b/security/landlock/access.h
index 7961c6630a2d..c7784922be3c 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);
diff --git a/security/landlock/audit.c b/security/landlock/audit.c
index e899995f1fd5..0645304e0375 100644
--- a/security/landlock/audit.c
+++ b/security/landlock/audit.c
@@ -37,6 +37,12 @@ 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_STREAM)] =
+		"fs.resolve_unix_stream",
+	[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM)] =
+		"fs.resolve_unix_dgram",
+	[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)] =
+		"fs.resolve_unix_seqpacket",
 };
 
 static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index 8205673c8b1c..94f5fc7ee9fd 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -9,6 +9,7 @@
  * Copyright © 2023-2024 Google LLC
  */
 
+#include "linux/net.h"
 #include <asm/ioctls.h>
 #include <kunit/test.h>
 #include <linux/atomic.h>
@@ -314,7 +315,10 @@ 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_STREAM | \
+	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM | \
+	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)
 /* clang-format on */
 
 /*
@@ -1588,6 +1592,33 @@ static int hook_path_truncate(const struct path *const path)
 	return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
 }
 
+static int hook_unix_path_connect(const struct path *const path, int type,
+				  int flags)
+{
+	access_mask_t access_request = 0;
+
+	/* Lookup for the purpose of saving coredumps is OK. */
+	if (flags & SOCK_COREDUMP)
+		return 0;
+
+	switch (type) {
+	case SOCK_STREAM:
+		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM;
+		break;
+	case SOCK_DGRAM:
+		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM;
+		break;
+	case SOCK_SEQPACKET:
+		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET;
+		break;
+	}
+
+	if (!access_request)
+		return 0;
+
+	return current_check_access_path(path, access_request);
+}
+
 /* File hooks */
 
 /**
@@ -1872,6 +1903,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_path_connect, hook_unix_path_connect),
 
 	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 65b5ff051674..1f6f864afec2 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_SEQPACKET
 #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 0116e9f93ffe..66fd196be85a 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -161,7 +161,7 @@ static const struct file_operations ruleset_fops = {
  * Documentation/userspace-api/landlock.rst should be updated to reflect the
  * UAPI change.
  */
-const int landlock_abi_version = 7;
+const int landlock_abi_version = 8;
 
 /**
  * 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 7b69002239d7..f4b1a275d8d9 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(7, landlock_create_ruleset(NULL, 0,
+	ASSERT_EQ(8, 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..0cbde65e032a 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -575,9 +575,12 @@ 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_STREAM | \
+	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM | \
+	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)
 
-#define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV
+#define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET
 
 #define ACCESS_ALL ( \
 	ACCESS_FILE | \
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 3/5] samples/landlock: Add support for named UNIX domain socket restrictions
  2026-01-10 14:32 [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Günther Noack
  2026-01-10 14:32 ` [PATCH v2 1/5] lsm: Add hook unix_path_connect Günther Noack
  2026-01-10 14:32 ` [PATCH v2 2/5] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
@ 2026-01-10 14:33 ` Günther Noack
  2026-01-11  9:50   ` Günther Noack
  2026-01-10 14:33 ` [PATCH v2 4/5] landlock/selftests: Test " Günther Noack
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 23+ messages in thread
From: Günther Noack @ 2026-01-10 14:33 UTC (permalink / raw)
  To: Mickaël Salaün
  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 rights for UNIX domain socket lookups are 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 | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index e7af02f98208..f7e73ba8910c 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -295,11 +295,14 @@ 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_STREAM | \
+	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM | \
+	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)
 
 /* clang-format on */
 
-#define LANDLOCK_ABI_LAST 7
+#define LANDLOCK_ABI_LAST 8
 
 #define XSTR(s) #s
 #define STR(s) XSTR(s)
@@ -444,6 +447,17 @@ 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:
+		/*
+		 * Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM,
+		 * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM and
+		 * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET for ABI < 8
+		 */
+		ruleset_attr.handled_access_fs &=
+			~(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM |
+			  LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM |
+			  LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET);
+		__attribute__((fallthrough));
 	case LANDLOCK_ABI_LAST:
 		break;
 	default:
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 4/5] landlock/selftests: Test named UNIX domain socket restrictions
  2026-01-10 14:32 [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Günther Noack
                   ` (2 preceding siblings ...)
  2026-01-10 14:33 ` [PATCH v2 3/5] samples/landlock: Add support for named UNIX domain socket restrictions Günther Noack
@ 2026-01-10 14:33 ` Günther Noack
  2026-01-10 14:33 ` [PATCH v2 5/5] landlock: Document FS access rights for pathname UNIX sockets Günther Noack
  2026-01-12 16:08 ` [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Mickaël Salaün
  5 siblings, 0 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-10 14:33 UTC (permalink / raw)
  To: Mickaël Salaün
  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 rights for connect() and sendmsg() to named UNIX
  domain sockets, in various combinations.
* Extract common helpers from an existing IOCTL test that
  also uses pathname unix(7) sockets.

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 | 218 +++++++++++++++++++--
 1 file changed, 202 insertions(+), 16 deletions(-)

diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 0cbde65e032a..e1822fa687e8 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -4360,30 +4360,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);
@@ -4395,9 +4426,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));
@@ -4572,6 +4601,163 @@ 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 int sock_type;
+	const int expected;
+	const bool use_sendto;
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(unix_socket, stream_handled_not_allowed)
+{
+	/* clang-format on */
+	.handled = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM,
+	.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_STREAM,
+	.allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM,
+	.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_DGRAM,
+	.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_DGRAM,
+	.allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM,
+	.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_DGRAM,
+	.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_DGRAM,
+	.allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM,
+	.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_SEQPACKET,
+	.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_SEQPACKET,
+	.allowed = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET,
+	.sock_type = SOCK_SEQPACKET,
+	.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;
+	const struct rule rules[] = {
+		{
+			.path = path,
+			.access = variant->allowed,
+		},
+		{},
+	};
+
+	/* Sets up a server */
+	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 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);
+
+	ASSERT_EQ(0, close(cli_fd));
+	ASSERT_EQ(0, close(srv_fd));
+	ASSERT_EQ(0, unlink(path));
+}
+
 /* clang-format off */
 FIXTURE(layout1_bind) {};
 /* clang-format on */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 5/5] landlock: Document FS access rights for pathname UNIX sockets
  2026-01-10 14:32 [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Günther Noack
                   ` (3 preceding siblings ...)
  2026-01-10 14:33 ` [PATCH v2 4/5] landlock/selftests: Test " Günther Noack
@ 2026-01-10 14:33 ` Günther Noack
  2026-01-12 16:08 ` [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Mickaël Salaün
  5 siblings, 0 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-10 14:33 UTC (permalink / raw)
  To: Mickaël Salaün
  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 | 25 +++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index 1d0c2c15c22e..29afde4f7e75 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -77,7 +77,10 @@ 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_STREAM |
+            LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM |
+            LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET,
         .handled_access_net =
             LANDLOCK_ACCESS_NET_BIND_TCP |
             LANDLOCK_ACCESS_NET_CONNECT_TCP,
@@ -127,6 +130,17 @@ 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:
+        /*
+         * Removes LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM,
+         * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM and
+         * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET for ABI < 8
+         */
+	 ruleset_attr.handled_access_fs &=
+	 	~(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM |
+		  LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM |
+		  LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET);
     }
 
 This enables the creation of an inclusive ruleset that will contain our rules.
@@ -604,6 +618,15 @@ Landlock audit events with the ``LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF``,
 sys_landlock_restrict_self().  See Documentation/admin-guide/LSM/landlock.rst
 for more details on audit.
 
+Pathname UNIX sockets (ABI < 8)
+-------------------------------
+
+Starting with the Landlock ABI version 8, it is possible to restrict
+connections to pathname :manpage:`unix(7)` sockets using the new
+``LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM``,
+``LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM`` and
+``LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET`` rights.
+
 .. _kernel_support:
 
 Kernel support
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-10 14:32 ` [PATCH v2 1/5] lsm: Add hook unix_path_connect Günther Noack
@ 2026-01-10 16:45   ` Justin Suess
  2026-01-11  9:55     ` Günther Noack
  2026-01-13 22:51     ` Paul Moore
  2026-01-13  9:34   ` Christian Brauner
  1 sibling, 2 replies; 23+ messages in thread
From: Justin Suess @ 2026-01-10 16:45 UTC (permalink / raw)
  To: Günther Noack, Mickaël Salaün, Paul Moore,
	James Morris, Serge E . Hallyn
  Cc: 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

On 1/10/26 09:32, Günther Noack wrote:
> From: Justin Suess <utilityemal77@gmail.com>
>
> Adds an LSM hook unix_path_connect.
>
> This hook is called to check the path of a named unix socket before a
> connection is initiated.
>
> 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..1dee5d8d52d2 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_path_connect, 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..382612af27a6 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_path_connect(const struct path *path, int type, int flags);
> +
> +#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +static inline int security_unix_path_connect(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 55cdebfa0da0..3aabe2d489ae 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_path_connect(&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..0cee3502db83 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_path_connect() - 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_path_connect(const struct path *path, int type, int flags)
> +{
> +	return call_int_hook(unix_path_connect, path, type, flags);
> +}
> +EXPORT_SYMBOL(security_unix_path_connect);
> +
> +#endif	/* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +
>  #ifdef CONFIG_SECURITY_INFINIBAND
>  /**
>   * security_ib_pkey_access() - Check if access to an IB pkey is allowed
Just for awareness,

I'm considering renaming this hook to unix_socket_path_lookup, since as Günther
pointed out this hook is not just hit on connect, but also on sendmsg.

Justin

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] samples/landlock: Add support for named UNIX domain socket restrictions
  2026-01-10 14:33 ` [PATCH v2 3/5] samples/landlock: Add support for named UNIX domain socket restrictions Günther Noack
@ 2026-01-11  9:50   ` Günther Noack
  0 siblings, 0 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-11  9:50 UTC (permalink / raw)
  To: Mickaël Salaün
  Cc: 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 Sat, Jan 10, 2026 at 03:33:00PM +0100, Günther Noack wrote:
> The access rights for UNIX domain socket lookups are 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.

Sorry, I missed a part of the discussion in V1, which was suggested by
Tingmao Wang in [1]:

You are right, the new access rights should indeed become part of
ACCESS_FILE in the sample tool.  (When the sample tool is adding a
rule for a non-directory, it only applies access rights that are also
in ACCESS_FILE.)

Will add it in V3.

–Günther

[1] https://lore.kernel.org/all/423dd2ca-ecba-47cf-98a7-4d99a48939da@maowtm.org/

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-10 16:45   ` Justin Suess
@ 2026-01-11  9:55     ` Günther Noack
  2026-01-13 22:51     ` Paul Moore
  1 sibling, 0 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-11  9:55 UTC (permalink / raw)
  To: Justin Suess
  Cc: Mickaël Salaün, Paul Moore, James Morris,
	Serge E . Hallyn, 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

On Sat, Jan 10, 2026 at 11:45:03AM -0500, Justin Suess wrote:
> Just for awareness,
> 
> I'm considering renaming this hook to unix_socket_path_lookup, since as Günther
> pointed out this hook is not just hit on connect, but also on sendmsg.

+1 I would be in favor of this.

(In doubt, Paul Moore has the last word on LSM hook naming.  I believe
that both "lookup" and "resolve" are being used exchangeably to refer
to path lookups. (e.g. see the path_resolution(7) man page [1]))

–Günther

[1] https://man7.org/linux/man-pages/man7/path_resolution.7.html

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/5] landlock: Control pathname UNIX domain socket resolution by path
  2026-01-10 14:32 ` [PATCH v2 2/5] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
@ 2026-01-12 15:38   ` Justin Suess
  2026-01-19 11:43     ` Mickaël Salaün
  0 siblings, 1 reply; 23+ messages in thread
From: Justin Suess @ 2026-01-12 15:38 UTC (permalink / raw)
  To: Günther Noack, Mickaël Salaün
  Cc: Jann Horn, linux-security-module, Tingmao Wang,
	Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
	konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross,
	Tahera Fahimi

On 1/10/26 09:32, Günther Noack wrote:
> * Add new access rights which control the look up operations for named
>   UNIX domain sockets.  The resolution happens during connect() and
>   sendmsg() (depending on socket type).
>   * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM
>   * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM
>   * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET
Might be a crazy thought but would it be better to implement the
STREAM/DGRAM/SEQPACKET as an add_rule flag rather than as a separate
access right? There are other types of address families like AF_CAN,
AF_BLUETOOTH, AF_VSOCK that support multiple socket types.

This saves us on access right numbers if they get added in the future to
landlock.

So we could have:

LANDLOCK_ADD_RULE_SOCK_STREAM
LANDLOCK_ADD_RULE_SOCK_DGRAM
LANDLOCK_ADD_RULE_SOCK_SEQPACKET

and use it as such:

landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
                             &path_beneath_for_unix_socket,
                             LANDLOCK_ADD_RULE_SOCK_STREAM |
                             LANDLOCK_ADD_RULE_SOCK_DGRAM);

For address families with only one socket type (ie tcp and udp), the
socket family be implied, which keeps backward compatibility w/ the
existing tcp access right.

This way, we don't have to make completely separate access rights for
future socket families. So we could add a single access right for bluetooth,
for instance, and distinguish which socket families we give it with the
LANDLOCK_ADD_RULE_SOCK_* flags.

We'd have to track the SOCK_(socket_type) for unix sockets as we gather
access rights. But afaik unix sockets should be the only socket type that
has to deal with tree traversal.
> * 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.
>
> 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                   |  2 +-
>  security/landlock/audit.c                    |  6 ++++
>  security/landlock/fs.c                       | 34 +++++++++++++++++++-
>  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   |  7 ++--
>  8 files changed, 58 insertions(+), 7 deletions(-)
>
> diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
> index f030adc462ee..455edc241c12 100644
> --- a/include/uapi/linux/landlock.h
> +++ b/include/uapi/linux/landlock.h
> @@ -216,6 +216,13 @@ struct landlock_net_port_attr {
>   *   :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with
>   *   ``O_TRUNC``.  This access right is available since the third version of the
>   *   Landlock ABI.
> + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM: Connect to named
> + *   :manpage:`unix(7)` ``SOCK_STREAM`` sockets.
> + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM: Send messages to named
> + *   :manpage:`unix(7)` ``SOCK_DGRAM`` sockets or connect to them using
> + *   :manpage:`connect(2)`.
> + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET: Connect to named
> + *   :manpage:`unix(7)` ``SOCK_SEQPACKET`` sockets.
>   *
>   * 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
> @@ -321,6 +328,9 @@ 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_STREAM		(1ULL << 16)
> +#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM		(1ULL << 17)
> +#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET	(1ULL << 18)
>  /* clang-format on */
>  
>  /**
> diff --git a/security/landlock/access.h b/security/landlock/access.h
> index 7961c6630a2d..c7784922be3c 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);
> diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> index e899995f1fd5..0645304e0375 100644
> --- a/security/landlock/audit.c
> +++ b/security/landlock/audit.c
> @@ -37,6 +37,12 @@ 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_STREAM)] =
> +		"fs.resolve_unix_stream",
> +	[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM)] =
> +		"fs.resolve_unix_dgram",
> +	[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)] =
> +		"fs.resolve_unix_seqpacket",
>  };
>  
>  static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index 8205673c8b1c..94f5fc7ee9fd 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -9,6 +9,7 @@
>   * Copyright © 2023-2024 Google LLC
>   */
>  
> +#include "linux/net.h"
>  #include <asm/ioctls.h>
>  #include <kunit/test.h>
>  #include <linux/atomic.h>
> @@ -314,7 +315,10 @@ 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_STREAM | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)
>  /* clang-format on */
>  
>  /*
> @@ -1588,6 +1592,33 @@ static int hook_path_truncate(const struct path *const path)
>  	return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
>  }
>  
> +static int hook_unix_path_connect(const struct path *const path, int type,
> +				  int flags)
> +{
> +	access_mask_t access_request = 0;
> +
> +	/* Lookup for the purpose of saving coredumps is OK. */
> +	if (flags & SOCK_COREDUMP)
> +		return 0;
> +
> +	switch (type) {
> +	case SOCK_STREAM:
> +		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM;
> +		break;
> +	case SOCK_DGRAM:
> +		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM;
> +		break;
> +	case SOCK_SEQPACKET:
> +		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET;
> +		break;
> +	}
> +
> +	if (!access_request)
> +		return 0;
> +
> +	return current_check_access_path(path, access_request);
> +}
> +
>  /* File hooks */
>  
>  /**
> @@ -1872,6 +1903,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_path_connect, hook_unix_path_connect),
>  
>  	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 65b5ff051674..1f6f864afec2 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_SEQPACKET
>  #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 0116e9f93ffe..66fd196be85a 100644
> --- a/security/landlock/syscalls.c
> +++ b/security/landlock/syscalls.c
> @@ -161,7 +161,7 @@ static const struct file_operations ruleset_fops = {
>   * Documentation/userspace-api/landlock.rst should be updated to reflect the
>   * UAPI change.
>   */
> -const int landlock_abi_version = 7;
> +const int landlock_abi_version = 8;
>  
>  /**
>   * 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 7b69002239d7..f4b1a275d8d9 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(7, landlock_create_ruleset(NULL, 0,
> +	ASSERT_EQ(8, 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..0cbde65e032a 100644
> --- a/tools/testing/selftests/landlock/fs_test.c
> +++ b/tools/testing/selftests/landlock/fs_test.c
> @@ -575,9 +575,12 @@ 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_STREAM | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM | \
> +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)
>  
> -#define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV
> +#define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET
>  
>  #define ACCESS_ALL ( \
>  	ACCESS_FILE | \


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control
  2026-01-10 14:32 [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Günther Noack
                   ` (4 preceding siblings ...)
  2026-01-10 14:33 ` [PATCH v2 5/5] landlock: Document FS access rights for pathname UNIX sockets Günther Noack
@ 2026-01-12 16:08 ` Mickaël Salaün
  2026-01-12 20:53   ` Günther Noack
  5 siblings, 1 reply; 23+ messages in thread
From: Mickaël Salaün @ 2026-01-12 16:08 UTC (permalink / raw)
  To: Günther Noack
  Cc: Paul Moore, James Morris, Serge E . Hallyn, 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

On Sat, Jan 10, 2026 at 03:32:55PM +0100, Günther Noack wrote:
> 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 a file system access right for each
> type of UNIX domain socket:
> 
>  * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM
>  * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM
>  * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET
> 
> 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 can come as a surprise for users (e.g. in
> [1]) and it can be used to escape a sandbox when a Unix service offers
> command execution (some scenarios were listed by Tingmao Wang in [2]).
> 
> The original feature request is at [4].
> 
> ## Alternatives and Related Work
> 

> ### Alternative: Use existing LSM hooks
> 
> The existing hooks security_unix_stream_connect(),
> security_unix_may_send() and security_socket_connect() do not give
> access to the resolved file system path.
> 
> Resolving the file system path again within Landlock would in my
> understanding produce a TOCTOU race, so making the decision based on
> the struct sockaddr_un contents is not an option.
> 
> It is tempting to use the struct path that the listening socket is
> bound to, which can be acquired through the existing hooks.
> Unfortunately, the listening socket may have been bound from within a
> different namespace, and it is therefore a path that can not actually
> be referenced by the sandboxed program at the time of constructing the
> Landlock policy.  (More details are on the Github issue at [6] and on
> the LKML at [9]).

Please move (or duplicate) this rationale in the patch dedicated to the
new hook.  It helps patch review (and to understand commits when already
merged).

> 
> ### 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 file system 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).
> 
> ## Open questions in V2
> 
> Seeking feedback on:
> 
> - Feedback on the LSM hook name would be appreciated. We realize that
>   not all invocations of the LSM hook are related to connect(2) as the
>   name suggests, but some also happen during sendmsg(2).

Renaming security_unix_path_connect() to security_unix_find() would look
appropriate to me wrt the caller.

> - Feedback on the structuring of the Landlock access rights, splitting
>   them up by socket type.  (Also naming; they are now consistently
>   called "RESOLVE", but could be named "CONNECT" in the stream and
>   seqpacket cases?)

I don't see use cases where differenciating the type of unix socket
would be useful.  LANDLOCK_ACCESS_FS_RESOLVE_UNIX would look good to me.

Tests should still cover all these types though.

What would be the inverse of "resolve" (i.e. to restrict the server
side)?  Would LANDLOCK_ACCESS_FS_MAKE_SOCK be enough?

> 
> ## 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].
> 
> 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.
> 
> [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/
> 
> ---
> 
> ## Older versions of this patch set
> 
> V1: https://lore.kernel.org/all/20260101134102.25938-1-gnoack3000@gmail.com/
> 
> 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 rights for pathname UNIX sockets
> 
> Justin Suess (1):
>   lsm: Add hook unix_path_connect
> 
>  Documentation/userspace-api/landlock.rst     |  25 ++-
>  include/linux/lsm_hook_defs.h                |   4 +
>  include/linux/security.h                     |  11 +
>  include/uapi/linux/landlock.h                |  10 +
>  net/unix/af_unix.c                           |   9 +
>  samples/landlock/sandboxer.c                 |  18 +-
>  security/landlock/access.h                   |   2 +-
>  security/landlock/audit.c                    |   6 +
>  security/landlock/fs.c                       |  34 ++-
>  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   | 225 +++++++++++++++++--
>  14 files changed, 344 insertions(+), 26 deletions(-)
> 
> -- 
> 2.52.0
> 
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control
  2026-01-12 16:08 ` [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Mickaël Salaün
@ 2026-01-12 20:53   ` Günther Noack
  2026-01-17 18:57     ` Justin Suess
  0 siblings, 1 reply; 23+ messages in thread
From: Günther Noack @ 2026-01-12 20:53 UTC (permalink / raw)
  To: Mickaël Salaün, Justin Suess
  Cc: Paul Moore, James Morris, Serge E . Hallyn, 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

Thanks for the review!

On Mon, Jan 12, 2026 at 05:08:02PM +0100, Mickaël Salaün wrote:
> On Sat, Jan 10, 2026 at 03:32:55PM +0100, Günther Noack wrote:
> > ## Alternatives and Related Work
> > 
> 
> > ### Alternative: Use existing LSM hooks
> > 
> > The existing hooks security_unix_stream_connect(),
> > security_unix_may_send() and security_socket_connect() do not give
> > access to the resolved file system path.
> > 
> > Resolving the file system path again within Landlock would in my
> > understanding produce a TOCTOU race, so making the decision based on
> > the struct sockaddr_un contents is not an option.
> > 
> > It is tempting to use the struct path that the listening socket is
> > bound to, which can be acquired through the existing hooks.
> > Unfortunately, the listening socket may have been bound from within a
> > different namespace, and it is therefore a path that can not actually
> > be referenced by the sandboxed program at the time of constructing the
> > Landlock policy.  (More details are on the Github issue at [6] and on
> > the LKML at [9]).
> 
> Please move (or duplicate) this rationale in the patch dedicated to the
> new hook.  It helps patch review (and to understand commits when already
> merged).

Justin, would you like to look into this?
Please feel free to copy the wording.


> > ### 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 file system 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).
> > 
> > ## Open questions in V2
> > 
> > Seeking feedback on:
> > 
> > - Feedback on the LSM hook name would be appreciated. We realize that
> >   not all invocations of the LSM hook are related to connect(2) as the
> >   name suggests, but some also happen during sendmsg(2).
> 
> Renaming security_unix_path_connect() to security_unix_find() would look
> appropriate to me wrt the caller.

Justin, this is also on your commit.  (I find security_unix_find() and
security_unix_resolve() equally acceptable options.)


> > - Feedback on the structuring of the Landlock access rights, splitting
> >   them up by socket type.  (Also naming; they are now consistently
> >   called "RESOLVE", but could be named "CONNECT" in the stream and
> >   seqpacket cases?)
> 
> I don't see use cases where differenciating the type of unix socket
> would be useful.  LANDLOCK_ACCESS_FS_RESOLVE_UNIX would look good to me.

I did it mostly because it seemed consistent with the TCP and (soon)
UDP controls, which are also controls specific to the socket type and
not just the address family.  But I agree that the granularity is
likely not needed here.  I can change it back for v3 and rename it to
LANDLOCK_ACCESS_FS_RESOLVE_UNIX.


> What would be the inverse of "resolve" (i.e. to restrict the server
> side)?  Would LANDLOCK_ACCESS_FS_MAKE_SOCK be enough?

Yes, that would be enough. My reasoning is as follows:

The server-side operation that is related to associating the service
with a given file system name is bind(2), and that is restrictable in
that case using LANDLOCK_ACCESS_FS_MAKE_SOCK.

Also, to my delight (and other than in TCP), listening on an unbound
socket does not work (see unix_listen() in af_unix.c):

  if (!READ_ONCE(u->addr))
  	goto out;	/* No listens on an unbound socket */

(You can get it to "autobind" during an explicit bind() or a connect()
call, but that creates an abstract UNIX address. (Documented in
socket(7) and implemented in unix_autobind() in af_unix.c))


–Günther

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-10 14:32 ` [PATCH v2 1/5] lsm: Add hook unix_path_connect Günther Noack
  2026-01-10 16:45   ` Justin Suess
@ 2026-01-13  9:34   ` Christian Brauner
  2026-01-13 23:27     ` Paul Moore
  1 sibling, 1 reply; 23+ messages in thread
From: Christian Brauner @ 2026-01-13  9:34 UTC (permalink / raw)
  To: Günther Noack
  Cc: Mickaël Salaün, Paul Moore, James Morris,
	Serge E . Hallyn, 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

On Sat, Jan 10, 2026 at 03:32:57PM +0100, Günther Noack wrote:
> From: Justin Suess <utilityemal77@gmail.com>
> 
> Adds an LSM hook unix_path_connect.
> 
> This hook is called to check the path of a named unix socket before a
> connection is initiated.
> 
> 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..1dee5d8d52d2 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_path_connect, 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..382612af27a6 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_path_connect(const struct path *path, int type, int flags);
> +
> +#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
> +static inline int security_unix_path_connect(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 55cdebfa0da0..3aabe2d489ae 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_path_connect(&path, type, flags);
> +	if (err)
> +		goto path_put;

Couldn't we try reflowing the code here so the path is passed to
security_unix_stream_connect() and security_unix_may_send() so that all
LSMs get the same data and we don't have to have different LSMs hooks
into different callpaths that effectively do the same thing.

I mean the objects are even in two completely different states between
those hooks. Even what type of sockets get a call to the LSM is
different between those two hooks.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-10 16:45   ` Justin Suess
  2026-01-11  9:55     ` Günther Noack
@ 2026-01-13 22:51     ` Paul Moore
  2026-01-13 23:30       ` Paul Moore
  1 sibling, 1 reply; 23+ messages in thread
From: Paul Moore @ 2026-01-13 22:51 UTC (permalink / raw)
  To: Justin Suess
  Cc: Günther Noack, Mickaël Salaün, James Morris,
	Serge E . Hallyn, 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

On Sat, Jan 10, 2026 at 11:45 AM Justin Suess <utilityemal77@gmail.com> wrote:
> On 1/10/26 09:32, Günther Noack wrote:
> > From: Justin Suess <utilityemal77@gmail.com>
> >
> > Adds an LSM hook unix_path_connect.
> >
> > This hook is called to check the path of a named unix socket before a
> > connection is initiated.
> >
> > 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(+)

...

> > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > +/*
> > + * security_unix_path_connect() - 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_path_connect(const struct path *path, int type, int flags)
> > +{
> > +     return call_int_hook(unix_path_connect, path, type, flags);
> > +}
> > +EXPORT_SYMBOL(security_unix_path_connect);

...

> I'm considering renaming this hook to unix_socket_path_lookup, since as Günther
> pointed out this hook is not just hit on connect, but also on sendmsg.

I'm not bothered too much by this, either _path_connect() or
_path_lookup() is okay; please don't use
security_unix_socket_path_lookup(), that's longer than it needs to be,
if you've got "_unix_" in there we know you're talking about a socket
:)

While I don't want us to do it often, we can always change established
hook names if the names end up being really awful or misleading.
We've done it in the past.

It would be nice if somehow the hook name reflected the fact that it
is called on the "client" side of the connection, and not the "server"
side, but I wouldn't use either of those terms (client or server), and
to be honest I can't think of anything better than _path_lookup() at
the moment.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-13  9:34   ` Christian Brauner
@ 2026-01-13 23:27     ` Paul Moore
  2026-01-15 10:10       ` Günther Noack
  0 siblings, 1 reply; 23+ messages in thread
From: Paul Moore @ 2026-01-13 23:27 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Günther Noack, Mickaël Salaün, James Morris,
	Serge E . Hallyn, 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

On Tue, Jan 13, 2026 at 4:34 AM Christian Brauner <brauner@kernel.org> wrote:
> On Sat, Jan 10, 2026 at 03:32:57PM +0100, Günther Noack wrote:
> > From: Justin Suess <utilityemal77@gmail.com>
> >
> > Adds an LSM hook unix_path_connect.
> >
> > This hook is called to check the path of a named unix socket before a
> > connection is initiated.
> >
> > 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/net/unix/af_unix.c b/net/unix/af_unix.c
> > index 55cdebfa0da0..3aabe2d489ae 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_path_connect(&path, type, flags);
> > +     if (err)
> > +             goto path_put;
>
> Couldn't we try reflowing the code here so the path is passed ...

It would be good if you could be a bit more specific about your
desires here.  Are you talking about changing the
unix_find_other()/unix_find_bsd() code path such that the path is
available to unix_find_other() callers and not limited to the
unix_find_bsd() scope?

> ... to
> security_unix_stream_connect() and security_unix_may_send() so that all
> LSMs get the same data and we don't have to have different LSMs hooks
> into different callpaths that effectively do the same thing.
>
> I mean the objects are even in two completely different states between
> those hooks. Even what type of sockets get a call to the LSM is
> different between those two hooks.

I'm working on the assumption that you are talking about changing the
UNIX socket code so that the path info is available to the existing
_may_send() and _stream_connect() hooks.  If that isn't the case, and
you're thinking of something different, disregard my comments below.

In both the unix_dgram_{connect(),sendmsg()}, aka
security_unix_may_send(), cases and the unix_stream_connect(), aka
security_unix_stream_connect(), case the call to unix_find_other() is
done to lookup the other end of the communication channel, which does
seem reasonably consistent to me.  Yes, of course, once you start
getting into the specifics of the UNIX socket handling the unix_dgram_
and unix_stream_ cases are very different, including their
corresponding existing LSM hooks, but that doesn't mean in the context
of unix_find_bsd() that security_unix_path_connect() doesn't have
value.

The alternative would be some rather serious surgery in af_unix.c to
persist the path struct from unix_find_bsd() until the later LSM hooks
are executed.  It's certainly not impossible, but I'm not sure it is
necessary or desirable at this point in time.  LSMs that wish to
connect the information from _unix_path_connect() to either
_unix_stream_connect() or _unix_may_send() can do so today without
needing to substantially change af_unix.c.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-13 22:51     ` Paul Moore
@ 2026-01-13 23:30       ` Paul Moore
  0 siblings, 0 replies; 23+ messages in thread
From: Paul Moore @ 2026-01-13 23:30 UTC (permalink / raw)
  To: Justin Suess
  Cc: Günther Noack, Mickaël Salaün, James Morris,
	Serge E . Hallyn, 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

On Tue, Jan 13, 2026 at 5:51 PM Paul Moore <paul@paul-moore.com> wrote:
> On Sat, Jan 10, 2026 at 11:45 AM Justin Suess <utilityemal77@gmail.com> wrote:
> > On 1/10/26 09:32, Günther Noack wrote:
> > > From: Justin Suess <utilityemal77@gmail.com>
> > >
> > > Adds an LSM hook unix_path_connect.
> > >
> > > This hook is called to check the path of a named unix socket before a
> > > connection is initiated.
> > >
> > > 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(+)
>
> ...
>
> > > +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> > > +/*
> > > + * security_unix_path_connect() - 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_path_connect(const struct path *path, int type, int flags)
> > > +{
> > > +     return call_int_hook(unix_path_connect, path, type, flags);
> > > +}
> > > +EXPORT_SYMBOL(security_unix_path_connect);
>
> ...
>
> > I'm considering renaming this hook to unix_socket_path_lookup, since as Günther
> > pointed out this hook is not just hit on connect, but also on sendmsg.
>
> I'm not bothered too much ...

I forgot to add that I know you're likely going to do another revision
to this patchset to rename the hook, but I would suggest waiting until
the AppArmor folks have had a chance to look at the hook.  I want to
make sure the new hook is reasonable and suitably generic for a
path-based LSM, and while I suspect it is, having another set of
path-based LSM eyes review the hook would be a very good thing.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-13 23:27     ` Paul Moore
@ 2026-01-15 10:10       ` Günther Noack
  2026-01-15 21:24         ` Demi Marie Obenour
  2026-01-15 21:46         ` Paul Moore
  0 siblings, 2 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-15 10:10 UTC (permalink / raw)
  To: Paul Moore, Christian Brauner, Justin Suess
  Cc: Mickaël Salaün, James Morris, Serge E . Hallyn,
	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

On Tue, Jan 13, 2026 at 06:27:15PM -0500, Paul Moore wrote:
> On Tue, Jan 13, 2026 at 4:34 AM Christian Brauner <brauner@kernel.org> wrote:
> > On Sat, Jan 10, 2026 at 03:32:57PM +0100, Günther Noack wrote:
> > > From: Justin Suess <utilityemal77@gmail.com>
> > >
> > > Adds an LSM hook unix_path_connect.
> > >
> > > This hook is called to check the path of a named unix socket before a
> > > connection is initiated.
> > >
> > > 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/net/unix/af_unix.c b/net/unix/af_unix.c
> > > index 55cdebfa0da0..3aabe2d489ae 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_path_connect(&path, type, flags);
> > > +     if (err)
> > > +             goto path_put;
> >
> > Couldn't we try reflowing the code here so the path is passed ...
> 
> It would be good if you could be a bit more specific about your
> desires here.  Are you talking about changing the
> unix_find_other()/unix_find_bsd() code path such that the path is
> available to unix_find_other() callers and not limited to the
> unix_find_bsd() scope?
> 
> > ... to
> > security_unix_stream_connect() and security_unix_may_send() so that all
> > LSMs get the same data and we don't have to have different LSMs hooks
> > into different callpaths that effectively do the same thing.
> >
> > I mean the objects are even in two completely different states between
> > those hooks. Even what type of sockets get a call to the LSM is
> > different between those two hooks.
> 
> I'm working on the assumption that you are talking about changing the
> UNIX socket code so that the path info is available to the existing
> _may_send() and _stream_connect() hooks.  If that isn't the case, and
> you're thinking of something different, disregard my comments below.
> 
> In both the unix_dgram_{connect(),sendmsg()}, aka
> security_unix_may_send(), cases and the unix_stream_connect(), aka
> security_unix_stream_connect(), case the call to unix_find_other() is
> done to lookup the other end of the communication channel, which does
> seem reasonably consistent to me.  Yes, of course, once you start
> getting into the specifics of the UNIX socket handling the unix_dgram_
> and unix_stream_ cases are very different, including their
> corresponding existing LSM hooks, but that doesn't mean in the context
> of unix_find_bsd() that security_unix_path_connect() doesn't have
> value.
> 
> The alternative would be some rather serious surgery in af_unix.c to
> persist the path struct from unix_find_bsd() until the later LSM hooks
> are executed.  It's certainly not impossible, but I'm not sure it is
> necessary or desirable at this point in time.  LSMs that wish to
> connect the information from _unix_path_connect() to either
> _unix_stream_connect() or _unix_may_send() can do so today without
> needing to substantially change af_unix.c.

Thanks for the review, Christan and Paul!

I am also unconvinced by the approach. It has also crossed my mind
before though, and my reasoning is as follows:

For reference, the function call hierarchy in af_unix.c is:

* unix_dgram_connect()   (*)
  * unix_find_other()
    * unix_find_bsd()
  * security_unix_may_send()

* unix_dgram_sendmsg()   (*)
  * unix_find_other()
    * unix_find_bsd()
  * security_unix_may_send()

* unix_stream_connect()  (*)
  * unix_find_other()
    * unix_find_bsd()
  * security_unix_stream_connect()

In my understanding, the hypothetical implementation would be:

* allocate a struct path on the stack of these proto_ops hook
  functions (marked with (*) above)
* pass a pointer to that path down to unix_find_other(), only to be
  filled out in the case that this is a pathname UNIX socket (not an
  abstract UNIX socket)
* pass a const pointer to that path to the LSM hooks

and then the LSM hooks would have to check whether the struct path has
non-zero pointers and could do the check.

This has the upside that it does not introduce a new LSM hook, but
only adds a "path" parameter to two existing LSM hooks.

On the other side, I see the following drawbacks:

* The more serious surgery in af_unix, which Paul also discussed:

  The function interface to unix_find_other() would need additional
  parameters for the sole purpose of supporting these LSM hooks and
  the refcounting of the struct path would have to be done in three
  functions instead of just in one.  That would complicate the
  af_unix.c logic, even when CONFIG_SECURITY_PATH is not set.

* The cases in which we pass a non-zero path argument to the LSM hooks
  would have surprising semantics IMHO, because it is not always set:

  * If a UNIX dgram user uses connect(2) and then calls sendmsg(2)
    without explicit recipient address, unix_dgram_sendmsg() would
    *not* do the look up any more and we can not provide the path to
    the security_unix_may_send() hook.
  * For abstract UNIX sockets it is not set either, of course.

  The path argument to the LSM hook would be present in the exact same
  cases where we now call the new UNIX path lookup LSM hook, but it
  would be invoked with a delay.

* Some properties of the resolved socket are still observable to
  userspace:

  When we only pass the path to a later LSM hook, there are a variety
  of additional error case checks in af_unix.c which are based on the
  "other" socket which we looked up through the path.  Examples:

  * was other shutdown(2)? (ECONNREFUSED on connect or EPIPE on dgram_sendmsg)
  * does other support SO_PASSRIGHTS (fd passing)? (EPERM on dgram_sendmsg)
  * would sendmsg pass sk_filter() (on dgram_sendmsg)

  For a LSM policy that is supposed to restrict the resolution of a
  UNIX socket by path, I would not expect such properties of the
  resolved socket to be observable?

  (And we also can't fix this up in the LSM by returning a matching
  error code, because at least unix_dgram_sendmsg() returns multiple
  different error codes in these error cases.)

  I would prefer if the correctness of our LSM did not depend on
  keeping track of the error scenarios in af_unix.c.  This seems
  brittle.

Overall, I am not convinced that using pre-existing hooks is the right
way and I would prefer the approach where we have a more dedicated LSM
hook for the path lookup.

Does that seem reasonable?  Let me know what you think.

–Günther

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-15 10:10       ` Günther Noack
@ 2026-01-15 21:24         ` Demi Marie Obenour
  2026-01-15 22:32           ` Günther Noack
  2026-01-15 21:46         ` Paul Moore
  1 sibling, 1 reply; 23+ messages in thread
From: Demi Marie Obenour @ 2026-01-15 21:24 UTC (permalink / raw)
  To: Günther Noack, Paul Moore, Christian Brauner, Justin Suess
  Cc: Mickaël Salaün, James Morris, Serge E . Hallyn,
	linux-security-module, Tingmao Wang, Samasth Norway Ananda,
	Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
	Alyssa Ross, Jann Horn, Tahera Fahimi, Simon Horman, netdev,
	Alexander Viro


[-- Attachment #1.1.1: Type: text/plain, Size: 2400 bytes --]

On 1/15/26 05:10, Günther Noack wrote:
> On Tue, Jan 13, 2026 at 06:27:15PM -0500, Paul Moore wrote:
>> On Tue, Jan 13, 2026 at 4:34 AM Christian Brauner <brauner@kernel.org> wrote:
>>> On Sat, Jan 10, 2026 at 03:32:57PM +0100, Günther Noack wrote:
>>>> From: Justin Suess <utilityemal77@gmail.com>
>>>>
>>>> Adds an LSM hook unix_path_connect.
>>>>
>>>> This hook is called to check the path of a named unix socket before a
>>>> connection is initiated.
>>>>
>>>> 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(+)
>>
>> ...

...

> * Some properties of the resolved socket are still observable to
>   userspace:
> 
>   When we only pass the path to a later LSM hook, there are a variety
>   of additional error case checks in af_unix.c which are based on the
>   "other" socket which we looked up through the path.  Examples:
> 
>   * was other shutdown(2)? (ECONNREFUSED on connect or EPIPE on dgram_sendmsg)
>   * does other support SO_PASSRIGHTS (fd passing)? (EPERM on dgram_sendmsg)
>   * would sendmsg pass sk_filter() (on dgram_sendmsg)
> 
>   For a LSM policy that is supposed to restrict the resolution of a
>   UNIX socket by path, I would not expect such properties of the
>   resolved socket to be observable?
> 
>   (And we also can't fix this up in the LSM by returning a matching
>   error code, because at least unix_dgram_sendmsg() returns multiple
>   different error codes in these error cases.)
> 
>   I would prefer if the correctness of our LSM did not depend on
>   keeping track of the error scenarios in af_unix.c.  This seems
>   brittle.

Indeed so.

> Overall, I am not convinced that using pre-existing hooks is the right
> way and I would prefer the approach where we have a more dedicated LSM
> hook for the path lookup.
> 
> Does that seem reasonable?  Let me know what you think.
> 
> –Günther

Having a dedicated LSM hook for all path lookups is definitely my
preferred approach.  Could this allow limiting directory traversal
as well?
-- 
Sincerely,
Demi Marie Obenour (she/her/hers)

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-15 10:10       ` Günther Noack
  2026-01-15 21:24         ` Demi Marie Obenour
@ 2026-01-15 21:46         ` Paul Moore
  1 sibling, 0 replies; 23+ messages in thread
From: Paul Moore @ 2026-01-15 21:46 UTC (permalink / raw)
  To: Günther Noack
  Cc: Christian Brauner, Justin Suess, Mickaël Salaün,
	James Morris, Serge E . Hallyn, 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

On Thu, Jan 15, 2026 at 5:10 AM Günther Noack <gnoack3000@gmail.com> wrote:
> On Tue, Jan 13, 2026 at 06:27:15PM -0500, Paul Moore wrote:
> > On Tue, Jan 13, 2026 at 4:34 AM Christian Brauner <brauner@kernel.org> wrote:
> > > On Sat, Jan 10, 2026 at 03:32:57PM +0100, Günther Noack wrote:
> > > > From: Justin Suess <utilityemal77@gmail.com>
> > > >
> > > > Adds an LSM hook unix_path_connect.
> > > >
> > > > This hook is called to check the path of a named unix socket before a
> > > > connection is initiated.
> > > >
> > > > 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(+)

...

> On the other side, I see the following drawbacks:
>
> * The more serious surgery in af_unix, which Paul also discussed:

Not to take away from what Günther already mentioned, but my concern
about extending the path beyond the unix_find_bsd() function for the
sake of the LSM is that history has shown that the easiest (this is
very much a relative statement) approach towards acceptance of a new
LSM hook is to keep the addition/patch as small as possible while
still being useful.  Making the addition of a new LSM hook dependent
on significant changes outside of the security/ directory often
results in failure.

> Overall, I am not convinced that using pre-existing hooks is the right
> way and I would prefer the approach where we have a more dedicated LSM
> hook for the path lookup.
>
> Does that seem reasonable?  Let me know what you think.

I believe it's definitely the "path" (sorry) of least resistance.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 1/5] lsm: Add hook unix_path_connect
  2026-01-15 21:24         ` Demi Marie Obenour
@ 2026-01-15 22:32           ` Günther Noack
  0 siblings, 0 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-15 22:32 UTC (permalink / raw)
  To: Demi Marie Obenour
  Cc: Paul Moore, Christian Brauner, Justin Suess,
	Mickaël Salaün, James Morris, Serge E . Hallyn,
	linux-security-module, Tingmao Wang, Samasth Norway Ananda,
	Matthieu Buffet, Mikhail Ivanov, konstantin.meskhidze,
	Alyssa Ross, Jann Horn, Tahera Fahimi, Simon Horman, netdev,
	Alexander Viro

On Thu, Jan 15, 2026 at 04:24:48PM -0500, Demi Marie Obenour wrote:
> On 1/15/26 05:10, Günther Noack wrote:
> >   I would prefer if the correctness of our LSM did not depend on
> >   keeping track of the error scenarios in af_unix.c.  This seems
> >   brittle.
> 
> Indeed so.

Thanks for the support!

> > Overall, I am not convinced that using pre-existing hooks is the right
> > way and I would prefer the approach where we have a more dedicated LSM
> > hook for the path lookup.
> > 
> > Does that seem reasonable?  Let me know what you think.
> > 
> > –Günther
> 
> Having a dedicated LSM hook for all path lookups is definitely my
> preferred approach.  Could this allow limiting directory traversal
> as well?

No, this does not limit all path lookups, in the sense of what was
discussed in the thread at [1]. (I assume this is what you meant?)

The LSM hook proposed here is only about the lookup of named UNIX
domain sockets, as it happens when clients pass a struct sockaddr_un
to connect(2) or sendmsg(2).

–Günther

[1] https://lore.kernel.org/all/81f908e3-8a98-46e7-b20c-fe647784ceb4@gmail.com/

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control
  2026-01-12 20:53   ` Günther Noack
@ 2026-01-17 18:57     ` Justin Suess
  2026-01-18 17:44       ` Günther Noack
  0 siblings, 1 reply; 23+ messages in thread
From: Justin Suess @ 2026-01-17 18:57 UTC (permalink / raw)
  To: Günther Noack, Mickaël Salaün
  Cc: Paul Moore, James Morris, Serge E . Hallyn, 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

On 1/12/26 15:53, Günther Noack wrote:
> Thanks for the review!
>
> On Mon, Jan 12, 2026 at 05:08:02PM +0100, Mickaël Salaün wrote:
>> On Sat, Jan 10, 2026 at 03:32:55PM +0100, Günther Noack wrote:
>>> ## Alternatives and Related Work
>>>
>>> ### Alternative: Use existing LSM hooks
>>>
>>> The existing hooks security_unix_stream_connect(),
>>> security_unix_may_send() and security_socket_connect() do not give
>>> access to the resolved file system path.
>>>
>>> Resolving the file system path again within Landlock would in my
>>> understanding produce a TOCTOU race, so making the decision based on
>>> the struct sockaddr_un contents is not an option.
>>>
>>> It is tempting to use the struct path that the listening socket is
>>> bound to, which can be acquired through the existing hooks.
>>> Unfortunately, the listening socket may have been bound from within a
>>> different namespace, and it is therefore a path that can not actually
>>> be referenced by the sandboxed program at the time of constructing the
>>> Landlock policy.  (More details are on the Github issue at [6] and on
>>> the LKML at [9]).
>> Please move (or duplicate) this rationale in the patch dedicated to the
>> new hook.  It helps patch review (and to understand commits when already
>> merged).
> Justin, would you like to look into this?
> Please feel free to copy the wording.
No problem.

It's quite long, so would it make sense in the notes?
Instead of directly in the commit message?
>
>
>>> ### 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 file system 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).
>>> ## Open questions in V2
>>>
>>> Seeking feedback on:
>>>
>>> - Feedback on the LSM hook name would be appreciated. We realize that
>>>   not all invocations of the LSM hook are related to connect(2) as the
>>>   name suggests, but some also happen during sendmsg(2).
>> Renaming security_unix_path_connect() to security_unix_find() would look
>> appropriate to me wrt the caller.
> Justin, this is also on your commit.  (I find security_unix_find() and
> security_unix_resolve() equally acceptable options.)
security_unix_find works for me, and seems to better match the hook
location. I'll send an updated commit.
>
>
>>> - Feedback on the structuring of the Landlock access rights, splitting
>>>   them up by socket type.  (Also naming; they are now consistently
>>>   called "RESOLVE", but could be named "CONNECT" in the stream and
>>>   seqpacket cases?)
>> I don't see use cases where differenciating the type of unix socket
>> would be useful.  LANDLOCK_ACCESS_FS_RESOLVE_UNIX would look good to me.
> I did it mostly because it seemed consistent with the TCP and (soon)
> UDP controls, which are also controls specific to the socket type and
> not just the address family.  But I agree that the granularity is
> likely not needed here.  I can change it back for v3 and rename it to
> LANDLOCK_ACCESS_FS_RESOLVE_UNIX.
>
>
>> What would be the inverse of "resolve" (i.e. to restrict the server
>> side)?  Would LANDLOCK_ACCESS_FS_MAKE_SOCK be enough?
> Yes, that would be enough. My reasoning is as follows:
>
> The server-side operation that is related to associating the service
> with a given file system name is bind(2), and that is restrictable in
> that case using LANDLOCK_ACCESS_FS_MAKE_SOCK.
>
> Also, to my delight (and other than in TCP), listening on an unbound
> socket does not work (see unix_listen() in af_unix.c):
>
>   if (!READ_ONCE(u->addr))
>   	goto out;	/* No listens on an unbound socket */
>
> (You can get it to "autobind" during an explicit bind() or a connect()
> call, but that creates an abstract UNIX address. (Documented in
> socket(7) and implemented in unix_autobind() in af_unix.c))
>
>
> –Günther


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control
  2026-01-17 18:57     ` Justin Suess
@ 2026-01-18 17:44       ` Günther Noack
  0 siblings, 0 replies; 23+ messages in thread
From: Günther Noack @ 2026-01-18 17:44 UTC (permalink / raw)
  To: Justin Suess
  Cc: Mickaël Salaün, Paul Moore, James Morris,
	Serge E . Hallyn, 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

Hello!

On Sat, Jan 17, 2026 at 01:57:20PM -0500, Justin Suess wrote:
> On 1/12/26 15:53, Günther Noack wrote:
> > On Mon, Jan 12, 2026 at 05:08:02PM +0100, Mickaël Salaün wrote:
> >> On Sat, Jan 10, 2026 at 03:32:55PM +0100, Günther Noack wrote:
> >>> ## Alternatives and Related Work
> >>>
> >>> ### Alternative: Use existing LSM hooks
> >>>
> >>> The existing hooks security_unix_stream_connect(),
> >>> security_unix_may_send() and security_socket_connect() do not give
> >>> access to the resolved file system path.
> >>>
> >>> Resolving the file system path again within Landlock would in my
> >>> understanding produce a TOCTOU race, so making the decision based on
> >>> the struct sockaddr_un contents is not an option.
> >>>
> >>> It is tempting to use the struct path that the listening socket is
> >>> bound to, which can be acquired through the existing hooks.
> >>> Unfortunately, the listening socket may have been bound from within a
> >>> different namespace, and it is therefore a path that can not actually
> >>> be referenced by the sandboxed program at the time of constructing the
> >>> Landlock policy.  (More details are on the Github issue at [6] and on
> >>> the LKML at [9]).
> >> Please move (or duplicate) this rationale in the patch dedicated to the
> >> new hook.  It helps patch review (and to understand commits when already
> >> merged).
> > Justin, would you like to look into this?
> > Please feel free to copy the wording.
> No problem.
> 
> It's quite long, so would it make sense in the notes?
> Instead of directly in the commit message?

I think including it in the commit message is what Mickaël meant here.
The quoted email above is already from the cover letter (which I
assume you meant by "notes"?).  IMHO, the considerations that are
specific to the LSM hook are OK to put on the commit that introduces
it, even if they are a bit longer.  That way, a summary of the
tradeoffs also makes its way into the overall commit history (unlike
the cover letter).

FWIW, commit messages with long descriptions are not unheard of,
e.g. commit ee6a44da3c87 ("tty: Require CAP_SYS_ADMIN for all usages
of TIOCL_SELMOUSEREPORT"), which I submitted a while back.

For reference, the official guidance on commit messages is
https://www.kernel.org/doc/html/latest/process/submitting-patches.html#describe-your-changes


> >>> Seeking feedback on:
> >>>
> >>> - Feedback on the LSM hook name would be appreciated. We realize that
> >>>   not all invocations of the LSM hook are related to connect(2) as the
> >>>   name suggests, but some also happen during sendmsg(2).
> >> Renaming security_unix_path_connect() to security_unix_find() would look
> >> appropriate to me wrt the caller.
> > Justin, this is also on your commit.  (I find security_unix_find() and
> > security_unix_resolve() equally acceptable options.)
> security_unix_find works for me, and seems to better match the hook
> location. I'll send an updated commit.

Thanks! Please feel free to ping me, I'd be ready to send an updated v3.

–Günther

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/5] landlock: Control pathname UNIX domain socket resolution by path
  2026-01-12 15:38   ` Justin Suess
@ 2026-01-19 11:43     ` Mickaël Salaün
  0 siblings, 0 replies; 23+ messages in thread
From: Mickaël Salaün @ 2026-01-19 11:43 UTC (permalink / raw)
  To: Justin Suess
  Cc: Günther Noack, Jann Horn, linux-security-module,
	Tingmao Wang, Samasth Norway Ananda, Matthieu Buffet,
	Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
	Alyssa Ross, Tahera Fahimi

On Mon, Jan 12, 2026 at 10:38:44AM -0500, Justin Suess wrote:
> On 1/10/26 09:32, Günther Noack wrote:
> > * Add new access rights which control the look up operations for named
> >   UNIX domain sockets.  The resolution happens during connect() and
> >   sendmsg() (depending on socket type).
> >   * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM
> >   * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM
> >   * LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET
> Might be a crazy thought but would it be better to implement the
> STREAM/DGRAM/SEQPACKET as an add_rule flag rather than as a separate
> access right? There are other types of address families like AF_CAN,
> AF_BLUETOOTH, AF_VSOCK that support multiple socket types.

There should only be one LANDLOCK_ACCESS_FS_RESOLVE_UNIX, not one per
stream/dgram/seqpacket.

I guess there is no other type of address families that can be tied to
the filesystem, so there is no need for a more generic approach.
Moreover, each new access right should come with a good test coverage,
so adding a generic access right would be too much work.

The add_rule flags should make sense for any kind of rule type e.g.,
related to how the rule is applied.  We also have a lot of flexibility
with the landlock_*_attr structs where we can add new fields.

FYI, this patch series will make it possible to restrict socket creation
according to their properties:
https://lore.kernel.org/all/20251118134639.3314803-1-ivanov.mikhail1@huawei-partners.com/

> 
> This saves us on access right numbers if they get added in the future to
> landlock.

Even if we reach 64 access rights per type, we can still add new types.
Anyway, I guess this would not happen because more specific
landlock_*_attr would probably fit best.

> 
> So we could have:
> 
> LANDLOCK_ADD_RULE_SOCK_STREAM
> LANDLOCK_ADD_RULE_SOCK_DGRAM
> LANDLOCK_ADD_RULE_SOCK_SEQPACKET

This would be the wrong semantic because users don't really care about
the stream/dgram/seqpacket type but about the path name and the peer.

If we want to restrict other socket types, we would probably use
landlock_net_port_attr or create a new struct if necessary.

> 
> and use it as such:
> 
> landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
>                              &path_beneath_for_unix_socket,
>                              LANDLOCK_ADD_RULE_SOCK_STREAM |
>                              LANDLOCK_ADD_RULE_SOCK_DGRAM);
> 
> For address families with only one socket type (ie tcp and udp), the
> socket family be implied, which keeps backward compatibility w/ the
> existing tcp access right.
> 
> This way, we don't have to make completely separate access rights for
> future socket families. So we could add a single access right for bluetooth,
> for instance, and distinguish which socket families we give it with the
> LANDLOCK_ADD_RULE_SOCK_* flags.
> 
> We'd have to track the SOCK_(socket_type) for unix sockets as we gather
> access rights. But afaik unix sockets should be the only socket type that
> has to deal with tree traversal.
> > * 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.
> >
> > 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                   |  2 +-
> >  security/landlock/audit.c                    |  6 ++++
> >  security/landlock/fs.c                       | 34 +++++++++++++++++++-
> >  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   |  7 ++--
> >  8 files changed, 58 insertions(+), 7 deletions(-)
> >
> > diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
> > index f030adc462ee..455edc241c12 100644
> > --- a/include/uapi/linux/landlock.h
> > +++ b/include/uapi/linux/landlock.h
> > @@ -216,6 +216,13 @@ struct landlock_net_port_attr {
> >   *   :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with
> >   *   ``O_TRUNC``.  This access right is available since the third version of the
> >   *   Landlock ABI.
> > + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM: Connect to named
> > + *   :manpage:`unix(7)` ``SOCK_STREAM`` sockets.
> > + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM: Send messages to named
> > + *   :manpage:`unix(7)` ``SOCK_DGRAM`` sockets or connect to them using
> > + *   :manpage:`connect(2)`.
> > + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET: Connect to named
> > + *   :manpage:`unix(7)` ``SOCK_SEQPACKET`` sockets.
> >   *
> >   * 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
> > @@ -321,6 +328,9 @@ 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_STREAM		(1ULL << 16)
> > +#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM		(1ULL << 17)
> > +#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET	(1ULL << 18)
> >  /* clang-format on */
> >  
> >  /**
> > diff --git a/security/landlock/access.h b/security/landlock/access.h
> > index 7961c6630a2d..c7784922be3c 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);
> > diff --git a/security/landlock/audit.c b/security/landlock/audit.c
> > index e899995f1fd5..0645304e0375 100644
> > --- a/security/landlock/audit.c
> > +++ b/security/landlock/audit.c
> > @@ -37,6 +37,12 @@ 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_STREAM)] =
> > +		"fs.resolve_unix_stream",
> > +	[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM)] =
> > +		"fs.resolve_unix_dgram",
> > +	[BIT_INDEX(LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)] =
> > +		"fs.resolve_unix_seqpacket",
> >  };
> >  
> >  static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS);
> > diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> > index 8205673c8b1c..94f5fc7ee9fd 100644
> > --- a/security/landlock/fs.c
> > +++ b/security/landlock/fs.c
> > @@ -9,6 +9,7 @@
> >   * Copyright © 2023-2024 Google LLC
> >   */
> >  
> > +#include "linux/net.h"
> >  #include <asm/ioctls.h>
> >  #include <kunit/test.h>
> >  #include <linux/atomic.h>
> > @@ -314,7 +315,10 @@ 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_STREAM | \
> > +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM | \
> > +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)
> >  /* clang-format on */
> >  
> >  /*
> > @@ -1588,6 +1592,33 @@ static int hook_path_truncate(const struct path *const path)
> >  	return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
> >  }
> >  
> > +static int hook_unix_path_connect(const struct path *const path, int type,
> > +				  int flags)
> > +{
> > +	access_mask_t access_request = 0;
> > +
> > +	/* Lookup for the purpose of saving coredumps is OK. */
> > +	if (flags & SOCK_COREDUMP)
> > +		return 0;
> > +
> > +	switch (type) {
> > +	case SOCK_STREAM:
> > +		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_STREAM;
> > +		break;
> > +	case SOCK_DGRAM:
> > +		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM;
> > +		break;
> > +	case SOCK_SEQPACKET:
> > +		access_request = LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET;
> > +		break;
> > +	}
> > +
> > +	if (!access_request)
> > +		return 0;
> > +
> > +	return current_check_access_path(path, access_request);
> > +}
> > +
> >  /* File hooks */
> >  
> >  /**
> > @@ -1872,6 +1903,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_path_connect, hook_unix_path_connect),
> >  
> >  	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 65b5ff051674..1f6f864afec2 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_SEQPACKET
> >  #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 0116e9f93ffe..66fd196be85a 100644
> > --- a/security/landlock/syscalls.c
> > +++ b/security/landlock/syscalls.c
> > @@ -161,7 +161,7 @@ static const struct file_operations ruleset_fops = {
> >   * Documentation/userspace-api/landlock.rst should be updated to reflect the
> >   * UAPI change.
> >   */
> > -const int landlock_abi_version = 7;
> > +const int landlock_abi_version = 8;
> >  
> >  /**
> >   * 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 7b69002239d7..f4b1a275d8d9 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(7, landlock_create_ruleset(NULL, 0,
> > +	ASSERT_EQ(8, 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..0cbde65e032a 100644
> > --- a/tools/testing/selftests/landlock/fs_test.c
> > +++ b/tools/testing/selftests/landlock/fs_test.c
> > @@ -575,9 +575,12 @@ 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_STREAM | \
> > +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_DGRAM | \
> > +	LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET)
> >  
> > -#define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL_DEV
> > +#define ACCESS_LAST LANDLOCK_ACCESS_FS_RESOLVE_UNIX_SEQPACKET
> >  
> >  #define ACCESS_ALL ( \
> >  	ACCESS_FILE | \
> 

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2026-01-19 11:50 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-10 14:32 [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Günther Noack
2026-01-10 14:32 ` [PATCH v2 1/5] lsm: Add hook unix_path_connect Günther Noack
2026-01-10 16:45   ` Justin Suess
2026-01-11  9:55     ` Günther Noack
2026-01-13 22:51     ` Paul Moore
2026-01-13 23:30       ` Paul Moore
2026-01-13  9:34   ` Christian Brauner
2026-01-13 23:27     ` Paul Moore
2026-01-15 10:10       ` Günther Noack
2026-01-15 21:24         ` Demi Marie Obenour
2026-01-15 22:32           ` Günther Noack
2026-01-15 21:46         ` Paul Moore
2026-01-10 14:32 ` [PATCH v2 2/5] landlock: Control pathname UNIX domain socket resolution by path Günther Noack
2026-01-12 15:38   ` Justin Suess
2026-01-19 11:43     ` Mickaël Salaün
2026-01-10 14:33 ` [PATCH v2 3/5] samples/landlock: Add support for named UNIX domain socket restrictions Günther Noack
2026-01-11  9:50   ` Günther Noack
2026-01-10 14:33 ` [PATCH v2 4/5] landlock/selftests: Test " Günther Noack
2026-01-10 14:33 ` [PATCH v2 5/5] landlock: Document FS access rights for pathname UNIX sockets Günther Noack
2026-01-12 16:08 ` [PATCH v2 0/5] landlock: Pathname-based UNIX connect() control Mickaël Salaün
2026-01-12 20:53   ` Günther Noack
2026-01-17 18:57     ` Justin Suess
2026-01-18 17:44       ` 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