]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
lsm: Add LSM hook security_unix_find
authorJustin Suess <utilityemal77@gmail.com>
Fri, 27 Mar 2026 16:48:26 +0000 (17:48 +0100)
committerMickaël Salaün <mic@digikod.net>
Tue, 7 Apr 2026 16:51:05 +0000 (18:51 +0200)
Add an LSM hook security_unix_find.

This hook is called to check the path of a named UNIX socket before a
connection is initiated. The peer socket may be inspected as well.

Why existing hooks are unsuitable:

Existing socket hooks, security_unix_stream_connect(),
security_unix_may_send(), and security_socket_connect() don't provide
TOCTOU-free / namespace independent access to the paths of sockets.

(1) We cannot resolve the path from the struct sockaddr in existing hooks.
This requires another path lookup. A change in the path between the
two lookups will cause a TOCTOU bug.

(2) We cannot use the struct path from the listening socket, because it
may be bound to a path in a different namespace than the caller,
resulting in a path that cannot be referenced at policy creation time.

Consumers of the hook wishing to reference @other are responsible
for acquiring the unix_state_lock and checking for the SOCK_DEAD flag
therein, ensuring the socket hasn't died since lookup.

Cc: Günther Noack <gnoack3000@gmail.com>
Cc: Tingmao Wang <m@maowtm.org>
Cc: Mickaël Salaün <mic@digikod.net>
Cc: Paul Moore <paul@paul-moore.com>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com>
Acked-by: Paul Moore <paul@paul-moore.com>
Link: https://lore.kernel.org/r/20260327164838.38231-2-gnoack3000@gmail.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
include/linux/lsm_hook_defs.h
include/linux/security.h
net/unix/af_unix.c
security/security.c

index 8c42b4bde09c073f6a420c81bc8bc87b2284544d..7a0fd3dbfa29be66e1747941088cb6f9059f3626 100644 (file)
@@ -317,6 +317,11 @@ LSM_HOOK(int, 0, post_notification, const struct cred *w_cred,
 LSM_HOOK(int, 0, watch_key, struct key *key)
 #endif /* CONFIG_SECURITY && CONFIG_KEY_NOTIFICATIONS */
 
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+LSM_HOOK(int, 0, unix_find, const struct path *path, struct sock *other,
+        int flags)
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
 #ifdef CONFIG_SECURITY_NETWORK
 LSM_HOOK(int, 0, unix_stream_connect, struct sock *sock, struct sock *other,
         struct sock *newsk)
index ee88dd2d2d1f715e9c1ff65220e83eacb5d9f167..c2d665cbfcfb386cfc157f5d619101411ef42ea3 100644 (file)
@@ -1932,6 +1932,17 @@ static inline int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
 }
 #endif /* CONFIG_SECURITY_NETWORK */
 
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+
+int security_unix_find(const struct path *path, struct sock *other, int flags);
+
+#else /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+static inline int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+       return 0;
+}
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
 #ifdef CONFIG_SECURITY_INFINIBAND
 int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey);
 int security_ib_endport_manage_subnet(void *sec, const char *name, u8 port_num);
index b23c33df8b4654188f7d412a39f6f541d859a7dc..a5a55a49058d4638b6025915294130b4c0af210e 100644 (file)
@@ -1231,11 +1231,15 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
                goto path_put;
 
        err = -EPROTOTYPE;
-       if (sk->sk_type == type)
-               touch_atime(&path);
-       else
+       if (sk->sk_type != type)
                goto sock_put;
 
+       err = security_unix_find(&path, sk, flags);
+       if (err)
+               goto sock_put;
+
+       touch_atime(&path);
+
        path_put(&path);
 
        return sk;
index a26c1474e2e499b81c3a3285f52f3c14c8bae4ec..687fc486de9d80097c4d194ae3dcc79f954b06f5 100644 (file)
@@ -4732,6 +4732,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
 
 #endif /* CONFIG_SECURITY_NETWORK */
 
+#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
+/**
+ * security_unix_find() - Check if a named AF_UNIX socket can connect
+ * @path: path of the socket being connected to
+ * @other: peer sock
+ * @flags: flags associated with the socket
+ *
+ * This hook is called to check permissions before connecting to a named
+ * AF_UNIX socket. The caller does not hold any locks on @other.
+ *
+ * Return: Returns 0 if permission is granted.
+ */
+int security_unix_find(const struct path *path, struct sock *other, int flags)
+{
+       return call_int_hook(unix_find, path, other, flags);
+}
+EXPORT_SYMBOL(security_unix_find);
+
+#endif /* CONFIG_SECURITY_NETWORK && CONFIG_SECURITY_PATH */
+
 #ifdef CONFIG_SECURITY_INFINIBAND
 /**
  * security_ib_pkey_access() - Check if access to an IB pkey is allowed