public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Wilfred Mallawa <wilfred.opensource@gmail.com>
To: John Fastabend <john.fastabend@gmail.com>,
	Jakub Kicinski <kuba@kernel.org>,
	Sabrina Dubroca <sd@queasysnail.net>,
	"David S . Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
	Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>
Cc: netdev@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	Alistair Francis <alistair.francis@wdc.com>,
	Damien Le'Moal <dlemoal@kernel.org>,
	Wilfred Mallawa <wilfred.mallawa@wdc.com>
Subject: [RFC net-next 1/3] net/tls_sw: support randomized zero padding
Date: Mon,  9 Mar 2026 15:48:36 +1000	[thread overview]
Message-ID: <20260309054837.2299732-3-wilfred.opensource@gmail.com> (raw)
In-Reply-To: <20260309054837.2299732-2-wilfred.opensource@gmail.com>

From: Wilfred Mallawa <wilfred.mallawa@wdc.com>

Currently, for TLS 1.3, ktls does not support record zero padding [1].
Record zero padding is used to allow the sender to hide the size of the
traffic patterns from an observer. TLS is susceptible to a variety of traffic
analysis attacks based on observing the length and timing of encrypted
packets [2]. Upcoming Western Digital NVMe-TCP hardware controllers
implement TLS 1.3. Which from a security perspective, can benefit from having
record zero padding enabled to mitigate against traffic analysis attacks [2].

Thus, for TX, add support to appending a randomized number of zero padding
bytes to end-of-record (EOR) records that are not full. The number of zero
padding bytes to append is determined by the remaining record room and the
user specified upper bound (minimum of the two). That is
rand([0, min(record_room, upper_bound)]).

For TLS 1.3, zero padding is added after the content type byte, as such,
if the record in context meets the above conditions for zero padding,
attach a zero padding buffer to the content type byte before a record is
encrypted. The padding buffer is freed when the record is freed.

By default, record zero padding is disabled, and userspace may enable it
by using the setsockopt TLS_TX_RANDOM_PAD option.

[1] https://datatracker.ietf.org/doc/html/rfc8446#section-5.4l
[2] https://datatracker.ietf.org/doc/html/rfc8446#appendix-E.3

Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
---
 include/net/tls.h  |  1 +
 net/tls/tls.h      |  6 ++++-
 net/tls/tls_main.c |  2 ++
 net/tls/tls_sw.c   | 58 ++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/include/net/tls.h b/include/net/tls.h
