Created attachment 237855 [details] Fix the length check for mmap of the dsp sound buffer For some sound cards, the system call mmap(2) consistently fails with EINVAL instead of mapping the sound buffer memory into userspace. It took me a while to figure out a pattern until I found the culprit. What happens: 1) Application does a ioctl(2) query of the dsp sound buffer size (SNDCTL_DSP_GETISPACE or SNDCTL_DSP_GETOSPACE). 2) Application requests to mmap(2) the dsp buffer of that size. 3) The requested memory map length is rounded to page size (vm_mmap() in sys/vm/vm_mmap.c). 4) The device checks that the requested length does not exceed its buffer size (dsp_mmap_single() in sys/dev/sound/pcm/dsp.c). Now because of the rounding in 3), 4) will always fail if the buffer size is not a multiple of the page size. This primarily affects dsp devices with a non-power-of-two number of channels, 24bit sample size, or low-latency sound buffers smaller than one page. I was able to reproduce the problem with multiple sound card setups on both 13.1-RELEASE and 14.0-CURRENT. Proposed fix (see patch attached): Let the device check the requested length against the allocation size of the buffer, which is always whole pages. This still prevents mapping pages which do not belong to the dsp buffer allocation, but works fine with the rounding in 3). Even though the application may now map more than the actual sound buffer (but no more than allocated by the dsp), the additional parts are effectively unused. This fix was tested with multiple sound card setups on 14.0-CURRENT.
@HPS: I hope it's ok to invite you here? Sounds like a topic you'd be interested in.
Looks good. I'll check the patch tomorrow. Do you have a committer? --HPS
(In reply to Hans Petter Selasky from comment #2) Thanks! No committer yet, so you'd be very welcome to do that :-)
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=ad370f7658ba59811d02c04032ac33ef787f752f commit ad370f7658ba59811d02c04032ac33ef787f752f Author: Florian Walpen <dev@submerge.ch> AuthorDate: 2022-11-04 18:04:26 +0000 Commit: Hans Petter Selasky <hselasky@FreeBSD.org> CommitDate: 2022-11-04 18:05:34 +0000 sound(4): Fix memory map of /dev/dsp devices when buffer size is not a multiple of PAGE_SIZE. By using sndbuf_getallocsize() instead of sndbuf_getsize() in dsp_mmap_single(). PR: 267555 MFC after: 1 week Sponsored by: NVIDIA Networking sys/dev/sound/pcm/dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Thank you for the patch! --HPS
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=f0a3d2341d345121c92e01f03d439b054f69793c commit f0a3d2341d345121c92e01f03d439b054f69793c Author: Florian Walpen <dev@submerge.ch> AuthorDate: 2022-11-04 18:04:26 +0000 Commit: Hans Petter Selasky <hselasky@FreeBSD.org> CommitDate: 2022-11-12 12:00:01 +0000 sound(4): Fix memory map of /dev/dsp devices when buffer size is not a multiple of PAGE_SIZE. By using sndbuf_getallocsize() instead of sndbuf_getsize() in dsp_mmap_single(). PR: 267555 Sponsored by: NVIDIA Networking (cherry picked from commit ad370f7658ba59811d02c04032ac33ef787f752f) sys/dev/sound/pcm/dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)