From: netdev-bot+sashiko@kernel.org
To: cel@kernel.org
Cc: john.fastabend@gmail.com, kuba@kernel.org, sd@queasysnail.net,
davem@davemloft.net, pabeni@redhat.com, horms@kernel.org,
davejwatson@fb.com, shuah@kernel.org, qingfang.deng@linux.dev,
edumazet@kernel.org, netdev@vger.kernel.org,
linux-kselftest@vger.kernel.org
Subject: Re: [PATCH net-next v5 01/10] tls: Bound consecutive no-data records in tls_sw_read_sock()
Date: Sun, 18 Oct 2026 19:22:53 +0000 [thread overview]
Message-ID: <179235137390.3135.8037803967508250404@kernel.org> (raw)
In-Reply-To: <20261014-tls-follow-on-v5-1-e76c301d4f05@kernel.org>
Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 1 · Low: 1
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [High] The new limit only counts consecutive empty records, so a peer
can get around it by mixing in small records.
- [Medium] When tls_sw_read_sock() stops at TLS_RX_NODATA_LIMIT, it
queues data_ready_work only if tls_strp_msg_ready(ctx) is true…
- [Low] (Baseline: not confirmed after checking the end of the series.)
At this commit, the wake condition at the new TLS_RX_NODATA_LIMIT exit…
--
tls: Bound consecutive no-data records in tls_sw_read_sock()
This patch makes tls_sw_read_sock() stop after TLS_RX_NODATA_LIMIT (16)
consecutive zero-length application_data records. Any record that delivers
bytes resets the count. When the loop stops and a parsed record is still
pending, a work item on tls_strp_wq calls the socket's current
sk_data_ready(), so consumers such as nvme-tcp get woken again.
> diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
> index 312e51270f293..37fcca95c0467 100644
> --- a/net/tls/tls_sw.c
> +++ b/net/tls/tls_sw.c
[ ... ]
> @@ -2136,14 +2153,23 @@ int tls_sw_read_sock(struct sock *sk, read_descriptor_t *desc,
> goto read_sock_requeue;
> }
>
[ ... ]
> if (rxm->full_len == 0) {
> consume_skb(skb);
> + if (++nodata >= TLS_RX_NODATA_LIMIT) {
> + /* tls_rx_reader_release() wakes only the
> + * callback saved when TLS_RX was set up;
> + * nvme-tcp installs its own afterward.
> + */
> + if (tls_strp_msg_ready(ctx))
> + queue_work(tls_strp_wq,
> + &ctx->data_ready_work);
[Severity: Medium]
What happens when this limit is hit after the parse of the next record
was deferred to strp->work?
After the 16th empty record, tls_rx_rec_done()->tls_strp_check_rcv() can
reach tls_strp_read_copy() if the receive queue layout forces copy mode.
That path calls alloc_page(strp->sk->sk_allocation), and
nvme_tcp_alloc_queue() sets sk_allocation to GFP_ATOMIC. If the
allocation fails:
net/tls/tls_strp.c:tls_strp_check_rcv() {
...
if (tls_strp_read_sock(strp) == -ENOMEM)
queue_work(tls_strp_wq, &strp->work);
...
}
then msg_ready stays false. The new break skips data_ready_work and
returns 0, so nvme_tcp_io_work() sees no progress and exits.
When strp->work parses the record later, tls_rx_msg_maybe_announce()
sends the announcement here:
ctx->saved_data_ready(strp->sk);
That is the pre-TLS callback, not nvme_tcp_data_ready(), which does not
chain to it. Only nvme_tcp_data_ready() schedules io_work.
Could the received record then sit unread until unrelated traffic or an
I/O timeout runs io_work again?
Before this patch, the loop went back into tls_rx_rec_wait(), which
retries tls_strp_check_rcv() right away. Hitting this stall needed two
allocation failures in a row.
[Severity: Low]
Should this wake condition also look at ctx->rx_list?
tls_sw_sock_is_readable() treats either of these as readable:
return tls_strp_msg_ready(ctx) ||
!skb_queue_empty(&ctx->rx_list);
At this commit, tls_sw_recvmsg() with MSG_PEEK can use put_on_rx_list to
leave 16 or more empty data records, followed by a non-empty record, on
rx_list while msg_ready is false. kcm_attach() only checks the family and
protocol, so a read_sock consumer can then be attached to that kTLS
socket.
In that case tls_sw_read_sock() would consume the 16 empty records from
rx_list, break without queueing data_ready_work, and return 0. The
decrypted payload would stay on rx_list.
The later patch in this series, "tls: Consume empty data records in
tls_sw_recvmsg()", appears to keep empty data records off rx_list. With
it, rx_list would be empty whenever this limit fires, so the issue goes
away at the end of the series. It still seems reachable with this commit
alone.
> + break;
> + }
> continue;
> }
>
> @@ -2154,6 +2180,7 @@ int tls_sw_read_sock(struct sock *sk, read_descriptor_t *desc,
> goto read_sock_requeue;
> }
> copied += used;
> + nodata = 0;
[Severity: High]
Can a peer get around the bound by resetting nodata here?
The commit message says:
A zero-length application_data record does not deliver a payload, so
tls_sw_read_sock() never runs the read_actor for one and nothing
decrements desc->count.
That implies desc->count bounds the loop for non-empty records. For
nvme-tcp it doesn't seem to:
drivers/nvme/host/tcp.c:nvme_tcp_try_recv() {
...
rd_desc.count = 1;
lock_sock(sk);
queue->nr_cqe = 0;
consumed = sock->ops->read_sock(sk, &rd_desc, nvme_tcp_recv_skb);
...
}
nvme_tcp_recv_skb() never decrements desc->count.
The loop's input is also not fixed when it starts. tls_rx_rec_wait()
calls sk_flush_backlog() when no record is ready, and
tls_read_flush_backlog() flushes the backlog periodically inside the
loop.
Suppose the peer keeps repeating "15 empty records, then one 1-byte data
record the consumer accepts". Each delivered byte sets nodata back to 0,
so the ++nodata >= TLS_RX_NODATA_LIMIT check never fires.
Wouldn't tls_sw_read_sock() then keep running with the socket lock held
for as long as the peer keeps sending? That is the case the commit
message says this patch closes.
Would this need a cap on the total number of records per call, or no
backlog flushing inside read_sock, rather than a count of consecutive
empty records?
> if (used < rxm->full_len) {
> rxm->offset += used;
> rxm->full_len -= used;
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014-tls-follow-on-v5-0-e76c301d4f05%40kernel.org
next prev parent reply other threads:[~2026-10-18 19:22 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-14 18:28 [PATCH net-next v5 00/10] net/tls: Receive-path fixes for zero-length data records Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 01/10] tls: Bound consecutive no-data records in tls_sw_read_sock() Chuck Lever
2026-10-18 19:22 ` netdev-bot+sashiko [this message]
2026-10-19 15:05 ` Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 02/10] tls: Check for a pending signal after an empty record Chuck Lever
2026-10-18 19:22 ` netdev-bot+sashiko
2026-10-19 15:09 ` Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 03/10] tls: Honor O_NONBLOCK in tls_sw_splice_read() Chuck Lever
2026-10-18 19:22 ` netdev-bot+sashiko
2026-10-19 15:10 ` Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 04/10] tls: Consume empty data records " Chuck Lever
2026-10-18 19:22 ` netdev-bot+sashiko
2026-10-19 15:10 ` Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 05/10] tls: Consume empty data records in tls_sw_recvmsg() Chuck Lever
2026-10-18 19:22 ` netdev-bot+sashiko
2026-10-19 15:11 ` Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 06/10] tls: Return copied data ahead of a run of empty records Chuck Lever
2026-10-18 19:23 ` netdev-bot+sashiko
2026-10-19 15:12 ` Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 07/10] selftests: tls: Skip the zero_len tests when TLS is unavailable Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 08/10] selftests: tls: Extend coverage for zero-length records Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 09/10] selftests: tls: Cover splice on a nonblocking socket Chuck Lever
2026-10-14 18:28 ` [PATCH net-next v5 10/10] selftests: tls: Cover the empty-record cap in splice Chuck Lever
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=179235137390.3135.8037803967508250404@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=cel@kernel.org \
--cc=davejwatson@fb.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=qingfang.deng@linux.dev \
--cc=sd@queasysnail.net \
--cc=shuah@kernel.org \
/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