git: 42eec5201ab9 - main - rpcsec_tls/server: use netlink RPC client to talk to rpc.tlsservd(8)

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Sat, 01 Feb 2025 09:02:17 UTC
The branch main has been updated by glebius:

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

commit 42eec5201ab936f7227950c2c159c02c9cb342d4
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-02-01 01:02:40 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-02-01 09:00:27 +0000

    rpcsec_tls/server: use netlink RPC client to talk to rpc.tlsservd(8)
    
    The server part just repeats what had been done to the client.  We trust
    the parallelism of clnt_nl and we pass socket cookie to the daemon, which
    we then expect to see in the rpctls_syscall(RPCTLS_SYSC_SRVSOCKET) to find
    the corresponding socket+xprt.  We reuse the same database that is used
    for clients.
    
    Note 1: this will be optimized further in a separate commit.  This one is
    made intentionally minimal, to ease the review process.
    
    Note 2: this change intentionally ignores aspect of multiple workers of
    rpc.tlsservd(8).  This also will be addressed in a future commit.
    
    Reviewed by:            rmacklem
    Differential Revision:  https://reviews.freebsd.org/D48561
---
 sys/rpc/rpcsec_tls.h             |   3 -
 sys/rpc/rpcsec_tls/rpctls_impl.c | 392 ++++++++++-----------------------------
 sys/rpc/rpcsec_tls/rpctlssd.x    |   5 +-
 3 files changed, 98 insertions(+), 302 deletions(-)

diff --git a/sys/rpc/rpcsec_tls.h b/sys/rpc/rpcsec_tls.h
index 4c4fa20dde31..8207c57d8f7f 100644
--- a/sys/rpc/rpcsec_tls.h
+++ b/sys/rpc/rpcsec_tls.h
@@ -30,10 +30,7 @@
 
 /* Operation values for rpctls syscall. */
 #define	RPCTLS_SYSC_CLSOCKET	2
-#define	RPCTLS_SYSC_SRVSETPATH	4
 #define	RPCTLS_SYSC_SRVSOCKET	5
-#define	RPCTLS_SYSC_SRVSHUTDOWN	6
-#define	RPCTLS_SYSC_SRVSTARTUP	7
 
 /* Max nprocs for SRV startup */
 #define	RPCTLS_SRV_MAXNPROCS	16
diff --git a/sys/rpc/rpcsec_tls/rpctls_impl.c b/sys/rpc/rpcsec_tls/rpctls_impl.c
index 327233f63f1d..7b6406cdcdd3 100644
--- a/sys/rpc/rpcsec_tls/rpctls_impl.c
+++ b/sys/rpc/rpcsec_tls/rpctls_impl.c
@@ -72,25 +72,21 @@ static struct syscall_helper_data rpctls_syscalls[] = {
 	SYSCALL_INIT_LAST
 };
 
-static struct mtx	rpctls_connect_lock;
-static struct mtx	rpctls_server_lock;
 static struct opaque_auth rpctls_null_verf;
 
 KRPC_VNET_DECLARE(uint64_t, svc_vc_tls_handshake_success);
 KRPC_VNET_DECLARE(uint64_t, svc_vc_tls_handshake_failed);
 
 KRPC_VNET_DEFINE_STATIC(CLIENT *, rpctls_connect_handle);
-KRPC_VNET_DEFINE_STATIC(CLIENT **, rpctls_server_handle);
-KRPC_VNET_DEFINE_STATIC(struct socket *, rpctls_server_so) = NULL;
-KRPC_VNET_DEFINE_STATIC(SVCXPRT *, rpctls_server_xprt) = NULL;
-KRPC_VNET_DEFINE_STATIC(bool, rpctls_srv_newdaemon) = false;
-KRPC_VNET_DEFINE_STATIC(int, rpctls_srv_prevproc) = 0;
-KRPC_VNET_DEFINE_STATIC(bool *, rpctls_server_busy);
+KRPC_VNET_DEFINE_STATIC(CLIENT *, rpctls_server_handle);
 
 struct upsock {
 	RB_ENTRY(upsock) tree;
 	struct socket *so;
-	CLIENT *cl;
+	union {
+		CLIENT *cl;
+		SVCXPRT *xp;
+	};
 };
 
 static RB_HEAD(upsock_t, upsock) upcall_sockets;
