Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Sep 2021 13:32:11 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: e9e4f8092c2e - stable/13 - socket: Fix a use-after-free in soclose()
Message-ID:  <202109241332.18ODWB08087029@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by markj:

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

commit e9e4f8092c2e0ccac922f930072cd14b22ee7c1c
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2021-09-17 16:26:06 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-09-24 13:01:51 +0000

    socket: Fix a use-after-free in soclose()
    
    After releasing the fd reference to a socket "so", we should avoid
    testing SOLISTENING(so) since the socket may have been freed.  Instead,
    directly test whether the list of unaccepted sockets is empty.
    
    Fixes:          f4bb1869ddd2 ("Consistently use the SOLISTENING() macro")
    Pointy hat:     markj
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit dfcef8771484271f2bccdb1dbc088a838441c5a7)
---
 sys/kern/uipc_socket.c | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index dc7407808535..13482fce5980 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1176,6 +1176,7 @@ int
 soclose(struct socket *so)
 {
 	struct accept_queue lqueue;
+	struct socket *sp, *tsp;
 	int error = 0;
 
 	KASSERT(!(so->so_state & SS_NOFDREF), ("soclose: SS_NOFDREF on enter"));
@@ -1210,11 +1211,9 @@ drop:
 	if (so->so_proto->pr_usrreqs->pru_close != NULL)
 		(*so->so_proto->pr_usrreqs->pru_close)(so);
 
+	TAILQ_INIT(&lqueue);
 	SOCK_LOCK(so);
 	if (SOLISTENING(so)) {
-		struct socket *sp;
-
-		TAILQ_INIT(&lqueue);
 		TAILQ_SWAP(&lqueue, &so->sol_incomp, socket, so_list);
 		TAILQ_CONCAT(&lqueue, &so->sol_comp, so_list);
 
@@ -1232,17 +1231,14 @@ drop:
 	KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF"));
 	so->so_state |= SS_NOFDREF;
 	sorele(so);
-	if (SOLISTENING(so)) {
-		struct socket *sp, *tsp;
-
-		TAILQ_FOREACH_SAFE(sp, &lqueue, so_list, tsp) {
-			SOCK_LOCK(sp);
-			if (sp->so_count == 0) {
-				SOCK_UNLOCK(sp);
-				soabort(sp);
-			} else
-				/* sp is now in sofree() */
-				SOCK_UNLOCK(sp);
+	TAILQ_FOREACH_SAFE(sp, &lqueue, so_list, tsp) {
+		SOCK_LOCK(sp);
+		if (refcount_load(&sp->so_count) == 0) {
+			SOCK_UNLOCK(sp);
+			soabort(sp);
+		} else {
+			/* sp is now in sofree() */
+			SOCK_UNLOCK(sp);
 		}
 	}
 	CURVNET_RESTORE();



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109241332.18ODWB08087029>