Skip to contentSkip to conversation

net/tls: Consume empty data records in tls_sw_read_sock()

PATCH Applied Chuck Lever 4 participants 9 messages Jun 30 – Jul 7

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 net/tls: Consume empty data records in tls_sw_read_sock()

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

tls_sw_recvmsg() does not stall on this: a zero-length data record copies nothing and falls through to consume_skb(). Mirror that in the read_sock() path by recognizing an empty data record before the actor runs, consuming it, and continuing.

Fixes 662fbcec32f4 ("net/tls: implement ->read_sock()")
---
 net/tls/tls_sw.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
net/tls/tls_sw.c +11 -0
index 9324e4ed20a3..d4afc90fd796 100644
@@ -2115,6 +2115,17 @@ int tls_sw_read_sock(struct sock *sk, read_descriptor_t *desc,
 			goto read_sock_requeue;
 		}
 
+		/* An empty data record (legal in TLS 1.3) gives a zero
+		 * read_actor return, indistinguishable from the consumer
+		 * stalling; the used <= 0 path would requeue it at the
+		 * head of rx_list and block all later records. Consume it
+		 * here instead.
+		 */
+		if (rxm->full_len == 0) {
+			consume_skb(skb);
+			continue;
+		}
+
 		used = read_actor(desc, skb, rxm->offset, rxm->full_len);
 		if (used <= 0) {
 			if (!copied)
Signature · 1 line
2.54.0
maintainer Reviewed-by on v1 1/1
#1 lore raw
Quoted 16 lines · Chuck Lever

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

tls_sw_recvmsg() does not stall on this: a zero-length data record copies nothing and falls through to consume_skb(). Mirror that in the read_sock() path by recognizing an empty data record before the actor runs, consuming it, and continuing.

Quoted 5 lines
Fixes 662fbcec32f4 ("net/tls: implement ->read_sock()")
---
 net/tls/tls_sw.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

I think tls_sw_splice_read() suffers from a similar issue (returning 0 even though more data may be available). Sashiko agrees, and also found a few more pre-existing issues.

Signature · 1 line
Sabrina
#2 lore raw
Quoted 23 lines · Sabrina Dubroca
Quoted 16 lines · Chuck Lever

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

tls_sw_recvmsg() does not stall on this: a zero-length data record copies nothing and falls through to consume_skb(). Mirror that in the read_sock() path by recognizing an empty data record before the actor runs, consuming it, and continuing.

Quoted 5 lines
Fixes 662fbcec32f4 ("net/tls: implement ->read_sock()")
---
 net/tls/tls_sw.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
Quoted 5 lines

I think tls_sw_splice_read() suffers from a similar issue (returning 0 even though more data may be available). Sashiko agrees, and also found a few more pre-existing issues.

Do you want a v2 series with those issues addressed?

Signature · 1 line
Chuck Lever
maintainer
#3 lore raw
Quoted 26 lines · Chuck Lever
Quoted 23 lines · Sabrina Dubroca
Quoted 21 lines · Chuck Lever

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

tls_sw_recvmsg() does not stall on this: a zero-length data record copies nothing and falls through to consume_skb(). Mirror that in the read_sock() path by recognizing an empty data record before the actor runs, consuming it, and continuing.

Fixes 662fbcec32f4 ("net/tls: implement ->read_sock()")
---
 net/tls/tls_sw.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
Quoted 7 lines
Quoted 5 lines

I think tls_sw_splice_read() suffers from a similar issue (returning 0 even though more data may be available). Sashiko agrees, and also found a few more pre-existing issues.

Do you want a v2 series with those issues addressed?

I'd be ok with this patch going in on its own, and the other issues being addressed separately. If you have time to look into those, that'd be great.

Signature · 1 line
Sabrina
#4 lore raw
Quoted 9 lines · Sabrina Dubroca
Quoted 8 lines · Chuck Lever
Quoted 5 lines · Sabrina Dubroca

I think tls_sw_splice_read() suffers from a similar issue (returning 0 even though more data may be available). Sashiko agrees, and also found a few more pre-existing issues.

Quoted 5 lines
Quoted 1 line

Do you want a v2 series with those issues addressed?

I'd be ok with this patch going in on its own, and the other issues being addressed separately. If you have time to look into those, that'd be great.

While I'm waiting for this patch to matriculate from net into net-next (as it is a pre-requisite for supporting TLS Alerts for in-kernel TLS consumers), I've started looking at the Sashiko findings. I might drop finding #3 because it doesn't seem to be easily reachable in the current code base. The other two seem straightforward.

Signature · 1 line
Chuck Lever
#5 lore raw
In reply to Sabrina Dubroca
Quoted 33 lines · Sabrina Dubroca
Quoted 32 lines · Chuck Lever
Quoted 28 lines · Sabrina Dubroca
Quoted 16 lines · Chuck Lever

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

tls_sw_recvmsg() does not stall on this: a zero-length data record copies nothing and falls through to consume_skb(). Mirror that in the read_sock() path by recognizing an empty data record before the actor runs, consuming it, and continuing.

Quoted 5 lines
Fixes 662fbcec32f4 ("net/tls: implement ->read_sock()")
---
 net/tls/tls_sw.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

I think tls_sw_splice_read() suffers from a similar issue (returning 0 even though more data may be available). Sashiko agrees, and also found a few more pre-existing issues.

Quoted 5 lines
Quoted 1 line

Do you want a v2 series with those issues addressed?

I'd be ok with this patch going in on its own, and the other issues being addressed separately. If you have time to look into those, that'd be great.

patchwork shows this patch continues to be marked as "New". Is there something I need to do to help move it forward?

Signature · 1 line
Chuck Lever
maintainer
#6 lore raw
Quoted 36 lines · Chuck Lever
Quoted 33 lines · Sabrina Dubroca
Quoted 32 lines · Chuck Lever
Quoted 28 lines · Sabrina Dubroca
Quoted 16 lines · Chuck Lever

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

tls_sw_recvmsg() does not stall on this: a zero-length data record copies nothing and falls through to consume_skb(). Mirror that in the read_sock() path by recognizing an empty data record before the actor runs, consuming it, and continuing.

Quoted 5 lines
Fixes 662fbcec32f4 ("net/tls: implement ->read_sock()")
---
 net/tls/tls_sw.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

I think tls_sw_splice_read() suffers from a similar issue (returning 0 even though more data may be available). Sashiko agrees, and also found a few more pre-existing issues.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Do you want a v2 series with those issues addressed?

I'd be ok with this patch going in on its own, and the other issues being addressed separately. If you have time to look into those, that'd be great.

patchwork shows this patch continues to be marked as "New". Is there something I need to do to help move it forward?

I don't think there's anything blocking it other than the length of the maintainers' backlog.

Signature · 1 line
Sabrina
maintainer
#7 lore raw
Quoted 41 lines · Sabrina Dubroca
Quoted 40 lines · Chuck Lever
Quoted 38 lines · Sabrina Dubroca
Quoted 26 lines · Chuck Lever
Quoted 23 lines · Sabrina Dubroca
Quoted 21 lines · Chuck Lever

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

tls_sw_recvmsg() does not stall on this: a zero-length data record copies nothing and falls through to consume_skb(). Mirror that in the read_sock() path by recognizing an empty data record before the actor runs, consuming it, and continuing.

Fixes 662fbcec32f4 ("net/tls: implement ->read_sock()")
---
 net/tls/tls_sw.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
Quoted 7 lines
Quoted 5 lines

I think tls_sw_splice_read() suffers from a similar issue (returning 0 even though more data may be available). Sashiko agrees, and also found a few more pre-existing issues.

Do you want a v2 series with those issues addressed?

I'd be ok with this patch going in on its own, and the other issues being addressed separately. If you have time to look into those, that'd be great.

Quoted 5 lines
Quoted 2 lines

patchwork shows this patch continues to be marked as "New". Is there something I need to do to help move it forward?

I don't think there's anything blocking it other than the length of the maintainers' backlog.

As noted yday:

https://lore.kernel.org/netdev/[email protected]/

current patch processing capacity is limited.

I'm processing this one right now.

/P

#8 lore raw
In reply to Chuck Lever
This patch was applied to netdev/net.git (main) by Paolo Abeni <[email protected]>:

Hello:

This patch was applied to netdev/net.git (main)
by Paolo Abeni <[email protected]>:

Quoted 11 lines · On Tue, 30 Jun 2026 15:15:51 -0400 you wrote:

A peer may send a zero-length TLS application_data record; TLS 1.3 explicitly permits these as a traffic-analysis countermeasure (RFC 8446, Section 5.1). After decryption such a record has full_len ==
0. tls_sw_read_sock() hands it to the read_actor, which has no payload to consume and returns zero. The loop treats a zero return as backpressure (used <= 0), requeues the skb at the head of rx_list, and stops. rx_list is serviced head-first on the next call, so the empty record is dequeued, fails the same way, and is requeued again; every later record on the connection is blocked behind it.

Quoted 1 line

[...]

Here is the summary with links:
- [net] net/tls: Consume empty data records in tls_sw_read_sock()

    https://git.kernel.org/netdev/net/c/3be28e2c9cd0

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html