@@ -100,27 +96,20 @@ upsock_compare(const struct upsock *a, const struct upsock *b)
 	return ((intptr_t)((uintptr_t)a->so/2 - (uintptr_t)b->so/2));
 }
 RB_GENERATE_STATIC(upsock_t, upsock, tree, upsock_compare);
+static struct mtx rpctls_lock;
 
-static CLIENT		*rpctls_server_client(int procpos);
 static enum clnt_stat	rpctls_server(SVCXPRT *xprt, struct socket *so,
 			    uint32_t *flags, uint64_t *sslp,
 			    uid_t *uid, int *ngrps, gid_t **gids,
 			    int *procposp);
 
-static void
-rpctls_vnetinit(const void *unused __unused)
+static CLIENT *
+rpctls_client_nl_create(const char *group, const rpcprog_t program,
+    const rpcvers_t version)
 {
 	CLIENT *cl;
-	int i;
 
-	KRPC_VNET(rpctls_server_handle) = malloc(sizeof(CLIENT *) *
-	    RPCTLS_SRV_MAXNPROCS, M_RPC, M_WAITOK | M_ZERO);
-	KRPC_VNET(rpctls_server_busy) = malloc(sizeof(bool) *
-	    RPCTLS_SRV_MAXNPROCS, M_RPC, M_WAITOK | M_ZERO);
-	for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++)
-		KRPC_VNET(rpctls_server_busy)[i] = false;
-
-	cl = client_nl_create("tlsclnt", RPCTLSCD, RPCTLSCDVERS);
+	cl = client_nl_create(group, program, version);
 	KASSERT(cl, ("%s: netlink client already exist", __func__));
 	/*
 	 * Set the try_count to 1 so that no retries of the RPC occur.  Since
@@ -133,8 +122,19 @@ rpctls_vnetinit(const void *unused __unused)
 	 */
 	clnt_control(cl, CLSET_RETRIES, &(int){1});
 	clnt_control(cl, CLSET_TIMEOUT, &(struct timeval){.tv_sec = 15});
-	clnt_control(cl, CLSET_WAITCHAN, "tlsclntd");
-	KRPC_VNET(rpctls_connect_handle) = cl;
+	clnt_control(cl, CLSET_WAITCHAN, __DECONST(char *, group));
+
+	return (cl);
+}
+
+static void
+rpctls_vnetinit(const void *unused __unused)
+{
+
+	KRPC_VNET(rpctls_connect_handle) =
+	    rpctls_client_nl_create("tlsclnt", RPCTLSCD, RPCTLSCDVERS);
+	KRPC_VNET(rpctls_server_handle) =
+	    rpctls_client_nl_create("tlsserv", RPCTLSSD, RPCTLSSDVERS);
 }
 VNET_SYSINIT(rpctls_vnetinit, SI_SUB_VNET_DONE, SI_ORDER_ANY,
     rpctls_vnetinit, NULL);
@@ -143,8 +143,8 @@ static void
 rpctls_cleanup(void *unused __unused)
 {
 
-	free(KRPC_VNET(rpctls_server_handle), M_RPC);
-	free(KRPC_VNET(rpctls_server_busy), M_RPC);
+	clnt_destroy(KRPC_VNET(rpctls_connect_handle));
+	clnt_destroy(KRPC_VNET(rpctls_server_handle));
 }
 VNET_SYSUNINIT(rpctls_cleanup, SI_SUB_VNET_DONE, SI_ORDER_ANY,
     rpctls_cleanup, NULL);
@@ -159,10 +159,7 @@ rpctls_init(void)
 		printf("rpctls_init: cannot register syscall\n");
 		return (error);
 	}
-	mtx_init(&rpctls_connect_lock, "rpctls_connect_lock", NULL,
-	    MTX_DEF);
-	mtx_init(&rpctls_server_lock, "rpctls_server_lock", NULL,
-	    MTX_DEF);
+	mtx_init(&rpctls_lock, "rpctls lock", NULL, MTX_DEF);
 	rpctls_null_verf.oa_flavor = AUTH_NULL;
 	rpctls_null_verf.oa_base = RPCTLS_START_STRING;
 	rpctls_null_verf.oa_length = strlen(RPCTLS_START_STRING);
