FreeRDP: Fix bypass of CVE-2026-91962: UINT32 overflow in audin Apple backends (audin_mac.m, audin_ios.m)
What fixes it
- 3.32.0FreeRDP, cGitHub
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Summary
The fix for CVE-2026-91962 (commit 3bf07d44, "[channels,audin] limit FramesPerPacket") rejects FramesPerPacket >= INT32_MAX in audin_main.c:500. However, the Apple backends compute the audio queue buffer size as FramesPerPacket * 2 * nChannels in UINT32 arithmetic at audin_mac.m:277 and audin_ios.m:245. Values that pass the guard still wrap the multiplication to 0 or tiny sizes, yielding undersized AudioQueueAllocateBuffer allocations and the same heap out-of-bounds write the original CVE described.
Details
**Fix in audin_main.c:500 (incomplete):**
/* allows FramesPerPacket from 0 to 2,147,483,646 */
if (FramesPerPacket >= INT32_MAX)
return ERROR_INVALID_DATA;**Vulnerable expression — unchanged by the fix — in audin_mac.m:277 and audin_ios.m:245:**
devStat = AudioQueueAllocateBuffer(mac->audioQueue,
mac->FramesPerPacket * 2 * mac->format.nChannels, /* UINT32 — no overflow check */
&mac->audioBuffers[index]);FramesPerPacket is declared UINT32 (audin_mac.m:71, audin_ios.m:59). The multiplication stays in 32-bit unsigned arithmetic; any product above 4,294,967,295 wraps modulo 2³².
The Mac backend enforces nChannels == 2 (audin_mac_format_supported, line 121), so the effective expression is FramesPerPacket × 4:
FramesPerPacket = 2^30 = 1,073,741,824— passes the INT32_MAX check (< 2,147,483,647)1,073,741,824 × 2 × 2 = 4,294,967,296→ UINT32 wraps to 0 bytesFramesPerPacket = 2^30 + 4 = 1,073,741,828→ wraps to 16 bytes; real audio ≈ 4.29 GB per callback
PoC
Compiled and executed on macOS Darwin 25.3.0 arm64 (Apple clang 21.0):
uint32_t FramesPerPacket = (1u << 30); /* 2^30 — passes INT32_MAX check */ uint16_t nChannels = 2; uint32_t buf_size = FramesPerPacket * 2 * (uint32_t)nChannels; /* wraps to 0 */ void *p = malloc(0); /* macOS returns non-NULL: p = 0x1048718d0 */ /* AudioQueueAllocateBuffer(..., 0, &buf) => noErr */ /* audio capture callback writes ~GB into 0-byte buf */ /* => heap out-of-bounds write */
Live output:
Case A: FramesPerPacket = 1073741824 (2^30) Passes INT32_MAX check: YES (bypass!) UINT32: 1073741824 * 2 * 2 = 4294967296 -> wraps to 0 bytes Case B: FramesPerPacket = 1073741828 (2^30+4) Passes INT32_MAX check: YES (bypass!) UINT32: 1073741828 * 2 * 2 = 4294967312 -> wraps to 16 bytes Real audio data per callback: ~4.29 GB written into 16 bytes malloc(0) = 0x1048718d0 (non-NULL — heap pointer returned on macOS) => AudioQueueAllocateBuffer succeeds, error check passes, OOB write follows
Suggested fix:
/* Option A: widen to UINT64 in each Apple backend */
const UINT64 bufSize = (UINT64)mac->FramesPerPacket * 2U
* (UINT64)mac->format.nChannels;
if (bufSize == 0 || bufSize > UINT32_MAX)
return ERROR_INVALID_DATA;
/* Option B: tighten guard in audin_main.c (covers all backends) */
if (FramesPerPacket == 0 || FramesPerPacket > UINT32_MAX / 4U)
return ERROR_INVALID_DATA;Impact
Heap out-of-bounds write in the audio input path of FreeRDP clients on macOS and iOS when connecting to a malicious RDP server. An attacker operating a malicious RDP server can trigger this by advertising the audin virtual channel and sending FramesPerPacket = 2^30 in the Open PDU. No client-side user interaction beyond connecting is required (the server controls the audin negotiation).
Potential impact: crash or client-side code execution (CWE-190, CWE-787). Same severity class as CVE-2026-91962. The fix shipped in 3.31.0 does not protect macOS or iOS clients.
Text from GitHub Advisory Database
Affected versions 1
- FreeRDP, c<= 3.31.0GitHub