| From a89dd597458848b463d284b15e42a8078beeb046 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= <Jeremy.Jean@oss.cyber.gouv.fr> |
| Date: Sun, 9 Aug 2026 17:07:48 +0000 |
| Subject: SUNRPC: wait for in-flight client TLS handshake callback |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> |
| |
| commit a89dd597458848b463d284b15e42a8078beeb046 upstream. |
| |
| xs_tls_handshake_sync() gives xs_tls_handshake_done() a reference to the |
| lower transport before submitting the handshake request. On timeout or |
| signal, the synchronous waiter drops that reference after calling |
| tls_handshake_cancel(). |
| |
| handshake_req_cancel() returns false when handshake_complete() has |
| already marked the request complete. In that case the completion callback |
| can still be running, so dropping the callback-owned reference in the |
| waiter can free the lower transport before xs_tls_handshake_done() stores |
| xprt_err or drops its own reference. |
| |
| If cancellation loses to completion, wait until xs_tls_handshake_done() |
| signals handshake_done and let the callback release its reference. This |
| mirrors the server-side handshake lifetime handling and keeps the timeout |
| or signal return value unchanged. |
| |
| Fixes: 75eb6af7acdf ("SUNRPC: Add a TCP-with-TLS RPC transport class") |
| Cc: stable@vger.kernel.org |
| Assisted-by: Codex:gpt-5 |
| Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> |
| Reviewed-by: Chuck Lever <cel@kernel.org> |
| Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/sunrpc/xprtsock.c | 12 +++++++++++- |
| 1 file changed, 11 insertions(+), 1 deletion(-) |
| |
| --- a/net/sunrpc/xprtsock.c |
| +++ b/net/sunrpc/xprtsock.c |
| @@ -2627,7 +2627,17 @@ static int xs_tls_handshake_sync(struct |
| rc = wait_for_completion_interruptible_timeout(&lower_transport->handshake_done, |
| XS_TLS_HANDSHAKE_TO); |
| if (rc <= 0) { |
| - tls_handshake_cancel(sk); |
| + if (!tls_handshake_cancel(sk)) { |
| + /* |
| + * Cancellation lost to handshake_complete(): the |
| + * callback still owns its xprt reference and is in |
| + * flight. Wait for it to finish before returning. |
| + */ |
| + wait_for_completion(&lower_transport->handshake_done); |
| + if (rc == 0) |
| + rc = -ETIMEDOUT; |
| + goto out; |
| + } |
| if (rc == 0) |
| rc = -ETIMEDOUT; |
| goto out_put_xprt; |