@@ -172,20 +169,10 @@ rpctls_init(void)
 int
 sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap)
 {
-        struct sockaddr_un sun;
-        struct netconfig *nconf;
 	struct file *fp;
-	struct socket *so;
 	struct upsock *ups;
-	SVCXPRT *xprt;
-	char path[MAXPATHLEN];
-	int fd = -1, error, i, try_count;
-	CLIENT *cl, *oldcl[RPCTLS_SRV_MAXNPROCS];
+	int fd = -1, error;
 	uint64_t ssl[3];
-	struct timeval timeo;
-#ifdef KERN_TLS
-	u_int maxlen;
-#endif
         
 	error = priv_check(td, PRIV_NFS_DAEMON);
 	if (error != 0)
@@ -193,183 +180,48 @@ sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap)
 
 	KRPC_CURVNET_SET(KRPC_TD_TO_VNET(td));
 	switch (uap->op) {
-	case RPCTLS_SYSC_SRVSTARTUP:
-		if (jailed(curthread->td_ucred) &&
-		    !prison_check_nfsd(curthread->td_ucred))
-			error = EPERM;
-		if (error == 0) {
-			/* Get rid of all old CLIENTs. */
-			mtx_lock(&rpctls_server_lock);
-			for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) {
-				oldcl[i] = KRPC_VNET(rpctls_server_handle)[i];
-				KRPC_VNET(rpctls_server_handle)[i] = NULL;
-				KRPC_VNET(rpctls_server_busy)[i] = false;
-			}
-			KRPC_VNET(rpctls_srv_newdaemon) = true;
-			KRPC_VNET(rpctls_srv_prevproc) = 0;
-			mtx_unlock(&rpctls_server_lock);
-			for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) {
-				if (oldcl[i] != NULL) {
-					CLNT_CLOSE(oldcl[i]);
-					CLNT_RELEASE(oldcl[i]);
-				}
-			}
-		}
-		break;
-	case RPCTLS_SYSC_SRVSETPATH:
-		if (jailed(curthread->td_ucred) &&
-		    !prison_check_nfsd(curthread->td_ucred))
-			error = EPERM;
-		if (error == 0)
-			error = copyinstr(uap->path, path, sizeof(path), NULL);
-		if (error == 0) {
-			error = ENXIO;
-#ifdef KERN_TLS
-			if (rpctls_getinfo(&maxlen, false, false))
-				error = 0;
-#endif
-		}
-		if (error == 0 && (strlen(path) + 1 > sizeof(sun.sun_path) ||
-		    strlen(path) == 0))
-			error = EINVAL;
-	
-		cl = NULL;
-		if (error == 0) {
-			sun.sun_family = AF_LOCAL;
-			strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
-			sun.sun_len = SUN_LEN(&sun);
-			
-			nconf = getnetconfigent("local");
-			cl = clnt_reconnect_create(nconf,
-			    (struct sockaddr *)&sun, RPCTLSSD, RPCTLSSDVERS,
-			    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
-			/*
-			 * The number of retries defaults to INT_MAX, which
-			 * effectively means an infinite, uninterruptable loop. 
-			 * Set the try_count to 1 so that no retries of the
-			 * RPC occur.  Since it is an upcall to a local daemon,
-			 * requests should not be lost and doing one of these
-			 * RPCs multiple times is not correct.
-			 * Set a timeout (currently 15sec) and assume that
-			 * the daemon is hung if a timeout occurs.
-			 */
-			if (cl != NULL) {
-				try_count = 1;
-				CLNT_CONTROL(cl, CLSET_RETRIES, &try_count);
-				timeo.tv_sec = 15;
-				timeo.tv_usec = 0;
-				CLNT_CONTROL(cl, CLSET_TIMEOUT, &timeo);
-			} else
-				error = EINVAL;
-		}
-	
-		for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++)
-			oldcl[i] = NULL;
-		mtx_lock(&rpctls_server_lock);
-		if (KRPC_VNET(rpctls_srv_newdaemon)) {
-			/*
-			 * For a new daemon, the rpctls_srv_handles have
-			 * already been cleaned up by RPCTLS_SYSC_SRVSTARTUP.
-			 * Scan for an available array entry to use.
-			 */
-			for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) {
-				if (KRPC_VNET(rpctls_server_handle)[i] == NULL)
-					break;
-			}
-			if (i == RPCTLS_SRV_MAXNPROCS && error == 0)
-				error = ENXIO;
-		} else {
-			/* For an old daemon, clear out old CLIENTs. */
-			for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) {
-				oldcl[i] = KRPC_VNET(rpctls_server_handle)[i];
-				KRPC_VNET(rpctls_server_handle)[i] = NULL;
-				KRPC_VNET(rpctls_server_busy)[i] = false;
-			}
-			i = 0;	/* Set to use rpctls_server_handle[0]. */
-		}
-		if (error == 0)
-			KRPC_VNET(rpctls_server_handle)[i] = cl;
-		mtx_unlock(&rpctls_server_lock);
-
-		for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) {
-			if (oldcl[i] != NULL) {
-				CLNT_CLOSE(oldcl[i]);
-				CLNT_RELEASE(oldcl[i]);
-			}
-		}
-		break;
-	case RPCTLS_SYSC_SRVSHUTDOWN:
-		mtx_lock(&rpctls_server_lock);
-		for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) {
-			oldcl[i] = KRPC_VNET(rpctls_server_handle)[i];
-			KRPC_VNET(rpctls_server_handle)[i] = NULL;
-		}
-		KRPC_VNET(rpctls_srv_newdaemon) = false;
-		mtx_unlock(&rpctls_server_lock);
-	
-		for (i = 0; i < RPCTLS_SRV_MAXNPROCS; i++) {
-			if (oldcl[i] != NULL) {
-				CLNT_CLOSE(oldcl[i]);
-				CLNT_RELEASE(oldcl[i]);
-			}
-		}
-		break;
 	case RPCTLS_SYSC_CLSOCKET:
-		mtx_lock(&rpctls_connect_lock);
+	case RPCTLS_SYSC_SRVSOCKET:
+		mtx_lock(&rpctls_lock);
 		ups = RB_FIND(upsock_t, &upcall_sockets,
 		    &(struct upsock){
 		    .so = __DECONST(struct socket *, uap->path) });
 		if (__predict_true(ups != NULL))
 			RB_REMOVE(upsock_t, &upcall_sockets, ups);
-		mtx_unlock(&rpctls_connect_lock);
+		mtx_unlock(&rpctls_lock);
 		if (ups == NULL) {
 			printf("%s: socket lookup failed\n", __func__);
 			error = EPERM;
 			break;
 		}
-		error = falloc(td, &fp, &fd, 0);
-		if (error == 0) {
+		if ((error = falloc(td, &fp, &fd, 0)) != 0)
+			break;
+		soref(ups->so);
+		switch (uap->op) {
+		case RPCTLS_SYSC_CLSOCKET:
 			/*
 			 * Set ssl refno so that clnt_vc_destroy() will
 			 * not close the socket and will leave that for
 			 * the daemon to do.
 			 */
-			soref(ups->so);
 			ssl[0] = ssl[1] = 0;
 			ssl[2] = RPCTLS_REFNO_HANDSHAKE;
 			CLNT_CONTROL(ups->cl, CLSET_TLS, ssl);
-			finit(fp, FREAD | FWRITE, DTYPE_SOCKET, ups->so,
-			    &socketops);
-			fdrop(fp, td);	/* Drop fp reference. */
-			td->td_retval[0] = fd;
+			break;
+		case RPCTLS_SYSC_SRVSOCKET:
+			/*
+			 * Once this file descriptor is associated
+			 * with the socket, it cannot be closed by
+			 * the server side krpc code (svc_vc.c).
+			 */
+			sx_xlock(&ups->xp->xp_lock);
+			ups->xp->xp_tls = RPCTLS_FLAGS_HANDSHFAIL;
+			sx_xunlock(&ups->xp->xp_lock);
+			break;
 		}
-		break;
-	case RPCTLS_SYSC_SRVSOCKET:
-		mtx_lock(&rpctls_server_lock);
-		so = KRPC_VNET(rpctls_server_so);
-		KRPC_VNET(rpctls_server_so) = NULL;
-		xprt = KRPC_VNET(rpctls_server_xprt);
-		KRPC_VNET(rpctls_server_xprt) = NULL;
-		mtx_unlock(&rpctls_server_lock);
-		if (so != NULL) {
-			error = falloc(td, &fp, &fd, 0);
-			if (error == 0) {
-				/*
-				 * Once this file descriptor is associated
-				 * with the socket, it cannot be closed by
-				 * the server side krpc code (svc_vc.c).
-				 */
-				soref(so);
-				sx_xlock(&xprt->xp_lock);
-				xprt->xp_tls = RPCTLS_FLAGS_HANDSHFAIL;
-				sx_xunlock(&xprt->xp_lock);
-				finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so,
-				    &socketops);
-				fdrop(fp, td);	/* Drop fp reference. */
-				td->td_retval[0] = fd;
-			}
-		} else
-			error = EPERM;
+		finit(fp, FREAD | FWRITE, DTYPE_SOCKET, ups->so, &socketops);
+		fdrop(fp, td);	/* Drop fp reference. */
+		td->td_retval[0] = fd;
 		break;
 	default:
 		error = EINVAL;