index ebd2550280ae..1feef72cc339 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -229,6 +229,7 @@ struct tls_context {
 	u8 zerocopy_sendfile:1;
 	u8 rx_no_pad:1;
 	u16 tx_max_payload_len;
+	u16 tx_record_zero_pad;
 
 	int (*push_pending_record)(struct sock *sk, int flags);
 	void (*sk_write_space)(struct sock *sk);
diff --git a/net/tls/tls.h b/net/tls/tls.h
index e8f81a006520..3a86eb145332 100644
--- a/net/tls/tls.h
+++ b/net/tls/tls.h
@@ -121,8 +121,12 @@ struct tls_rec {
 	/* AAD | msg_encrypted.sg.data (data contains overhead for hdr & iv & tag) */
 	struct scatterlist sg_aead_out[2];
 
+	/* TLS 1.3 record zero padding */
+	char *zero_padding;
+	u16 zero_padding_len;
+
 	char content_type;
-	struct scatterlist sg_content_type;
+	struct scatterlist sg_content_trail[2];
 
 	struct sock *sk;
 
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index fd39acf41a61..b0702effbc26 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -1076,6 +1076,8 @@ static int tls_init(struct sock *sk)
 	ctx->tx_conf = TLS_BASE;
 	ctx->rx_conf = TLS_BASE;
 	ctx->tx_max_payload_len = TLS_MAX_PAYLOAD_SIZE;
+	/* TX record zero padding is disabled by default */
+	ctx->tx_record_zero_pad = 0;
 	update_sk_prot(sk, ctx);
 out:
 	write_unlock_bh(&sk->sk_callback_lock);
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index a656ce235758..84b167607e1f 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -389,6 +389,7 @@ static void tls_free_rec(struct sock *sk, struct tls_rec *rec)
 {
 	sk_msg_free(sk, &rec->msg_encrypted);
 	sk_msg_free(sk, &rec->msg_plaintext);
+	kfree(rec->zero_padding);
 	kfree(rec);
 }
 
@@ -430,6 +431,7 @@ int tls_tx_records(struct sock *sk, int flags)
 		 */
 		list_del(&rec->list);
 		sk_msg_free(sk, &rec->msg_plaintext);
+		kfree(rec->zero_padding);
 		kfree(rec);
 	}
 
@@ -450,6 +452,7 @@ int tls_tx_records(struct sock *sk, int flags)
 
 			list_del(&rec->list);
 			sk_msg_free(sk, &rec->msg_plaintext);
+			kfree(rec->zero_padding);
 			kfree(rec);
 		} else {
 			break;
@@ -779,12 +782,29 @@ static int tls_push_record(struct sock *sk, int flags,
 	sk_msg_iter_var_prev(i);
 
 	rec->content_type = record_type;
+
 	if (prot->version == TLS_1_3_VERSION) {
-		/* Add content type to end of message.  No padding added */
-		sg_set_buf(&rec->sg_content_type, &rec->content_type, 1);
-		sg_mark_end(&rec->sg_content_type);
+		/*
+		 * Add content type to end of message with zero padding
+		 * if available.
+		 */
+		sg_init_table(rec->sg_content_trail, 2);
+		sg_set_buf(&rec->sg_content_trail[0], &rec->content_type, 1);
+		if (rec->zero_padding_len) {
+			rec->zero_padding = kzalloc(rec->zero_padding_len,
+						    sk->sk_allocation);
+			if (!rec->zero_padding)
+				return -ENOMEM;
+
+			sg_set_buf(&rec->sg_content_trail[1],
+				   rec->zero_padding, rec->zero_padding_len);
+			sg_mark_end(&rec->sg_content_trail[1]);
+		} else {
+			sg_mark_end(&rec->sg_content_trail[0]);
+		}
+
 		sg_chain(msg_pl->sg.data, msg_pl->sg.end + 1,
-			 &rec->sg_content_type);
+			 rec->sg_content_trail);
 	} else {
 		sg_mark_end(sk_msg_elem(msg_pl, i));
 	}
@@ -805,19 +825,21 @@ static int tls_push_record(struct sock *sk, int flags,
 	i = msg_en->sg.start;
 	sg_chain(rec->sg_aead_out, 2, &msg_en->sg.data[i]);
 
-	tls_make_aad(rec->aad_space, msg_pl->sg.size + prot->tail_size,
-		     tls_ctx->tx.rec_seq, record_type, prot);
+	tls_make_aad(rec->aad_space, msg_pl->sg.size + prot->tail_size +
+		     rec->zero_padding_len, tls_ctx->tx.rec_seq,
+		     record_type, prot);
 
 	tls_fill_prepend(tls_ctx,
 			 page_address(sg_page(&msg_en->sg.data[i])) +
 			 msg_en->sg.data[i].offset,
-			 msg_pl->sg.size + prot->tail_size,
-			 record_type);
+			 msg_pl->sg.size + prot->tail_size +
+			 rec->zero_padding_len, record_type);
 
 	tls_ctx->pending_open_record_frags = false;
 
 	rc = tls_do_encryption(sk, tls_ctx, ctx, req,
-			       msg_pl->sg.size + prot->tail_size, i);
+			       msg_pl->sg.size + prot->tail_size +
+			       rec->zero_padding_len, i);
 	if (rc < 0) {
 		if (rc != -EINPROGRESS) {
 			tls_err_abort(sk, -EBADMSG);
@@ -1033,6 +1055,8 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
 	unsigned char record_type = TLS_RECORD_TYPE_DATA;
 	bool is_kvec = iov_iter_is_kvec(&msg->msg_iter);
 	bool eor = !(msg->msg_flags & MSG_MORE);
+	bool tls_13 = (prot->version == TLS_1_3_VERSION);
+	bool rec_zero_pad = eor && tls_13 && tls_ctx->tx_record_zero_pad;
 	size_t try_to_copy;
 	ssize_t copied = 0;
 	struct sk_msg *msg_pl, *msg_en;
@@ -1043,6 +1067,7 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
 	int record_room;
 	int num_zc = 0;
 	int orig_size;
+	int max_zero_pad_len, zero_pad_len = 0;
 	int ret = 0;
 
 	if (!eor && (msg->msg_flags & MSG_EOR))
@@ -1085,8 +1110,19 @@ static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg,
 			full_record = true;
 		}
 
+		if (rec_zero_pad && !full_record)
+			zero_pad_len = record_room - try_to_copy;
+
+		if (zero_pad_len > prot->tail_size) {
+			max_zero_pad_len = min(zero_pad_len,
+					       tls_ctx->tx_record_zero_pad);
+			zero_pad_len =
+				get_random_u32_inclusive(0, max_zero_pad_len);
+			rec->zero_padding_len = zero_pad_len;
+		}
+
 		required_size = msg_pl->sg.size + try_to_copy +
-				prot->overhead_size;
+				prot->overhead_size + rec->zero_padding_len;
 
 		if (!sk_stream_memory_free(sk))
 			goto wait_for_sndbuf;
@@ -2555,6 +2591,7 @@ void tls_sw_release_resources_tx(struct sock *sk)
 				       struct tls_rec, list);
 		list_del(&rec->list);
 		sk_msg_free(sk, &rec->msg_plaintext);
