* [PATCH] tomoyo: fix socket permission checks
@ 2026-09-22 15:57 Tetsuo Handa
2026-09-24 0:34 ` kernel test robot
0 siblings, 1 reply; 2+ messages in thread
From: Tetsuo Handa @ 2026-09-22 15:57 UTC (permalink / raw)
To: LKML; +Cc: Matthieu Buffet
This is a squashed patch addressing three problems.
[PATCH 1/3] tomoyo: Enforce connect policy in TCP Fast Open
Tomoyo restricted TCP connections in 2011 in commit
059d84dbb389 ("TOMOYO: Add socket operation restriction support.")
using the socket_connect() LSM hook.
However, the MSG_FASTOPEN sendmsg() flag was added in 2012 to allow
combining connect() and the first sendmsg(). Tomoyo was not updated to
take this into account in its send hook.
This resulted in a TCP connect policy bypass similar to that reported in
Landlock in 2024 (see Link below), with the difference that Tomoyo was
fine when originally merged, and the problem got introduced when adding
fastopen support, possibly due to lack of synchronization between lsm
and netdev worlds.
Add MSG_FASTOPEN handling in Tomoyo's existing send hook.
Link: https://github.com/landlock-lsm/linux/issues/41
Link: https://lore.kernel.org/all/20260616201615.275032-1-hexlabsecurity@proton.me/
Fixes: cf60af03ca4e ("net-tcp: Fast Open client - sendmsg(MSG_FASTOPEN)")
Cc: stable@kernel.org
Signed-off-by: Matthieu Buffet <matthieu@buffet.re>
[penguin-kernel: Modified to use tomoyo_sock_family() in order to exempt
kernel services. Also, modified not to check sk->sk_protocol because
conditions to check became too complicated and error prone because of
the second patch.]
[PATCH 2/3] tomoyo: Handle SMC socket
During the sashiko's review on the first patch, sashiko pointed out that
TOMOYO is not checking PF_SMC sockets. If a socket was created using
socket(PF_SMC, SOCK_STREAM) instead of socket(PF_INET, SOCK_STREAM),
tomoyo_sock_family() was returning 0 despite PF_SMC sockets can communicate
like PF_INET socket. Check permissions on PF_SMC sockets, by adding PF_SMC
to tomoyo_sock_family() and tomoyo_socket_sendmsg_permission().
Link: https://sashiko.dev/#/patchset/20260619002207.61104-1-matthieu%40buffet.re
[PATCH 3/3] tomoyo: Handle SCTP socket
During the sashiko's review on the first patch, sashiko pointed out that
TOMOYO is not checking SCTP sockets. Implement sctp_bind_connect callback,
using selinux_sctp_bind_connect() as template. Since sctp_bind_connect
callback receives pointer to "struct sock", update existing socket hooks
to receive pointer to "struct sock". Also, extend policy profile structure
because SCTP allows socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP).
Link: https://sashiko.dev/#/patchset/20260619002207.61104-1-matthieu%40buffet.re
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
security/tomoyo/common.c | 3 ++
security/tomoyo/common.h | 12 +++----
security/tomoyo/network.c | 52 ++++++++++++++++------------
security/tomoyo/tomoyo.c | 73 +++++++++++++++++++++++++++++++++++++--
security/tomoyo/util.c | 3 ++
5 files changed, 112 insertions(+), 31 deletions(-)
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index fdaeaff01fc1..d645a17d7348 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -54,6 +54,9 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send",
[TOMOYO_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind",
[TOMOYO_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send",
+ [TOMOYO_MAC_NETWORK_INET_SEQPACKET_BIND] = "inet_seqpacket_bind",
+ [TOMOYO_MAC_NETWORK_INET_SEQPACKET_LISTEN] = "inet_seqpacket_listen",
+ [TOMOYO_MAC_NETWORK_INET_SEQPACKET_CONNECT] = "inet_seqpacket_connect",
[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind",
[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen",
[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect",
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index d098cf8aae61..6db83be62077 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -354,6 +354,9 @@ enum tomoyo_mac_index {
TOMOYO_MAC_NETWORK_INET_DGRAM_SEND,
TOMOYO_MAC_NETWORK_INET_RAW_BIND,
TOMOYO_MAC_NETWORK_INET_RAW_SEND,
+ TOMOYO_MAC_NETWORK_INET_SEQPACKET_BIND,
+ TOMOYO_MAC_NETWORK_INET_SEQPACKET_LISTEN,
+ TOMOYO_MAC_NETWORK_INET_SEQPACKET_CONNECT,
TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND,
TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN,
TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT,
@@ -1023,13 +1026,10 @@ int tomoyo_path_perm(const u8 operation, const struct path *path,
const char *target);
__poll_t tomoyo_poll_control(struct file *file, poll_table *wait);
__poll_t tomoyo_poll_log(struct file *file, poll_table *wait);
-int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
- int addr_len);
-int tomoyo_socket_connect_permission(struct socket *sock,
- struct sockaddr *addr, int addr_len);
+int tomoyo_socket_bind_permission(struct sock *sk, struct sockaddr *addr, int addr_len);
+int tomoyo_socket_connect_permission(struct sock *sk, struct sockaddr *addr, int addr_len);
int tomoyo_socket_listen_permission(struct socket *sock);
-int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
- int size);
+int tomoyo_socket_sendmsg_permission(struct sock *sk, struct msghdr *msg, int size);
int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
__must_hold_shared(&tomoyo_ss)
__printf(2, 3);
diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c
index cfc2a019de1e..938e10613bb5 100644
--- a/security/tomoyo/network.c
+++ b/security/tomoyo/network.c
@@ -152,6 +152,11 @@ static const u8 tomoyo_inet2mac
[TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_RAW_BIND,
[TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_RAW_SEND,
},
+ [SOCK_SEQPACKET] = {
+ [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_SEQPACKET_BIND,
+ [TOMOYO_NETWORK_LISTEN] = TOMOYO_MAC_NETWORK_INET_SEQPACKET_LISTEN,
+ [TOMOYO_NETWORK_CONNECT] = TOMOYO_MAC_NETWORK_INET_SEQPACKET_CONNECT,
+ },
};
/*
@@ -636,6 +641,7 @@ static u8 tomoyo_sock_family(struct sock *sk)
switch (family) {
case PF_INET:
case PF_INET6:
+ case PF_SMC:
case PF_UNIX:
return family;
default:
@@ -680,18 +686,17 @@ int tomoyo_socket_listen_permission(struct socket *sock)
/**
* tomoyo_socket_connect_permission - Check permission for setting the remote address of a socket.
*
- * @sock: Pointer to "struct socket".
+ * @sk: Pointer to "struct sock".
* @addr: Pointer to "struct sockaddr".
* @addr_len: Size of @addr.
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_socket_connect_permission(struct socket *sock,
- struct sockaddr *addr, int addr_len)
+int tomoyo_socket_connect_permission(struct sock *sk, struct sockaddr *addr, int addr_len)
{
struct tomoyo_addr_info address;
- const u8 family = tomoyo_sock_family(sock->sk);
- const unsigned int type = sock->type;
+ const u8 family = tomoyo_sock_family(sk);
+ const unsigned int type = sk->sk_type;
if (!family)
return 0;
@@ -710,25 +715,23 @@ int tomoyo_socket_connect_permission(struct socket *sock,
}
if (family == PF_UNIX)
return tomoyo_check_unix_address(addr, addr_len, &address);
- return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
- &address);
+ return tomoyo_check_inet_address(addr, addr_len, sk->sk_protocol, &address);
}
/**
* tomoyo_socket_bind_permission - Check permission for setting the local address of a socket.
*
- * @sock: Pointer to "struct socket".
+ * @sk: Pointer to "struct sock".
* @addr: Pointer to "struct sockaddr".
* @addr_len: Size of @addr.
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
- int addr_len)
+int tomoyo_socket_bind_permission(struct sock *sk, struct sockaddr *addr, int addr_len)
{
struct tomoyo_addr_info address;
- const u8 family = tomoyo_sock_family(sock->sk);
- const unsigned int type = sock->type;
+ const u8 family = tomoyo_sock_family(sk);
+ const unsigned int type = sk->sk_type;
if (!family)
return 0;
@@ -745,28 +748,33 @@ int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
}
if (family == PF_UNIX)
return tomoyo_check_unix_address(addr, addr_len, &address);
- return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
- &address);
+ return tomoyo_check_inet_address(addr, addr_len, sk->sk_protocol, &address);
}
/**
* tomoyo_socket_sendmsg_permission - Check permission for sending a datagram.
*
- * @sock: Pointer to "struct socket".
+ * @sk: Pointer to "struct sock".
* @msg: Pointer to "struct msghdr".
* @size: Unused.
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
- int size)
+int tomoyo_socket_sendmsg_permission(struct sock *sk, struct msghdr *msg, int size)
{
struct tomoyo_addr_info address;
- const u8 family = tomoyo_sock_family(sock->sk);
- const unsigned int type = sock->type;
+ const u8 family = tomoyo_sock_family(sk);
+ const unsigned int type = sk->sk_type;
- if (!msg->msg_name || !family ||
- (type != SOCK_DGRAM && type != SOCK_RAW))
+ if (!msg->msg_name || !family)
+ return 0;
+ if ((msg->msg_flags & MSG_FASTOPEN) && type == SOCK_STREAM && family != PF_UNIX) {
+ address.protocol = SOCK_STREAM;
+ address.operation = TOMOYO_NETWORK_CONNECT;
+ return tomoyo_check_inet_address((struct sockaddr *)msg->msg_name,
+ msg->msg_namelen, 0, &address);
+ }
+ if (type != SOCK_DGRAM && type != SOCK_RAW)
return 0;
address.protocol = type;
address.operation = TOMOYO_NETWORK_SEND;
@@ -776,5 +784,5 @@ int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
msg->msg_namelen, &address);
return tomoyo_check_inet_address((struct sockaddr *) msg->msg_name,
msg->msg_namelen,
- sock->sk->sk_protocol, &address);
+ sk->sk_protocol, &address);
}
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index c66e02ed8ee3..2968a8ce14e1 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -8,6 +8,7 @@
#include <linux/lsm_hooks.h>
#include <uapi/linux/lsm.h>
#include "common.h"
+#include <linux/sctp.h>
/**
* tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
@@ -468,7 +469,7 @@ static int tomoyo_socket_listen(struct socket *sock, int backlog)
static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr,
int addr_len)
{
- return tomoyo_socket_connect_permission(sock, addr, addr_len);
+ return tomoyo_socket_connect_permission(sock->sk, addr, addr_len);
}
/**
@@ -483,7 +484,7 @@ static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr,
static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr,
int addr_len)
{
- return tomoyo_socket_bind_permission(sock, addr, addr_len);
+ return tomoyo_socket_bind_permission(sock->sk, addr, addr_len);
}
/**
@@ -498,7 +499,72 @@ static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr,
static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
- return tomoyo_socket_sendmsg_permission(sock, msg, size);
+ return tomoyo_socket_sendmsg_permission(sock->sk, msg, size);
+}
+
+/**
+ * tomoyo_sctp_bind_connect - Check permission for sctp's bind or connext.
+ *
+ * @sk: Pointer to "struct sock".
+ * @optname: Type of operation.
+ * @address: Pointer to "struct sockaddr".
+ * @addrlen: Size of @address.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_sctp_bind_connect(struct sock *sk, int optname, struct sockaddr *address,
+ int addrlen)
+{
+ int len, err, walk_size = 0;
+ void *addr_buf;
+ struct sockaddr *addr;
+
+ /* Process one or more addresses that may be IPv4 or IPv6 */
+ addr_buf = address;
+
+ while (walk_size < addrlen) {
+ if (walk_size + sizeof(sa_family_t) > addrlen)
+ return -EINVAL;
+
+ addr = addr_buf;
+ switch (addr->sa_family) {
+ case AF_INET:
+ len = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ len = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (walk_size + len > addrlen)
+ return -EINVAL;
+
+ switch (optname) {
+ /* Bind checks */
+ case SCTP_PRIMARY_ADDR:
+ case SCTP_SET_PEER_PRIMARY_ADDR:
+ case SCTP_SOCKOPT_BINDX_ADD:
+ err = tomoyo_socket_bind_permission(sk, addr, len);
+ if (err)
+ return err;
+ break;
+ /* Connect checks */
+ case SCTP_SOCKOPT_CONNECTX:
+ case SCTP_PARAM_SET_PRIMARY:
+ case SCTP_PARAM_ADD_IP:
+ case SCTP_SENDMSG_CONNECT:
+ err = tomoyo_socket_connect_permission(sk, addr, len);
+ if (err)
+ return err;
+ break;
+ }
+
+ addr_buf += len;
+ walk_size += len;
+ }
+
+ return 0;
}
struct lsm_blob_sizes tomoyo_blob_sizes __ro_after_init = {
@@ -583,6 +649,7 @@ static struct security_hook_list tomoyo_hooks[] __ro_after_init = {
LSM_HOOK_INIT(socket_connect, tomoyo_socket_connect),
LSM_HOOK_INIT(socket_listen, tomoyo_socket_listen),
LSM_HOOK_INIT(socket_sendmsg, tomoyo_socket_sendmsg),
+ LSM_HOOK_INIT(sctp_bind_connect, tomoyo_sctp_bind_connect),
};
/* Lock for GC. */
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index 6799b1122c9d..b27b7036e860 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -60,6 +60,9 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
TOMOYO_MAC_CATEGORY_NETWORK,
[TOMOYO_MAC_NETWORK_INET_RAW_SEND] =
TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_SEQPACKET_BIND] = TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_SEQPACKET_LISTEN] = TOMOYO_MAC_CATEGORY_NETWORK,
+ [TOMOYO_MAC_NETWORK_INET_SEQPACKET_CONNECT] = TOMOYO_MAC_CATEGORY_NETWORK,
[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] =
TOMOYO_MAC_CATEGORY_NETWORK,
[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] =
--
2.52.0
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] tomoyo: fix socket permission checks
2026-09-22 15:57 [PATCH] tomoyo: fix socket permission checks Tetsuo Handa
@ 2026-09-24 0:34 ` kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2026-09-24 0:34 UTC (permalink / raw)
To: Tetsuo Handa, LKML; +Cc: oe-kbuild-all, Matthieu Buffet
Hi Tetsuo,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v7.3-rc4 next-20260922]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Tetsuo-Handa/tomoyo-fix-socket-permission-checks/20260923-005744
base: linus/master
patch link: https://lore.kernel.org/r/db497449-b16b-4a61-9f06-fbbe7a3dcc73%40I-love.SAKURA.ne.jp
patch subject: [PATCH] tomoyo: fix socket permission checks
config: i386-randconfig-1300-20260924 (https://download.01.org/0day-ci/archive/20260924/202609240841.x5ug9vqH-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
sparse: v0.6.5-rc1
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260924/202609240841.x5ug9vqH-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202609240841.x5ug9vqH-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> security/tomoyo/tomoyo.c:554:22: sparse: sparse: restricted __be16 degrades to integer
security/tomoyo/tomoyo.c:555:22: sparse: sparse: restricted __be16 degrades to integer
vim +554 security/tomoyo/tomoyo.c
504
505 /**
506 * tomoyo_sctp_bind_connect - Check permission for sctp's bind or connext.
507 *
508 * @sk: Pointer to "struct sock".
509 * @optname: Type of operation.
510 * @address: Pointer to "struct sockaddr".
511 * @addrlen: Size of @address.
512 *
513 * Returns 0 on success, negative value otherwise.
514 */
515 static int tomoyo_sctp_bind_connect(struct sock *sk, int optname, struct sockaddr *address,
516 int addrlen)
517 {
518 int len, err, walk_size = 0;
519 void *addr_buf;
520 struct sockaddr *addr;
521
522 /* Process one or more addresses that may be IPv4 or IPv6 */
523 addr_buf = address;
524
525 while (walk_size < addrlen) {
526 if (walk_size + sizeof(sa_family_t) > addrlen)
527 return -EINVAL;
528
529 addr = addr_buf;
530 switch (addr->sa_family) {
531 case AF_INET:
532 len = sizeof(struct sockaddr_in);
533 break;
534 case AF_INET6:
535 len = sizeof(struct sockaddr_in6);
536 break;
537 default:
538 return -EINVAL;
539 }
540 if (walk_size + len > addrlen)
541 return -EINVAL;
542
543 switch (optname) {
544 /* Bind checks */
545 case SCTP_PRIMARY_ADDR:
546 case SCTP_SET_PEER_PRIMARY_ADDR:
547 case SCTP_SOCKOPT_BINDX_ADD:
548 err = tomoyo_socket_bind_permission(sk, addr, len);
549 if (err)
550 return err;
551 break;
552 /* Connect checks */
553 case SCTP_SOCKOPT_CONNECTX:
> 554 case SCTP_PARAM_SET_PRIMARY:
555 case SCTP_PARAM_ADD_IP:
556 case SCTP_SENDMSG_CONNECT:
557 err = tomoyo_socket_connect_permission(sk, addr, len);
558 if (err)
559 return err;
560 break;
561 }
562
563 addr_buf += len;
564 walk_size += len;
565 }
566
567 return 0;
568 }
569
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-24 0:35 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-22 15:57 [PATCH] tomoyo: fix socket permission checks Tetsuo Handa
2026-09-24 0:34 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®