A zero-length application_data record decrypts to full_len == 0,
so tls_sw_splice_read() splices zero bytes and returns zero. A zero
return from a splice read means EOF, and the caller tears down a
connection that is still live.
Consume the record and fetch the next one, as tls_sw_recvmsg()
does. Test for a pending signal before each retry, so the splicing
task stays killable. A nonblocking splice gets -EAGAIN, as
tls_sw_recvmsg() does. After this change, tls_sw_splice_read() reads
empty records for as long as they arrive, until a signal is pending.
When an empty record precedes a close_notify, splice(2) now returns
-EINVAL from the control-record test instead of a false EOF. A
splice that reaches an alert record already reports -EINVAL.
Fixes: c46234ebb4d1 ("tls: RX path for ktls")
Reported-by: Sabrina Dubroca <[email protected]>
Closes: https://lore.kernel.org/netdev/akaoXcfamBp8_mYe@krikkit/
Signed-off-by: Chuck Lever <[email protected]>
---
net/tls/tls_sw.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index d63b4c71780a..fe9c5c21dadc 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -2027,6 +2027,7 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t
*ppos,
struct sock *sk = sock->sk;
struct tls_msg *tlm;
struct sk_buff *skb;
+ bool released = true;
ssize_t copied = 0;
bool nonblock;
int chunk;
@@ -2044,12 +2045,13 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t
*ppos,
if (err)
goto splice_read_end;
+retry:
if (!skb_queue_empty(&ctx->rx_list)) {
skb = __skb_dequeue(&ctx->rx_list);
} else {
struct tls_decrypt_arg darg;
- err = tls_rx_rec_wait(sk, nonblock, true, false);
+ err = tls_rx_rec_wait(sk, nonblock, released, false);
if (err <= 0)
goto splice_read_end;
@@ -2061,6 +2063,9 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t
*ppos,
tls_rx_rec_done(ctx);
skb = darg.skb;
+
+ /* The retry's wait runs with the socket lock still held. */
+ released = false;
}
rxm = strp_msg(skb);
@@ -2072,6 +2077,16 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t
*ppos,
goto splice_requeue;
}
+ /* Splicing zero bytes reads as EOF to the caller. */
+ if (rxm->full_len == 0) {
+ consume_skb(skb);
+ if (signal_pending(current)) {
+ err = tls_rx_signal_err(sk, nonblock);
+ goto splice_read_end;
+ }
+ goto retry;
+ }
+
chunk = min_t(unsigned int, rxm->full_len, len);
copied = skb_splice_bits(skb, sk, rxm->offset, pipe, chunk, flags);
if (copied < 0)
--
2.55.0