+		kfree(rec->zero_padding);
 		kfree(rec);
 	}
 
@@ -2562,6 +2599,7 @@ void tls_sw_release_resources_tx(struct sock *sk)
 		list_del(&rec->list);
 		sk_msg_free(sk, &rec->msg_encrypted);
 		sk_msg_free(sk, &rec->msg_plaintext);
+		kfree(rec->zero_padding);
 		kfree(rec);
 	}
 
-- 
2.53.0


  reply	other threads:[~2026-03-09  5:54 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-09  5:48 [RFC net-next 0/3] tls_sw: add tx record zero padding Wilfred Mallawa
2026-03-09  5:48 ` Wilfred Mallawa [this message]
2026-03-13 13:16   ` [RFC net-next 1/3] net/tls_sw: support randomized " Sabrina Dubroca
2026-03-14 14:39     ` Jakub Kicinski
2026-03-17  0:53       ` Wilfred Mallawa
2026-03-17  1:03         ` Jakub Kicinski
2026-03-17  1:21           ` Wilfred Mallawa
2026-03-17  1:30             ` Jakub Kicinski
2026-03-17  1:53               ` Wilfred Mallawa
2026-03-19  1:35                 ` Alistair Francis
2026-03-17  9:19           ` Sabrina Dubroca
2026-03-17  0:20     ` Wilfred Mallawa
2026-03-09  5:48 ` [RFC net-next 2/3] net/tls: add randomized zero padding socket option Wilfred Mallawa
2026-03-09  5:48 ` [RFC net-next 3/3] selftest: tls: add tls record zero pad test Wilfred Mallawa
2026-03-13 12:13 ` [RFC net-next 0/3] tls_sw: add tx record zero padding Sabrina Dubroca
2026-03-17  0:59   ` Wilfred Mallawa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260309054837.2299732-3-wilfred.opensource@gmail.com \
    --to=wilfred.opensource@gmail.com \
    --cc=alistair.francis@wdc.com \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=dlemoal@kernel.org \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=john.fastabend@gmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sd@queasysnail.net \
    --cc=skhan@linuxfoundation.org \
    --cc=wilfred.mallawa@wdc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox