Netdev List
 help / color / mirror / Atom feed
From: Jiayuan Chen <jiayuan.chen@linux.dev>
To: Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org, john.fastabend@gmail.com,
	sd@queasysnail.net, davem@davemloft.net, edumazet@google.com,
	pabeni@redhat.com, horms@kernel.org, wilfred.mallawa@wdc.com,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net] tls: fix TX context confusion in the max payload size setsockopt
Date: Tue, 1 Sep 2026 14:37:10 +0800	[thread overview]
Message-ID: <f777c2f2-3bf8-44e4-be5e-81dee14d445f@linux.dev> (raw)
In-Reply-To: <20260901031931.1636980-1-kuba@kernel.org>


on 9/1/26 11:19 AM, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
>      tls: fix TX context confusion in the max payload size setsockopt
>
> The patch replaces the unchecked tls_sw_ctx_tx() dereference in
> do_tls_setsockopt_tx_payload_len() with a new helper,
> tls_tx_record_is_open(), that dispatches on ctx->tx_conf so the TLS_HW
> path looks at tls_offload_ctx_tx(ctx)->open_record instead of a field of
> the wrong structure.  The rest of the option handling is unchanged.
>
>> diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
>> index fbb274287aa5..e4f288c1fa34 100644
>> --- a/net/tls/tls_main.c
>> +++ b/net/tls/tls_main.c
>> @@ -833,15 +833,29 @@ static int do_tls_setsockopt_no_pad(struct sock *sk, sockptr_t optval,
>>   	return rc;
>>   }
>>
>> +/* priv_ctx_tx holds a different structure on each TX path, so tx_conf has to
>> + * say which open record to look at.
>> + */
>> +static bool tls_tx_record_is_open(struct tls_context *ctx)
>> +{
>> +	switch (ctx->tx_conf) {
>> +	case TLS_SW:
>> +		return !!tls_sw_ctx_tx(ctx)->open_rec;
>> +	case TLS_HW:
>> +		return !!tls_offload_ctx_tx(ctx)->open_record;
>> +	default:
>> +		return false;
>> +	}
>> +}
>> +
>>   static int do_tls_setsockopt_tx_payload_len(struct sock *sk, sockptr_t optval,
>>   					    unsigned int optlen)
>>   {
>>   	struct tls_context *ctx = tls_get_ctx(sk);
>> -	struct tls_sw_context_tx *sw_ctx = tls_sw_ctx_tx(ctx);
>>   	u16 value;
>>   	bool tls_13 = ctx->prot_info.version == TLS_1_3_VERSION;
>>
>> -	if (sw_ctx && sw_ctx->open_rec)
>> +	if (tls_tx_record_is_open(ctx))
>>   		return -EBUSY;
> [Severity: High]
> For the TLS_HW arm, is open_record enough to tell that no record is being
> built?  do_tls_setsockopt() calls this helper with only the socket lock
> held:
>
> net/tls/tls_main.c:do_tls_setsockopt() {
> 	case TLS_TX_MAX_PAYLOAD_LEN:
> 		lock_sock(sk);
> 		rc = do_tls_setsockopt_tx_payload_len(sk, optval, optlen);
> 		release_sock(sk);
> }
>
> but the offload TX path is serialized by ctx->tx_lock, and it drops the
> socket lock at a point where open_record is already NULL:
>
> net/tls/tls_device.c:tls_push_record() {
> 	offload_ctx->open_record = NULL;
> 	...
> 	return tls_push_sg(sk, ctx, offload_ctx->sg_tx_data, 0, flags);
> }
>
> tls_push_sg() calls tcp_sendmsg_locked(), which for a blocking sendmsg()
> with a full send buffer waits in sk_stream_wait_memory() and releases the
> socket lock there.  tls_push_data() has a second such wait on the
> tls_do_allocation() failure path.
>
> So can a concurrent setsockopt() see open_record == NULL, take the "not
> open" branch and publish a smaller ctx->tx_max_payload_len while a sender
> is parked mid-sendmsg holding tx_lock?


Yes, this window exists, but it seems to be a pre-existing issue. I 
think I can fix it by taking tx_lock.

> If so, does the offload path then keep using the old limit for the rest of
> that sendmsg?  tls_push_data() latches it once, before the loop, and never
> refreshes it:
>
> net/tls/tls_device.c:tls_push_data() {
> 	max_open_record_len = tls_ctx->tx_max_payload_len +
> 			      prot->prepend_size;
> 	do {
> 		...
> 		copy = min_t(size_t, size, max_open_record_len - record->len);
> }
>
> That would mean setsockopt returns 0 while records larger than the new
> limit continue to go out, which does not match what
> Documentation/networking/tls.rst says about TLS_TX_MAX_PAYLOAD_LEN ("the
> kernel enforces the specified limit on all outgoing TLS records.  No
> plaintext fragment will exceed this size").
>
> There is a follow-on question about the next call.  If the sender leaves a
> record open across the syscall (MSG_MORE with record->num_frags <
> MAX_SKB_FRAGS - 1), the next tls_push_data() latches the new, smaller
> max_open_record_len while record->len is still the old, larger value.
> max_open_record_len is u32 and record->len is int, so does
>
> 	copy = min_t(size_t, size, max_open_record_len - record->len);
>
> wrap around here and drop the record-size clamp entirely, letting
> tls_append_frag() grow the record past the 2^14 plaintext maximum before
> "record->len >= max_open_record_len" closes it?
>
> Note that tls_sw_sendmsg_locked() re-reads the limit on every iteration:
>
> net/tls/tls_sw.c:tls_sw_sendmsg_locked() {
> 		record_room = tls_ctx->tx_max_payload_len - msg_pl->sg.size;
> }
>
> so the latched offload value looks like the odd one out.
>
> Would it be better to serialize the check and the store against the lock
> that actually protects record building?  Since tls_device_sendmsg() takes
> tx_lock before lock_sock:
>
> net/tls/tls_device.c:tls_device_sendmsg() {
> 	mutex_lock(&tls_ctx->tx_lock);
> 	lock_sock(sk);
> }
>
> tx_lock is the outer lock, so taking it inside the already socket-locked
> helper is not an option; the acquisition in do_tls_setsockopt() would have
> to be reordered (or the helper made to wait for in-flight senders, as
> tls_sk_proto_cleanup() does on sk_write_pending).
>
> One smaller point: the plain read of tls_ctx->tx_max_payload_len in
> tls_push_data() against the plain write in
> do_tls_setsockopt_tx_payload_len() is an unannotated data race that KCSAN
> would flag.

I don't think so: all tls_push_data() callers hold the socket lock, and the

write is under the socket lock too, so the accesses are serialized.


      reply	other threads:[~2026-09-01  6:37 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31  2:56 [PATCH net] tls: fix TX context confusion in the max payload size setsockopt Jiayuan Chen
2026-09-01  3:19 ` Jakub Kicinski
2026-09-01  6:37   ` Jiayuan Chen [this message]

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=f777c2f2-3bf8-44e4-be5e-81dee14d445f@linux.dev \
    --to=jiayuan.chen@linux.dev \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=john.fastabend@gmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=sd@queasysnail.net \
    --cc=wilfred.mallawa@wdc.com \
    /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