git: a46b8546b1c8 - stable/15 - cuse: Fix server reference leak in cuse_client_open()

Christos Margiolis <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a7b68dd.1dcd6.1cd0a338__2045.19780106551$1786472745$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by christos:

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

commit a46b8546b1c8cafc529024aa87ce82ceb7bf84cb
Author:     giacomo <[email protected]>
AuthorDate: 2026-07-15 12:10:54 +0000
Commit:     Christos Margiolis <[email protected]>
CommitDate: 2026-08-11 18:24:04 +0000

    cuse: Fix server reference leak in cuse_client_open()
    
    If the server is closing (or the device node is going away), or if
    devfs_set_cdevpriv() fails, cuse_client_open() returns with the server
    reference taken at the top of the function still held and the newly
    allocated client still linked on pcs->hcli.  Since cuse_client_free()
    has not been registered as the cdevpriv destructor at that point,
    nothing ever undoes this work: every open() that races the is_closing
    window permanently leaks one server reference and one cuse_client.
    
    A leaked reference is fatal on server exit: cuse_server_free()
    busy-waits in an uninterruptible pause("W", hz) loop until pcs->refs
    drops to 1, which now never happens, so the exiting server process
    (e.g. virtual_oss(8)) is left wedged in state "D", immune to SIGKILL,
    cuse.ko is pinned (kldunload hangs too), and only a reboot recovers.
    
    Before 634e578ac7b0 the is_closing error path dropped the reference by
    calling devfs_clear_cdevpriv(), which ran the cuse_client_free()
    destructor.  That commit moved devfs_set_cdevpriv() after the
    is_closing check to fix the panic paths, but left both error returns
    without any cleanup.
    
    Fix by calling cuse_client_free() directly on both error paths.  The
    client is fully constructed and linked on pcs->hcli at these points,
    which is exactly the state cuse_client_free() expects.
    
    PR:             296291
    Fixes:          634e578ac7b0 ("cuse: Fix cdevpriv bugs in cuse_client_open()")
    Assisted-By:    Claude Opus 4.8 (claude-opus-4-8)
    Signed-off-by:  giacomo <[email protected]>
    MFC after:      2 weeks
    Reviewed by:    christos
    Pull-Request:   https://github.com/freebsd/freebsd-src/pull/2324
    
    (cherry picked from commit d83e42234f76504a1ff7f4309ad629b6644bfb16)
---
 sys/fs/cuse/cuse.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c
index 8f67c4b5572b..ef786d125c15 100644
--- a/sys/fs/cuse/cuse.c
+++ b/sys/fs/cuse/cuse.c
@@ -1546,11 +1546,19 @@ cuse_client_open(struct cdev *dev, int fflags, int devtype, struct thread *td)
 	}
 	cuse_server_unlock(pcs);
 
-	if (error != 0)
+	/*
+	 * On error, free the client and unref the server, so that the
+	 * exiting server process does not become unkillable.
+	 */
+	if (error != 0) {
+		cuse_client_free(pcc);
 		return (error);
+	}
 
-	if ((error = devfs_set_cdevpriv(pcc, &cuse_client_free)) != 0)
+	if ((error = devfs_set_cdevpriv(pcc, &cuse_client_free)) != 0) {
+		cuse_client_free(pcc);
 		return (error);
+	}
 
 	pccmd = &pcc->cmds[CUSE_CMD_OPEN];
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.