[PATCH net-next v9 5/5] tls: Flush backlog before waiting for a new record

Chuck Lever <[email protected]> Wed, 29 Apr 2026 17:48:12 -0400
Newsgroups dev.linux.lists.kernel-tls-handshake,org.kernel.vger.netdev
Message-ID <[email protected]>
From: Chuck Lever <[email protected]>

While lock_sock is held, incoming TCP segments land on
sk->sk_backlog rather than sk->sk_receive_queue.
tls_rx_rec_wait() inspects only sk_receive_queue, so backlog
data remains invisible. For non-blocking callers (read_sock,
and recvmsg or splice_read with MSG_DONTWAIT) this causes a
spurious -EAGAIN. For blocking callers it forces an
unnecessary sleep/wakeup cycle.

Flush the backlog inside tls_rx_rec_wait() before checking
sk_receive_queue so the strparser can parse newly-arrived
segments immediately. On the next loop iteration
tls_read_flush_backlog() may redundantly flush, but this
path is cold and the cost is negligible.

Backlog processing can run tcp_reset(), which sets both
sk->sk_err = ECONNRESET and (via tcp_done()) sk->sk_shutdown
= SHUTDOWN_MASK. The pre-existing top-of-loop sk_err check
already ran before the flush, so without further care the
freshly-set error would be masked by the next-line
sk_shutdown test returning 0 (EOF). Re-check sk_err
immediately before the sk_shutdown test so a connection
abort surfaces as -ECONNRESET rather than a clean EOF.

Suggested-by: Sabrina Dubroca <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Signed-off-by: Chuck Lever <[email protected]>
---
 net/tls/tls_sw.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index cbb068266bab..b888aaa505c0 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -1382,6 +1382,8 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock,
 		if (ret < 0)
 			return ret;
 
+		if (sk_flush_backlog(sk))
+			released = true;
 		if (!skb_queue_empty(&sk->sk_receive_queue)) {
 			/* Defer notification to the exit point;
 			 * this thread will consume the record
@@ -1392,6 +1394,8 @@ tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock,
 				break;
 		}
 
+		if (sk->sk_err)
+			return sock_error(sk);
 		if (sk->sk_shutdown & RCV_SHUTDOWN)
 			return 0;
 

-- 
2.53.0