git: c04ca8bd36f7 - releng/15.1 - rpcsec_tls: Avoid a socket reference underflow in rpctls_server()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 30 Jun 2026 17:21:51 UTC
The branch releng/15.1 has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=c04ca8bd36f778a8190e5aa3249075929a916dbe
commit c04ca8bd36f778a8190e5aa3249075929a916dbe
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-06-15 15:52:24 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-06-29 19:16:40 +0000
rpcsec_tls: Avoid a socket reference underflow in rpctls_server()
The upcall_sockets tree owns a ref on any resident socket. When a
socket is removed after a TLS handshake failure, rpctls_rpc_failed()
thus calls soclose().
rpctls_server() does not acquire an extra ref to compensate for this.
So, if the upcall fails, e.g., because rpc.tlsservd is not running,
we'll call soclose() to drop the reference, but this effectively
releases the xprt layer's reference.
Fix the problem by explicitly acquiring a socket reference when adding
a socket to the upcall tree.
Approved by: so
Security: FreeBSD-EN-26:17.rpcsec_tls
PR: 289734
Reviewed by: rmacklem, glebius
MFC after: 1 week
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D57555
(cherry picked from commit fc7993cf2d6ddba9f94683565838bf8fabc0145c)
(cherry picked from commit f3b14134dec11c2f09980f25c4c60accbfea0f1e)
---
sys/rpc/rpcsec_tls/rpctls_impl.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/sys/rpc/rpcsec_tls/rpctls_impl.c b/sys/rpc/rpcsec_tls/rpctls_impl.c
index 22ba699a6fab..d8d4a240e0b9 100644
--- a/sys/rpc/rpcsec_tls/rpctls_impl.c
+++ b/sys/rpc/rpcsec_tls/rpctls_impl.c
@@ -190,7 +190,6 @@ sys_rpctls_syscall(struct thread *td, struct rpctls_syscall_args *uap)
KRPC_CURVNET_RESTORE();
return (error);
}
- soref(ups.so);
if (ups.server) {
/*
* Once this file descriptor is associated
@@ -277,6 +276,7 @@ rpctls_connect(CLIENT *newclient, char *certname, struct socket *so,
if (stat != RPC_SUCCESS)
return (RPC_SYSTEMERROR);
+ soref(so);
mtx_lock(&rpctls_lock);
RB_INSERT(upsock_t, &upcall_sockets, &ups);
mtx_unlock(&rpctls_lock);
@@ -294,9 +294,16 @@ rpctls_connect(CLIENT *newclient, char *certname, struct socket *so,
stat = rpctlscd_connect_2(&arg, &res, rpctls_connect_handle);
if (stat == RPC_SUCCESS)
*reterr = res.reterr;
- else
+ else {
rpctls_rpc_failed(&ups, so);
+ /*
+ * The socket was closed, make sure the krpc code doesn't close
+ * it a second time.
+ */
+ CLNT_CONTROL(newclient, CLSET_TLS, &(int){RPCTLS_INHANDSHAKE});
+ }
+
/* Unblock reception. */
CLNT_CONTROL(newclient, CLSET_BLOCKRCV, &(int){0});
@@ -388,6 +395,7 @@ rpctls_server(SVCXPRT *xprt, uint32_t *flags, uid_t *uid, int *ngrps,
uint32_t *gidv;
int i;
+ soref(xprt->xp_socket);
mtx_lock(&rpctls_lock);
RB_INSERT(upsock_t, &upcall_sockets, &ups);
mtx_unlock(&rpctls_lock);
@@ -407,9 +415,18 @@ rpctls_server(SVCXPRT *xprt, uint32_t *flags, uid_t *uid, int *ngrps,
for (i = 0; i < *ngrps; i++)
*gidp++ = *gidv++;
}
- } else
+ } else {
rpctls_rpc_failed(&ups, xprt->xp_socket);
+ /*
+ * The socket was closed, make sure the krpc code doesn't close
+ * it a second time.
+ */
+ sx_xlock(&ups.xp->xp_lock);
+ ups.xp->xp_tls = RPCTLS_FLAGS_HANDSHFAIL;
+ sx_xunlock(&ups.xp->xp_lock);
+ }
+
mem_free(res.gid.gid_val, 0);
#ifdef INVARIANTS