@@ -379,25 +231,6 @@ sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap)
 	return (error);
 }
 
-/*
- * Acquire the rpctls_server_handle and return it with a reference count,
- * if it is available.
- */
-static CLIENT *
-rpctls_server_client(int procpos)
-{
-	CLIENT *cl;
-
-	KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread));
-	mtx_lock(&rpctls_server_lock);
-	cl = KRPC_VNET(rpctls_server_handle)[procpos];
-	if (cl != NULL)
-		CLNT_ACQUIRE(cl);
-	mtx_unlock(&rpctls_server_lock);
-	KRPC_CURVNET_RESTORE();
-	return (cl);
-}
-
 /* Do an upcall for a new socket connect using TLS. */
 enum clnt_stat
 rpctls_connect(CLIENT *newclient, char *certname, struct socket *so,
@@ -428,9 +261,9 @@ rpctls_connect(CLIENT *newclient, char *certname, struct socket *so,
 	if (stat != RPC_SUCCESS)
 		return (RPC_SYSTEMERROR);
 
-	mtx_lock(&rpctls_connect_lock);
+	mtx_lock(&rpctls_lock);
 	RB_INSERT(upsock_t, &upcall_sockets, &ups);
-	mtx_unlock(&rpctls_connect_lock);
+	mtx_unlock(&rpctls_lock);
 
 	/* Temporarily block reception during the handshake upcall. */
 	val = 1;
@@ -455,12 +288,12 @@ rpctls_connect(CLIENT *newclient, char *certname, struct socket *so,
 			*sslp = res.ssl;
 		}
 	} else {
-		mtx_lock(&rpctls_connect_lock);
+		mtx_lock(&rpctls_lock);
 		if (RB_FIND(upsock_t, &upcall_sockets, &ups)) {
 			struct upsock *removed __diagused;
 
 			removed = RB_REMOVE(upsock_t, &upcall_sockets, &ups);
-			mtx_unlock(&rpctls_connect_lock);
+			mtx_unlock(&rpctls_lock);
 			MPASS(removed == &ups);
 			/*
 			 * Do a shutdown on the socket, since the daemon is
@@ -475,7 +308,7 @@ rpctls_connect(CLIENT *newclient, char *certname, struct socket *so,
 			 * The daemon has taken the socket from the tree, but
 			 * failed to do the handshake.
 			 */
-			mtx_unlock(&rpctls_connect_lock);
+			mtx_unlock(&rpctls_lock);
 		}
 	}
 
@@ -513,20 +346,13 @@ rpctls_srv_handlerecord(uint64_t sec, uint64_t usec, uint64_t ssl, int procpos,
 	struct rpctlssd_handlerecord_arg arg;
 	struct rpctlssd_handlerecord_res res;
 	enum clnt_stat stat;
-	CLIENT *cl;
-
-	cl = rpctls_server_client(procpos);
-	if (cl == NULL) {
-		*reterr = RPCTLSERR_NOSSL;
-		return (RPC_SUCCESS);
-	}
+	CLIENT *cl = KRPC_VNET(rpctls_server_handle);
 
 	/* Do the handlerecord upcall. */
 	arg.sec = sec;
 	arg.usec = usec;
 	arg.ssl = ssl;
 	stat = rpctlssd_handlerecord_1(&arg, &res, cl);
-	CLNT_RELEASE(cl);
 	if (stat == RPC_SUCCESS)
 		*reterr = res.reterr;
 	return (stat);
@@ -559,20 +385,13 @@ rpctls_srv_disconnect(uint64_t sec, uint64_t usec, uint64_t ssl, int procpos,
 	struct rpctlssd_disconnect_arg arg;
 	struct rpctlssd_disconnect_res res;
 	enum clnt_stat stat;
-	CLIENT *cl;
-
-	cl = rpctls_server_client(procpos);
-	if (cl == NULL) {
-		*reterr = RPCTLSERR_NOSSL;
-		return (RPC_SUCCESS);
-	}
+	CLIENT *cl = KRPC_VNET(rpctls_server_handle);
 
 	/* Do the disconnect upcall. */
 	arg.sec = sec;
 	arg.usec = usec;
 	arg.ssl = ssl;
 	stat = rpctlssd_disconnect_1(&arg, &res, cl);
-	CLNT_RELEASE(cl);
 	if (stat == RPC_SUCCESS)
 		*reterr = res.reterr;
 	return (stat);
@@ -584,54 +403,33 @@ rpctls_server(SVCXPRT *xprt, struct socket *so, uint32_t *flags, uint64_t *sslp,
     uid_t *uid, int *ngrps, gid_t **gids, int *procposp)
 {
 	enum clnt_stat stat;
-	CLIENT *cl;
+	struct upsock ups = {
+		.so = so,
+		.xp = xprt,
+	};
+	CLIENT *cl = KRPC_VNET(rpctls_server_handle);
+	struct rpctlssd_connect_arg arg;
 	struct rpctlssd_connect_res res;
 	gid_t *gidp;
 	uint32_t *gidv;
-	int i, procpos;
-
-	KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread));
-	cl = NULL;
-	procpos = -1;
-	mtx_lock(&rpctls_server_lock);
-	for (i = (KRPC_VNET(rpctls_srv_prevproc) + 1) % RPCTLS_SRV_MAXNPROCS;
-	    i != KRPC_VNET(rpctls_srv_prevproc);
-	    i = (i + 1) % RPCTLS_SRV_MAXNPROCS) {
-		if (KRPC_VNET(rpctls_server_handle)[i] != NULL)
-			break;
-	}
-	if (i == KRPC_VNET(rpctls_srv_prevproc)) {
-		if (KRPC_VNET(rpctls_server_handle)[i] != NULL)
-			procpos = i;
-	} else
-		KRPC_VNET(rpctls_srv_prevproc) = procpos = i;
-	mtx_unlock(&rpctls_server_lock);
-	if (procpos >= 0)
-		cl = rpctls_server_client(procpos);
-	if (cl == NULL) {
-		KRPC_CURVNET_RESTORE();
-		return (RPC_SYSTEMERROR);
-	}
+	int i;
 
-	/* Serialize the server upcalls. */
-	mtx_lock(&rpctls_server_lock);
-	while (KRPC_VNET(rpctls_server_busy)[procpos])
-		msleep(&KRPC_VNET(rpctls_server_busy)[procpos],
-		    &rpctls_server_lock, PVFS, "rtlssn", 0);
-	KRPC_VNET(rpctls_server_busy)[procpos] = true;
-	KRPC_VNET(rpctls_server_so) = so;
-	KRPC_VNET(rpctls_server_xprt) = xprt;
-	mtx_unlock(&rpctls_server_lock);
+	mtx_lock(&rpctls_lock);
+	RB_INSERT(upsock_t, &upcall_sockets, &ups);
+	mtx_unlock(&rpctls_lock);
 
 	/* Do the server upcall. */
 	res.gid.gid_val = NULL;
-	stat = rpctlssd_connect_1(NULL, &res, cl);
+	arg.socookie = (uintptr_t)so;
+	stat = rpctlssd_connect_1(&arg, &res, cl);
 	if (stat == RPC_SUCCESS) {
+#ifdef INVARIANTS
+		MPASS((RB_FIND(upsock_t, &upcall_sockets, &ups) == NULL));
+#endif
 		*flags = res.flags;
 		*sslp++ = res.sec;
 		*sslp++ = res.usec;
 		*sslp = res.ssl;
-		*procposp = procpos;
 		if ((*flags & (RPCTLS_FLAGS_CERTUSER |
 		    RPCTLS_FLAGS_DISABLED)) == RPCTLS_FLAGS_CERTUSER) {
 			*ngrps = res.gid.gid_len;
@@ -641,27 +439,32 @@ rpctls_server(SVCXPRT *xprt, struct socket *so, uint32_t *flags, uint64_t *sslp,
 			for (i = 0; i < *ngrps; i++)
 				*gidp++ = *gidv++;
 		}
-	} else if (stat == RPC_TIMEDOUT) {
-		/*
-		 * Do a shutdown on the socket, since the daemon is probably
-		 * stuck in SSL_accept() trying to read the socket.
-		 * Do not soclose() the socket, since the daemon will close()
-		 * the socket after SSL_accept() returns an error.
-		 */
-		soshutdown(so, SHUT_RD);
+	} else {
+		mtx_lock(&rpctls_lock);
+		if (RB_FIND(upsock_t, &upcall_sockets, &ups)) {
+			struct upsock *removed __diagused;
+
+			removed = RB_REMOVE(upsock_t, &upcall_sockets, &ups);
+			mtx_unlock(&rpctls_lock);
+			MPASS(removed == &ups);
+			/*
+			 * Do a shutdown on the socket, since the daemon is
+			 * probably stuck in SSL_accept() trying to read the
+			 * socket.  Do not soclose() the socket, since the
+			 * daemon will close() the socket after SSL_accept()
+			 * returns an error.
+			 */
+			soshutdown(so, SHUT_RD);
+		} else {
+			/*
+			 * The daemon has taken the socket from the tree, but
+			 * failed to do the handshake.
+			 */
+			mtx_unlock(&rpctls_lock);
+		}
 	}
-	CLNT_RELEASE(cl);
 	mem_free(res.gid.gid_val, 0);
 
-	/* Once the upcall is done, the daemon is done with the fp and so. */
-	mtx_lock(&rpctls_server_lock);
-	KRPC_VNET(rpctls_server_so) = NULL;
-	KRPC_VNET(rpctls_server_xprt) = NULL;
-	KRPC_VNET(rpctls_server_busy)[procpos] = false;
-	wakeup(&KRPC_VNET(rpctls_server_busy)[procpos]);
-	mtx_unlock(&rpctls_server_lock);
-	KRPC_CURVNET_RESTORE();
-
 	return (stat);
 }
 
@@ -789,13 +592,6 @@ rpctls_getinfo(u_int *maxlenp, bool rpctlscd_run, bool rpctlssd_run)
 	    &maxlen, &siz, NULL, 0, NULL, 0);
 	if (error != 0)
 		return (false);
-	KRPC_CURVNET_SET_QUIET(KRPC_TD_TO_VNET(curthread));
-	if (rpctlssd_run && KRPC_VNET(rpctls_server_handle)[0] == NULL) {
-		KRPC_CURVNET_RESTORE();
-		return (false);
-	}
-	KRPC_CURVNET_RESTORE();
 	*maxlenp = maxlen;
 	return (enable);
 }
-
diff --git a/sys/rpc/rpcsec_tls/rpctlssd.x b/sys/rpc/rpcsec_tls/rpctlssd.x
index 922583284b11..e9afca084ada 100644
--- a/sys/rpc/rpcsec_tls/rpctlssd.x
+++ b/sys/rpc/rpcsec_tls/rpctlssd.x
@@ -27,6 +27,9 @@
 
 /* Modified from gssd.x for the server side of RPC-over-TLS. */
 
+struct rpctlssd_connect_arg {
+	uint64_t socookie;
+};
 
 struct rpctlssd_connect_res {
 	uint32_t flags;
@@ -62,7 +65,7 @@ program RPCTLSSD {
 		void RPCTLSSD_NULL(void) = 0;
 
 		rpctlssd_connect_res
-		RPCTLSSD_CONNECT(void) = 1;
+		RPCTLSSD_CONNECT(rpctlssd_connect_arg) = 1;
 
 		rpctlssd_handlerecord_res
 		RPCTLSSD_HANDLERECORD(rpctlssd_handlerecord_arg) = 2;