diff --git a/Documentation/networking/kcm.rst b/Documentation/networking/kcm.rst
index 71f44d0beaa3..07778f29211c 100644
--- a/Documentation/networking/kcm.rst
+++ b/Documentation/networking/kcm.rst
@@ -167,6 +167,9 @@ The kcm_attach structure contains:
- fd: file descriptor for TCP socket being attached
- bpf_prog_fd: file descriptor for compiled BPF program downloaded
+The transport socket must be a TCP stream socket with no TCP ULP installed.
+TLS cannot be enabled on a transport socket while it is attached to KCM.
+
Unattach transport sockets
--------------------------
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index e6b79cf4798f..d4b07fbae2d5 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -516,6 +516,9 @@ struct tcp_sock {
#if IS_ENABLED(CONFIG_MPTCP)
bool is_mptcp;
#endif
+#if IS_ENABLED(CONFIG_AF_KCM)
+ bool kcm_attached;
+#endif
#if IS_ENABLED(CONFIG_SMC)
bool syn_smc; /* SYN includes SMC */
bool (*smc_hs_congested)(const struct sock *sk);diff --git a/include/net/tcp.h b/include/net/tcp.h
index 5c9203aae834..5e99d3142f5e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2882,6 +2882,15 @@ void tcp_cleanup_ulp(struct sock *sk);
void tcp_update_ulp(struct sock *sk, struct proto *p,
void (*write_space)(struct sock *sk));
+static inline bool tcp_kcm_attached(const struct sock *sk)
+{
+#if IS_ENABLED(CONFIG_AF_KCM)
+ return tcp_sk(sk)->kcm_attached;
+#else
+ return false;
+#endif
+}
+
#define MODULE_ALIAS_TCP_ULP(name) \
MODULE_INFO(alias, name); \
MODULE_INFO(alias, "tcp-ulp-" name)diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index a7f94d42036f..ca789812124e 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -30,6 +30,7 @@
#include <net/kcm.h>
#include <net/netns/generic.h>
#include <net/sock.h>
+#include <net/tcp.h>
#include <uapi/linux/kcm.h>
#include <trace/events/sock.h>
@@ -1259,9 +1260,10 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
lock_sock(csk);
- /* Only allow TCP sockets to be attached for now */
- if ((csk->sk_family != AF_INET && csk->sk_family != AF_INET6) ||
- csk->sk_protocol != IPPROTO_TCP) {
+ /* Only allow TCP sockets to be attached for now. A raw socket
+ * created with IPPROTO_TCP has that sk_protocol but no icsk.
+ */
+ if (!sk_is_tcp(csk)) {
err = -EOPNOTSUPP;
goto out;
}@@ -1272,6 +1274,12 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
goto out;
}
+ /* KCM and ULPs cannot share the receive path and socket callbacks. */
+ if (inet_csk_has_ulp(csk)) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
if (!psock) {
err = -ENOMEM;@@ -1305,6 +1313,7 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
psock->save_write_space = csk->sk_write_space;
psock->save_state_change = csk->sk_state_change;
csk->sk_user_data = psock;
+ tcp_sk(csk)->kcm_attached = true;
WRITE_ONCE(csk->sk_data_ready, psock_data_ready);
WRITE_ONCE(csk->sk_write_space, psock_write_space);
csk->sk_state_change = psock_state_change;
@@ -1386,6 +1395,7 @@ static void kcm_unattach(struct kcm_psock *psock)
WRITE_ONCE(csk->sk_write_space, psock->save_write_space);
csk->sk_state_change = psock->save_state_change;
strp_stop(&psock->strp);
+ tcp_sk(csk)->kcm_attached = false;
if (WARN_ON(psock->rx_kcm)) {
write_unlock_bh(&csk->sk_callback_lock);diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index b8d5a843f761..fa71c75c2861 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -1067,6 +1067,9 @@ static int tls_init(struct sock *sk)
if (sk->sk_state != TCP_ESTABLISHED)
return -ENOTCONN;
+ if (tcp_kcm_attached(sk))
+ return -EBUSY;
+
/* allocate tls context */
write_lock_bh(&sk->sk_callback_lock);
ctx = tls_ctx_create(sk);
--
2.50.1