TLS 1.2 and TLS 1.3 both permit zero-length application_data
records as a traffic-analysis countermeasure (RFC 5246, Section
6.2.1; RFC 8446, Section 5.1). Such a record decrypts to
full_len == 0, so every arm of the receive loop reaches
"decrypted += chunk" and "len -= chunk" with chunk == 0: len
never reaches zero, and tls_strp_msg_ready() holds the second
loop term true while the peer keeps records arriving. The peek
arm and the async arm also queue each record on rx_list, which
then grows without bound. tls_rx_rec_wait() returns without
waiting whenever a record is already parsed, so its signal check
never runs, and no other test in the loop consults
signal_pending(). A peer streaming empty records therefore holds
the caller in recvmsg(), unresponsive to SIGKILL, until it stops.
Consume an empty data record as soon as the receive loop has it,
before the paths diverge on darg.zc, and test for a pending
signal there. Freeing the record's skb requires its decryption to
have completed, so an empty record is no longer decrypted
asynchronously, and the new branch sets MSG_EOR itself because
the record no longer reaches the assignment at the bottom of the
loop. Bytes already received take precedence over the signal:
they are returned, and the signal is handled when the caller next
enters the kernel.
Fixes: c46234ebb4d1 ("tls: RX path for ktls")
Signed-off-by: Chuck Lever <[email protected]>
---
net/tls/tls_sw.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index f85d8a639731..0e76b31b1291 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -1877,9 +1877,12 @@ int tls_sw_recvmsg(struct sock *sk,
tlm->control == TLS_RECORD_TYPE_DATA)
darg.zc = true;
- /* Do not use async mode if record is non-data */
+ /* Do not use async mode if record is non-data, or if it
+ * is empty: the receive loop frees an empty record's skb,
+ * so its decryption must have completed.
+ */
if (tlm->control == TLS_RECORD_TYPE_DATA)
- darg.async = ctx->async_capable;
+ darg.async = ctx->async_capable && to_decrypt;
else
darg.async = false;
@@ -1915,6 +1918,27 @@ int tls_sw_recvmsg(struct sock *sk,
chunk = rxm->full_len;
tls_rx_rec_done(ctx);
+ /* An empty record advances neither loop bound, so a flood
+ * of them can be interrupted only here. On the zero-copy
+ * path darg.skb is the strparser anchor, already released
+ * by tls_rx_rec_done().
+ */
+ if (tls_rx_empty_data_rec(chunk, control)) {
+ long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
+ if (!darg.zc)
+ consume_skb(darg.skb);
+
+ /* An empty record still marks a boundary. */
+ msg->msg_flags |= MSG_EOR;
+
+ if (signal_pending(current)) {
+ err = tls_rx_intr_errno(timeo);
+ goto recv_end;
+ }
+ continue;
+ }
+
if (!darg.zc) {
bool partially_consumed = chunk > len;
struct sk_buff *skb = darg.skb;
--
2.54.0