diff options
| author | Christos Margiolis <christos@FreeBSD.org> | 2026-05-29 11:32:42 +0000 |
|---|---|---|
| committer | Christos Margiolis <christos@FreeBSD.org> | 2026-06-11 09:30:22 +0000 |
| commit | 0bd5ef6b43633a3cf77495a087a9376b2b3b11c9 (patch) | |
| tree | 6bc17152559cdc406f49330b3afc188ac4935b32 | |
| parent | 0d644b41d6e485a482040c5e249ec12ff305c8a1 (diff) | |
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
| -rw-r--r-- | usr.sbin/virtual_oss/virtual_oss/int.h | 2 | ||||
| -rw-r--r-- | 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); } |
