[PATCH v2 0/1] MR10326: Draft: mmdevapi: Avoid copying more memory than reserved in validate_fmt (ASan).
The function `validate_fmt` may receive a pointer which got just reserved memory for the `WAVEFORMATEX`. Unfortunately the assignment `fmt2 = *fmt` always copies the size of `WAVEFORMATEXTENSIBLE`. CC: @giomasce (I currently cannot point to a specific commit, but this may also be related to the recent changes?) <details> <summary>ASan details [gitlab CI](https://gitlab.winehq.org/bernhardu/wine/-/jobs/237050#L2464)</summary> ``` ==qcap_test.exe==728==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x0022c122 at pc 0x785f4342 bp 0x0022bf4c sp 0x0022bb1c READ of size 40 at 0x0022c122 thread T0 #0 0x785f4341 in __asan_memcpy /home/runner/work/llvm-mingw/llvm-mingw/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:65:3 #1 0x778957a5 in validate_fmt /builds/bernhardu/wine/build64/../dlls/mmdevapi/client.c:363:33 #2 0x77896d1e in client_IsFormatSupported /builds/bernhardu/wine/build64/../dlls/mmdevapi/client.c:881:10 #3 0x783e3624 in IAudioClient_IsFormatSupported /builds/bernhardu/wine/build64/include/audioclient.h:406:12 #4 0x783e5cd7 in WINMM_TestFormat /builds/bernhardu/wine/build64/../dlls/winmm/waveform.c:454:10 #5 0x783e5928 in WINMM_GetSupportedFormats /builds/bernhardu/wine/build64/../dlls/winmm/waveform.c:504:14 #6 0x783e553b in WINMM_InitMMDevice /builds/bernhardu/wine/build64/../dlls/winmm/waveform.c:524:35 #7 0x783e4e9b in WINMM_EnumDevices /builds/bernhardu/wine/build64/../dlls/winmm/waveform.c:610:17 #8 0x783d30e8 in WINMM_InitMMDevices /builds/bernhardu/wine/build64/../dlls/winmm/waveform.c:856:10 #9 0x7be4a996 in RtlRunOnceExecuteOnce /builds/bernhardu/wine/build64/../dlls/ntdll/sync.c:462:10 ... Address 0x0022c122 is located in stack of thread T0 at offset 34 in frame #0 0x783e5c0f in WINMM_TestFormat /builds/bernhardu/wine/build64/../dlls/winmm/waveform.c:442 This frame has 2 object(s): [16, 34) 'fmt' (line 443) <== Memory access at offset 34 overflows this variable [80, 84) 'junk' (line 443) HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork (longjmp, SEH and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-buffer-overflow /builds/bernhardu/wine/build64/../dlls/mmdevapi/client.c:363:33 in validate_fmt ``` </details> -- v2: mmdevapi: Avoid copying more memory than reserved in validate_fmt (ASan). https://gitlab.winehq.org/wine/wine/-/merge_requests/10326
From: Bernhard Übelacker <bernhardu@mailbox.org> --- dlls/mmdevapi/client.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c index 4c23905aad8..c765c9fd5f5 100644 --- a/dlls/mmdevapi/client.c +++ b/dlls/mmdevapi/client.c @@ -360,9 +360,14 @@ skip: HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible) { - WAVEFORMATEXTENSIBLE fmt2 = *fmt; + WAVEFORMATEXTENSIBLE fmt2 = {0}; HRESULT ret; + if (fmt->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE || fmt->Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format)) + *(WAVEFORMATEX*)&fmt2 = *(WAVEFORMATEX*)fmt; + else + fmt2 = *fmt; + /* Reduce non-extensible formats to extensible ones. */ if (fmt2.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10326
v2: - compare with the right size, before it was the completely wrong sizeof an integer constant, now it is the bytes a `WAVEFORMATEXTENSIBLE` is bigger than a `WAVEFORMATEX`. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10326#note_132222
Thanks for investigating this. Would you consider this as a fixup? https://gitlab.winehq.org/giomasce/wine/-/commit/0c342aeb3f61c7455487deb684c... Basically it integrates the check with the code immediately following, hopefully making it more linear to understand. It also does the same change to other similar or identical copies of that function. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10326#note_132518
On Wed Mar 18 16:34:37 2026 +0000, Giovanni Mascellani wrote:
Thanks for investigating this. Would you consider this as a fixup? https://gitlab.winehq.org/giomasce/wine/-/commit/0c342aeb3f61c7455487deb684c... Basically it integrates the check with the code immediately following, hopefully making it more linear to understand. It also does the same change to other similar or identical copies of that function. Hello, thanks for taking a look. I put your fixup patch on top of the ASan tree, but received now this failure: https://gitlab.winehq.org/bernhardu/wine/-/jobs/239086#L2792
To make handling this easier, is it ok to squash it into one patch, and add a "Co-authored-by: Giovanni Mascellani <gmascellani@codeweavers.com>"? Is this probably an issue of `WINMM_OpenDevice` by handling all `info->format->wFormatTag` different than `WAVE_FORMAT_PCM` with a `malloc(sizeof(WAVEFORMATEX) + info->format->cbSize)`? Should there be a check for `info->format->wFormatTag == WAVE_FORMAT_EXTENSIBLE`, which then allocates at least the size of `WAVEFORMATEXTENSIBLE`? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10326#note_132653
To make handling this easier, is it ok to squash it into one patch, and add a "Co-authored-by: Giovanni Mascellani gmascellani@codeweavers.com"?
Sure, that's what I intended.
Is this probably an issue of `WINMM_OpenDevice` by handling all `info->format->wFormatTag` different than `WAVE_FORMAT_PCM` with a `malloc(sizeof(WAVEFORMATEX) + info->format->cbSize)`?
Right. Well, let's just move the `cbSize` check before copying the format. I updated the fixup in my branch, can you have another run with it? Thanks for the patience! :-) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10326#note_132980
participants (2)
-
Bernhard Übelacker -
Giovanni Mascellani (@giomasce)