git: 013af29c1e17 - stable/15 - virtual_oss(8): Properly cleanup cuse(3)
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 18 Jun 2026 19:33:42 UTC
The branch stable/15 has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=013af29c1e1727ae4c8cae8167d4ad55a1c1d778
commit 013af29c1e1727ae4c8cae8167d4ad55a1c1d778
Author: Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-05-29 11:32:42 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2026-06-18 19:33:35 +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
(cherry picked from commit 0bd5ef6b43633a3cf77495a087a9376b2b3b11c9)
---
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 69a943832074..dbe35dbefd58 100644
--- a/usr.sbin/virtual_oss/virtual_oss/int.h
+++ b/usr.sbin/virtual_oss/virtual_oss/int.h
@@ -120,6 +120,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 b66d17d940af..a6cf691e7fbb 100644
--- a/usr.sbin/virtual_oss/virtual_oss/main.c
+++ b/usr.sbin/virtual_oss/virtual_oss/main.c
@@ -1856,6 +1856,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)
@@ -1863,6 +1872,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;
@@ -1935,9 +1945,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);
@@ -1952,9 +1963,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();
@@ -1989,6 +2001,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
@@ -2558,6 +2577,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);
@@ -2643,8 +2663,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);
}