]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
tls: Purge async_hold in tls_decrypt_async_wait()
authorChuck Lever <chuck.lever@oracle.com>
Tue, 24 Mar 2026 12:53:23 +0000 (08:53 -0400)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 26 Mar 2026 08:55:53 +0000 (09:55 +0100)
The async_hold queue pins encrypted input skbs while
the AEAD engine references their scatterlist data. Once
tls_decrypt_async_wait() returns, every AEAD operation
has completed and the engine no longer references those
skbs, so they can be freed unconditionally.

A subsequent patch adds batch async decryption to
tls_sw_read_sock(), introducing a new call site that
must drain pending AEAD operations and release held
skbs. Move __skb_queue_purge(&ctx->async_hold) into
tls_decrypt_async_wait() so the purge is centralized
and every caller -- recvmsg's drain path, the -EBUSY
fallback in tls_do_decryption(), and the new read_sock
batch path -- releases held skbs on synchronization
without each site managing the purge independently.

This fixes a leak when tls_strp_msg_hold() fails part-way through,
after having added some cloned skbs to the async_hold
queue. tls_decrypt_sg() will then call tls_decrypt_async_wait() to
process all pending decrypts, and drop back to synchronous mode, but
tls_sw_recvmsg() only flushes the async_hold queue when one record has
been processed in "fully-async" mode, which may not be the case here.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reported-by: Yiming Qian <yimingqian591@gmail.com>
Fixes: b8a6ff84abbc ("tls: wait for pending async decryptions if tls_strp_msg_hold fails")
Link: https://patch.msgid.link/20260324-tls-read-sock-v5-1-5408befe5774@oracle.com
[pabeni@redhat.com: added leak comment]
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/tls/tls_sw.c

index 5fe07f110fe8c7f3a61242428ac5f0b6bfded810..dd9dda759bbb8c76042f111ff2c82a15eae2aa30 100644 (file)
@@ -246,6 +246,7 @@ static int tls_decrypt_async_wait(struct tls_sw_context_rx *ctx)
                crypto_wait_req(-EINPROGRESS, &ctx->async_wait);
        atomic_inc(&ctx->decrypt_pending);
 
+       __skb_queue_purge(&ctx->async_hold);
        return ctx->async_wait.err;
 }
 
@@ -2225,7 +2226,6 @@ recv_end:
 
                /* Wait for all previously submitted records to be decrypted */
                ret = tls_decrypt_async_wait(ctx);
-               __skb_queue_purge(&ctx->async_hold);
 
                if (ret) {
                        if (err >= 0 || err == -EINPROGRESS)