git: f8575d4e4758 - stable/13 - krpc: Ref cnt the client structures for TLS upcalls

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Thu, 02 May 2024 01:20:56 UTC
The branch stable/13 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=f8575d4e47587dc0153360debd3a6ec5665a57b5

commit f8575d4e47587dc0153360debd3a6ec5665a57b5
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-04-27 00:55:24 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-05-02 01:19:09 +0000

    krpc: Ref cnt the client structures for TLS upcalls
    
    A crash occurred during testing, where the client structures had
    already been free'd when the upcall thread tried to lock them.
    
    This patch acquires a reference count on both of the structures
    and these are released when the upcall is done, so that the
    structures cannot be free'd prematurely.  This happened because
    the testing is done over a very slow vpn.
    
    Found during a IETF bakeathon testing event this week.
    
    (cherry picked from commit 4ba444de708bada46a88ecac17b2f6c1dc912234)
---
 sys/rpc/clnt_vc.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/sys/rpc/clnt_vc.c b/sys/rpc/clnt_vc.c
index 2edd7421f5c8..a8670553546e 100644
--- a/sys/rpc/clnt_vc.c
+++ b/sys/rpc/clnt_vc.c
@@ -759,6 +759,7 @@ clnt_vc_control(CLIENT *cl, u_int request, void *info)
 	case CLSET_BACKCHANNEL:
 		xprt = (SVCXPRT *)info;
 		if (ct->ct_backchannelxprt == NULL) {
+			SVC_ACQUIRE(xprt);
 			xprt->xp_p2 = ct;
 			if (ct->ct_sslrefno != 0)
 				xprt->xp_tls = RPCTLS_FLAGS_HANDSHAKE;
@@ -772,9 +773,11 @@ clnt_vc_control(CLIENT *cl, u_int request, void *info)
 		ct->ct_sslusec = *p++;
 		ct->ct_sslrefno = *p;
 		if (ct->ct_sslrefno != RPCTLS_REFNO_HANDSHAKE) {
+			/* cl ref cnt is released by clnt_vc_dotlsupcall(). */
+			CLNT_ACQUIRE(cl);
 			mtx_unlock(&ct->ct_lock);
 			/* Start the kthread that handles upcalls. */
-			error = kthread_add(clnt_vc_dotlsupcall, ct,
+			error = kthread_add(clnt_vc_dotlsupcall, cl,
 			    NULL, NULL, 0, 0, "krpctls%u", thrdnum++);
 			if (error != 0)
 				panic("Can't add KRPC thread error %d", error);
@@ -874,6 +877,7 @@ clnt_vc_destroy(CLIENT *cl)
 		mtx_lock(&ct->ct_lock);
 		xprt->xp_p2 = NULL;
 		sx_xunlock(&xprt->xp_lock);
+		SVC_RELEASE(xprt);
 	}
 
 	if (ct->ct_socket) {
@@ -1275,7 +1279,8 @@ clnt_vc_upcallsdone(struct ct_data *ct)
 static void
 clnt_vc_dotlsupcall(void *data)
 {
-	struct ct_data *ct = (struct ct_data *)data;
+	CLIENT *cl = (CLIENT *)data;
+	struct ct_data *ct = (struct ct_data *)cl->cl_private;
 	enum clnt_stat ret;
 	uint32_t reterr;
 
@@ -1312,5 +1317,6 @@ clnt_vc_dotlsupcall(void *data)
 	ct->ct_rcvstate &= ~RPCRCVSTATE_UPCALLTHREAD;
 	wakeup(&ct->ct_sslrefno);
 	mtx_unlock(&ct->ct_lock);
+	CLNT_RELEASE(cl);
 	kthread_exit();
 }