git: 08cda4bcd43c - main - ktls: Add a tunable to disable TLS receive

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 01 Jul 2026 00:55:03 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=08cda4bcd43cfcb2c0b1abd29bc7cd30896727bc

commit 08cda4bcd43cfcb2c0b1abd29bc7cd30896727bc
Author:     Andrew Gallatin <gallatin@FreeBSD.org>
AuthorDate: 2026-07-01 00:53:15 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-07-01 00:54:02 +0000

    ktls: Add a tunable to disable TLS receive
    
    TLS receive offload is really only beneficial for in-kernel use cases
    (such as NFS over TLS) or when using a hardware offload.  In addition,
    several recent SAs have involved the TLS receive path, but the only
    current mitigation for those is to disable TLS offload entirely.
    
    Reviewed by:    ziaee, gallatin, markj
    Relnotes:       yes
    Sponsored by:   Netflix
    Sponsored by:   Chelsio Communications
    Co-authored-by: John Baldwin <jhb@FreeBSD.org>
    Differential Revision:  https://reviews.freebsd.org/D57974
---
 share/man/man4/ktls.4      |  4 ++-
 sys/kern/uipc_ktls.c       |  7 +++-
 tests/sys/kern/ktls_test.c | 90 +++++++++++++++++++++++++++++-----------------
 3 files changed, 67 insertions(+), 34 deletions(-)

diff --git a/share/man/man4/ktls.4 b/share/man/man4/ktls.4
index 56b03d45faf7..5fca616dae4d 100644
--- a/share/man/man4/ktls.4
+++ b/share/man/man4/ktls.4
@@ -29,7 +29,7 @@
 .\"
 .\" * Other names and brands may be claimed as the property of others.
 .\"
-.Dd October 31, 2024
+.Dd June 30, 2026
 .Dt KTLS 4
 .Os
 .Sh NAME
@@ -182,6 +182,8 @@ A few of them are described below:
 .Bl -tag -width ".Va kern.ipc.tls.cbc_enable"
 .It Va kern.ipc.tls.enable
 Determines if new kernel TLS sessions can be created.
+.It Va kern.ipc.tls.rx_enable
+Determines if new kernel TLS receive sessions can be created.
 .It Va kern.ipc.tls.cbc_enable
 Determines if new kernel TLS sessions with a cipher suite using AES-CBC
 can be created.
diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c
index 629fe8923466..0966c930ca0f 100644
--- a/sys/kern/uipc_ktls.c
+++ b/sys/kern/uipc_ktls.c
@@ -148,6 +148,11 @@ SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, enable, CTLFLAG_RWTUN,
     &ktls_offload_enable, 0,
     "Enable support for kernel TLS offload");
 
