The branch main has been updated by christos:

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

commit 0bd5ef6b43633a3cf77495a087a9376b2b3b11c9
Author:     Christos Margiolis <[email protected]>
AuthorDate: 2026-05-29 11:32:42 +0000
Commit:     Christos Margiolis <[email protected]>
CommitDate: 2026-06-11 09:30:22 +0000

    virtual_oss(8): Properly cleanup cuse(3)
    
    virtual_oss(8) does not currently keep track of the cuse(3) it creates,
    nor does it destroy any of them on exit, except for the control device.
    This is harmless if virtual_oss(8) is killed after all audio streams
    have been shut down, but if it's killed during I/O, the process hangs
    and/or goes into uninterruptible sleep state.
    
    To fix this, have pointers to all cuse(3) devices, and explicitly
    destroy them on exit. Also make sure we don't leak memory in
    dup_profile().
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Reviewed by:    jrm
    Pull-Request:   https://ron-dev.freebsd.org/FreeBSD/src/pulls/41
---
 usr.sbin/virtual_oss/virtual_oss/int.h  |  2 ++
 usr.sbin/virtual_oss/virtual_oss/main.c | 39 +++++++++++++++++++++++++++++----
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/usr.sbin/virtual_oss/virtual_oss/int.h 
b/usr.sbin/virtual_oss/virtual_oss/int.h
index 974f1a51f573..7b7cabd62743 100644
--- a/usr.sbin/virtual_oss/virtual_oss/int.h
+++ b/usr.sbin/virtual_oss/virtual_oss/int.h
@@ -122,6 +122,8 @@ struct virtual_profile {
        vclient_head_t head;
        char oss_name[VMAX_STRING];
        char wav_name[VMAX_STRING];
+       struct cuse_dev *oss_dev;
+       struct cuse_dev *wav_dev;
        uint32_t rx_filter_size;
        uint32_t tx_filter_size;
        double *rx_filter_data[VMAX_CHAN];
diff --git a/usr.sbin/virtual_oss/virtual_oss/main.c 
b/usr.sbin/virtual_oss/virtual_oss/main.c
index 1d24be89f3da..9eafd5549a5c 100644
--- a/usr.sbin/virtual_oss/virtual_oss/main.c
+++ b/usr.sbin/virtual_oss/virtual_oss/main.c
@@ -1858,6 +1858,15 @@ done:
        nvlist_destroy(nvl);
 }
 
+static void
+cleanup_profile(vprofile_t *pvp)
+{
+       if (pvp->oss_dev != NULL)
+               cuse_dev_destroy(pvp->oss_dev);
+       if (pvp->wav_dev != NULL)
+               cuse_dev_destroy(pvp->wav_dev);
+}
+
 static const char *
 dup_profile(vprofile_t *pvp, int *pamp, int pol, int rx_mute,
     int tx_mute, int synchronized, int is_client)
@@ -1865,6 +1874,7 @@ dup_profile(vprofile_t *pvp, int *pamp, int pol, int 
rx_mute,
        vprofile_t *ptr;
        struct cuse_dev *pdev;
        struct group *gr;
+       const char *errstr;
        gid_t gid;
        int x, perm;
 
@@ -1937,9 +1947,10 @@ dup_profile(vprofile_t *pvp, int *pamp, int pol, int 
rx_mute,
                pdev = cuse_dev_create(&vclient_oss_methods, ptr, NULL,
                    0, gid, perm, ptr->oss_name);
                if (pdev == NULL) {
-                       free(ptr);
-                       return ("Could not create CUSE DSP device");
+                       errstr = "Could not create CUSE DSP device";
+                       goto err;
                }
+               ptr->oss_dev = pdev;
 
                /* register to sndstat */
                ptr->fd_sta = open("/dev/sndstat", O_WRONLY);
@@ -1954,9 +1965,10 @@ dup_profile(vprofile_t *pvp, int *pamp, int pol, int 
rx_mute,
                pdev = cuse_dev_create(&vclient_wav_methods, ptr, NULL,
                    0, gid, perm, ptr->wav_name);
                if (pdev == NULL) {
-                       free(ptr);
-                       return ("Could not create CUSE WAV device");
+                       errstr = "Could not create CUSE WAV device";
+                       goto err;
                }
+               ptr->wav_dev = pdev;
        }
 
        atomic_lock();
@@ -1991,6 +2003,13 @@ dup_profile(vprofile_t *pvp, int *pamp, int pol, int 
rx_mute,
        init_compressor(pvp);
 
        return (voss_httpd_start(ptr));
+
+err:
+       cleanup_profile(ptr);
+       free(ptr);
+
+       return (errstr);
+
 }
 
 static void
@@ -2560,6 +2579,7 @@ main(int argc, char **argv)
        const char *ptrerr;
        struct sigaction sa;
        struct cuse_dev *pdev = NULL;
+       struct virtual_profile *pvp;
 
        TAILQ_INIT(&virtual_profile_client_head);
        TAILQ_INIT(&virtual_profile_loopback_head);
@@ -2645,8 +2665,19 @@ main(int argc, char **argv)
 
        destroy_threads();
 
+       /* Destroy CUSE devices */
+
        if (voss_ctl_device[0] != 0)
                cuse_dev_destroy(pdev);
 
+       TAILQ_FOREACH(pvp, &virtual_profile_client_head, entry) {
+               cleanup_profile(pvp);
+       }
+       TAILQ_FOREACH(pvp, &virtual_profile_loopback_head, entry) {
+               cleanup_profile(pvp);
+       }
+
+       cuse_uninit();
+
        return (0);
 }

Reply via email to