Re: AppArmor: TCP Fast Open bypasses connect mediation (last unaddressed LSM)
From: John Johansen
Date: Tue Jun 23 2026 - 03:15:21 EST
On 6/18/26 18:11, Bryam Vargas wrote:
Hello John, and LSM folks,If you have a patch, I'd love to take it and give you the credit other wise I can
I have been working on the Landlock TCP Fast Open connect bypass [1]. Stephen
Smalley's SELinux fix for the same issue [3] -- "Similar to Landlock, SELinux was
not updated when TCP Fast Open support was introduced ..." -- made me go back and
check the rest of the connect-mediating LSMs, since I had only been looking at
Landlock. With Landlock [2], SELinux [3], and now TOMOYO [4] all getting fixes,
AppArmor is the last one with the same gap and no fix yet.
Root cause (shared with the others)
-----------------------------------
security_socket_connect() has a single call site, net/socket.c (the connect(2)
syscall). TCP Fast Open performs an implicit connect inside sendmsg:
tcp_sendmsg -> tcp_sendmsg_fastopen -> __inet_stream_connect(..., is_sendmsg=1)
-> sk->sk_prot->connect() net/ipv4/{tcp.c,af_inet.c}
This never calls security_socket_connect(); the only LSM hook on the path is
security_socket_sendmsg(). mptcp_sendmsg_fastopen reaches the same code and is a
second producer.
AppArmor
--------
apparmor_socket_connect() requests AA_MAY_CONNECT; apparmor_socket_sendmsg() (via
aa_sock_msg_perm) requests AA_MAY_SEND. These are distinct bits, and apparmor_parser
compiles them independently: "network send inet stream," yields accept mask 0x02
while "network connect inet stream," yields 0x40. So an egress-restriction profile
that grants send but not connect is bypassed by MSG_FASTOPEN.
Reproduced on 6.12.88 with apparmor active. Under a profile granting the inet/inet6
stream lifecycle except connect:
aa-exec -p egress_restricted -- ./probe
[TCP ] connect(2)=EACCES(blocked) sendto(MSG_FASTOPEN)=OK(reached) => connection established
[TCP6] connect(2)=EACCES(blocked) sendto(MSG_FASTOPEN)=OK(reached) => connection established
(The coarse "network inet stream," idiom grants connect anyway, so this only bites the
fine-grained "allow send, deny connect" policy that the asymmetry is meant to serve.)
Fix
---
Same shape as the TOMOYO [4] and SELinux [3] fixes: in apparmor_socket_sendmsg (or
aa_sock_msg_perm), when MSG_FASTOPEN is set and msg_name carries a destination on a
not-yet-connected stream socket, additionally require aa_sk_perm(OP_CONNECT,
AA_MAY_CONNECT, sk). I am happy to send that patch and the reproducer.
throw it together.
(A single core check in __inet_stream_connect(), gated on is_sendmsg, would haveI think per LSM makes sense, at least atm, as it is probably easier. We can look
covered all five LSMs and both the TCP and MPTCP producers in one place -- the kernel
already mediates the analogous implicit-connect-on-send for AF_UNIX via
security_unix_may_send and for SCTP via security_sctp_bind_connect. But since the
other four LSMs are taking per-hook fixes, AppArmor matching them is the consistent
move; mentioning the core option only in case it is preferred.)
at refactoring after the fact.
[1] Landlock: LANDLOCK_ACCESS_NET_CONNECT_TCP bypass via TCP Fast Open (report)Thanks for the detailed report Bryan
https://lore.kernel.org/r/20260616201615.275032-1-hexlabsecurity@xxxxxxxxx
[2] landlock: fix TCP Fast Open connection bypass (Matthieu Buffet)
https://lore.kernel.org/r/20260617180526.15627-2-matthieu@xxxxxxxxx
[3] selinux: check connect-related permissions on TCP Fast Open (Stephen Smalley)
https://lore.kernel.org/r/20260618175513.112443-2-stephen.smalley.work@xxxxxxxxx
[4] tomoyo: Enforce connect policy in TCP Fast Open (Matthieu Buffet)
https://lore.kernel.org/r/20260619002207.61104-1-matthieu@xxxxxxxxx
Thanks,
Bryam Vargas