+static bool ktls_rx_offload_enable = true;
+SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, rx_enable, CTLFLAG_RWTUN,
+    &ktls_rx_offload_enable, 0,
+    "Enable support for kernel TLS receive offload");
+
 static bool ktls_cbc_enable = true;
 SYSCTL_BOOL(_kern_ipc_tls, OID_AUTO, cbc_enable, CTLFLAG_RWTUN,
     &ktls_cbc_enable, 1,
@@ -1285,7 +1290,7 @@ ktls_enable_rx(struct socket *so, struct tls_enable *en)
 	struct ktls_session *tls;
 	int error;
 
-	if (!ktls_offload_enable)
+	if (!ktls_offload_enable || !ktls_rx_offload_enable)
 		return (ENOTSUP);
 
 	counter_u64_add(ktls_offload_enable_calls, 1);
diff --git a/tests/sys/kern/ktls_test.c b/tests/sys/kern/ktls_test.c
index 7003b86fb4e2..e0bcf17262f2 100644
--- a/tests/sys/kern/ktls_test.c
+++ b/tests/sys/kern/ktls_test.c
@@ -69,6 +69,28 @@ require_ktls(void)
 
 #define	ATF_REQUIRE_KTLS()	require_ktls()
 
+static void
+require_ktls_rx(void)
+{
+	size_t len;
+	bool enable;
+
+	ATF_REQUIRE_KTLS();
+
+	len = sizeof(enable);
+	if (sysctlbyname("kern.ipc.tls.rx_enable", &enable, &len, NULL, 0) ==
+	    -1) {
+		if (errno == ENOENT)
+			atf_tc_skip("kernel does not support TLS offload");
+		atf_libc_error(errno, "Failed to read kern.ipc.tls.rx_enable");
+	}
+
+	if (!enable)
+		atf_tc_skip("Kernel TLS receive is disabled");
+}
+
+#define	ATF_REQUIRE_KTLS_RX()	require_ktls_rx()
+
 static void
 check_tls_mode(const atf_tc_t *tc, int s, int sockopt)
 {
@@ -2286,7 +2308,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_##name, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2306,7 +2328,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_bad_data, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2326,7 +2348,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_bad_mac, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2346,7 +2368,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_truncated_record, tc)		\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2366,7 +2388,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_bad_major, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2386,7 +2408,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_bad_minor, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2406,7 +2428,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_##name, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2426,7 +2448,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_split_##name, tc)		\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2622,7 +2644,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_bad_padding, tc)		\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2679,7 +2701,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_bad_iv, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2722,7 +2744,7 @@ ATF_TC_BODY(ktls_receive_##cipher_name##_bad_type, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2781,7 +2803,7 @@ ATF_TC_BODY(ktls_receive_invalid_##name, tc)				\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2820,7 +2842,7 @@ ATF_TC_BODY(ktls_receive_unsupported_##name, tc)			\
 	struct tls_enable en;						\
 	uint64_t seqno;							\
 									\
-	ATF_REQUIRE_KTLS();						\
+	ATF_REQUIRE_KTLS_RX();						\
 	seqno = random();						\
 	build_tls_enable(tc, cipher_alg, key_size, auth_alg, minor,	\
 	    seqno, &en);						\
@@ -2881,29 +2903,18 @@ ATF_TC_BODY(ktls_sendto_baddst, tc)
  * Make sure that listen(2) returns an error for KTLS-enabled sockets, and
  * verify that an attempt to enable KTLS on a listening socket fails.
  */
-ATF_TC_WITHOUT_HEAD(ktls_listening_socket);
-ATF_TC_BODY(ktls_listening_socket, tc)
+static void
+ktls_listening_socket(const atf_tc_t *tc, int optname)
 {
 	struct tls_enable en;
 	struct sockaddr_in sin;
 	int s;
 
-	ATF_REQUIRE_KTLS();
-
-	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-	ATF_REQUIRE(s >= 0);
-	build_tls_enable(tc, CRYPTO_AES_NIST_GCM_16, 128 / 8, 0,
-	    TLS_MINOR_VER_THREE, (uint64_t)random(), &en);
-	ATF_REQUIRE(setsockopt(s, IPPROTO_TCP, TCP_TXTLS_ENABLE, &en,
-	    sizeof(en)) == 0);
-	ATF_REQUIRE_ERRNO(EINVAL, listen(s, 1) == -1);
-	ATF_REQUIRE(close(s) == 0);
-
 	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 	ATF_REQUIRE(s >= 0);
 	build_tls_enable(tc, CRYPTO_AES_NIST_GCM_16, 128 / 8, 0,
 	    TLS_MINOR_VER_THREE, (uint64_t)random(), &en);
-	ATF_REQUIRE(setsockopt(s, IPPROTO_TCP, TCP_RXTLS_ENABLE, &en,
+	ATF_REQUIRE(setsockopt(s, IPPROTO_TCP, optname, &en,
 	    sizeof(en)) == 0);
 	ATF_REQUIRE_ERRNO(EINVAL, listen(s, 1) == -1);
 	ATF_REQUIRE(close(s) == 0);
@@ -2918,12 +2929,26 @@ ATF_TC_BODY(ktls_listening_socket, tc)
 	build_tls_enable(tc, CRYPTO_AES_NIST_GCM_16, 128 / 8, 0,
 	    TLS_MINOR_VER_THREE, (uint64_t)random(), &en);
 	ATF_REQUIRE_ERRNO(ENOTCONN,
-	    setsockopt(s, IPPROTO_TCP, TCP_TXTLS_ENABLE, &en, sizeof(en)) != 0);
-	ATF_REQUIRE_ERRNO(ENOTCONN,
-	    setsockopt(s, IPPROTO_TCP, TCP_RXTLS_ENABLE, &en, sizeof(en)) != 0);
+	    setsockopt(s, IPPROTO_TCP, optname, &en, sizeof(en)) != 0);
 	ATF_REQUIRE(close(s) == 0);
 }
 
+ATF_TC_WITHOUT_HEAD(ktls_listening_socket_tx);
+ATF_TC_BODY(ktls_listening_socket_tx, tc)
+{
+	ATF_REQUIRE_KTLS();
+
+	ktls_listening_socket(tc, TCP_TXTLS_ENABLE);
+}
+
+ATF_TC_WITHOUT_HEAD(ktls_listening_socket_rx);
+ATF_TC_BODY(ktls_listening_socket_rx, tc)
+{
+	ATF_REQUIRE_KTLS_RX();
+
+	ktls_listening_socket(tc, TCP_RXTLS_ENABLE);
+}
+
 /*
  * Verify that the KTLS receive path does not overwrite data belonging
  * to a file whose payload is transmitted over a loopback connection
@@ -2947,7 +2972,7 @@ ATF_TC_BODY(ktls_receive_loopback_sendfile, tc)
 	int mode, shm, sockets[2];
 	socklen_t slen;
 
-	ATF_REQUIRE_KTLS();
+	ATF_REQUIRE_KTLS_RX();
 	seqno = random();
 	build_tls_enable(tc, CRYPTO_AES_NIST_GCM_16, 128 / 8, 0,
 	    TLS_MINOR_VER_TWO, seqno, &en);
@@ -3040,7 +3065,8 @@ ATF_TP_ADD_TCS(tp)
 
 	/* Miscellaneous */
 	ATF_TP_ADD_TC(tp, ktls_sendto_baddst);
-	ATF_TP_ADD_TC(tp, ktls_listening_socket);
+	ATF_TP_ADD_TC(tp, ktls_listening_socket_tx);
+	ATF_TP_ADD_TC(tp, ktls_listening_socket_rx);
 	ATF_TP_ADD_TC(tp, ktls_receive_loopback_sendfile);
 
 	return (atf_no_error());