Re: [PATCH] net/handshake: duplicate handshake cancellations leak socket

"Chuck Lever" <[email protected]>
Newsgroups dev.linux.lists.kernel-tls-handshake,org.kernel.vger.netdev
Message-ID <[email protected]>

On Tue, Dec 9, 2025, at 2:30 PM, Scott Mayhew wrote:
> When a handshake request is cancelled it is removed from the
> handshake_net->hn_requests list, but it is still present in the
> handshake_rhashtbl until it is destroyed.
>
> If a second cancellation request arrives for the same handshake request,
> then remove_pending() will return false... and assuming
> HANDSHAKE_F_REQ_COMPLETED isn't set in req->hr_flags, we'll continue
> processing through the out_true label, where we put another reference on
> the sock and a refcount underflow occurs.
>
> This can happen for example if a handshake times out - particularly if
> the SUNRPC client sends the AUTH_TLS probe to the server but doesn't
> follow it up with the ClientHello due to a problem with tlshd.  When the
> timeout is hit on the server, the server will send a FIN, which triggers
> a cancellation request via xs_reset_transport().  When the timeout is
> hit on the client, another cancellation request happens via
> xs_tls_handshake_sync().
>
> Add a test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED) in the pending cancel
> path so duplicate cancels can be detected.
>
> Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for 
> handling handshake requests")
> Suggested-by: Chuck Lever <[email protected]>
> Signed-off-by: Scott Mayhew <[email protected]>
> ---
>  net/handshake/request.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/net/handshake/request.c b/net/handshake/request.c
> index 274d2c89b6b2..f78091680bca 100644
> --- a/net/handshake/request.c
> +++ b/net/handshake/request.c
> @@ -324,7 +324,11 @@ bool handshake_req_cancel(struct sock *sk)
> 
>  	hn = handshake_pernet(net);
>  	if (hn && remove_pending(hn, req)) {
> -		/* Request hadn't been accepted */
> +		/* Request hadn't been accepted - mark cancelled */
> +		if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) {
> +			trace_handshake_cancel_busy(net, req, sk);
> +			return false;
> +		}
>  		goto out_true;
>  	}
>  	if (test_and_set_bit(HANDSHAKE_F_REQ_COMPLETED, &req->hr_flags)) {
> -- 
> 2.51.0

Reviewed-by: Chuck Lever <[email protected]>


-- 
Chuck Lever
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.