FreeRDP: urbdrc: missing OutputBufferSize validation in urb_isoch_transfer IN path - reachable assertion DoS (CWE-617)
What fixes it
- 3.32.1FreeRDP, 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
urb_isoch_transfer() in channels/urbdrc/client/data_transfer.c reads OutputBufferSize from the network stream (controlled by the RDP server) but validates it only for OUT-direction transfers. For IN-direction, the value flows unchecked into libusb_udev_isoch_transfer(), where WINPR_ASSERTING_INT_CAST(int, BufferSize) fires a reachable assertion when BufferSize > INT32_MAX, terminating the FreeRDP client process. Same class as CVE-2026-91961 (control_transfer path), different function.
Details
File 1: channels/urbdrc/client/data_transfer.c ~line 994 File 2: channels/urbdrc/client/libusb/libusb_udevice.c ~line 1421 Tested on commit: 7c3b4bd CWE: CWE-617 (Reachable Assertion)
Vulnerable code — missing IN-direction check:
Stream_Read_UINT32(s, OutputBufferSize);
if (transferDir == USBD_TRANSFER_DIRECTION_OUT)
{
if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize))
return ERROR_INVALID_DATA;
}
// IN direction: OutputBufferSize is never range-checked before useAssertion fires in libusb backend:
libusb_fill_iso_transfer(
iso_transfer, pdev->libusb_handle,
WINPR_ASSERTING_INT_CAST(uint8_t, EndpointAddress),
Stream_Pointer(user_data->data),
WINPR_ASSERTING_INT_CAST(int, BufferSize), // ← assert fires if BufferSize > INT32_MAX
WINPR_ASSERTING_INT_CAST(int, NumberOfPackets),
func_iso_callback, user_data, Timeout);When BufferSize = 0x80000001: cast to int flips sign positive→negative, WINPR_ASSERTING_INT_CAST sign-check assert fires → winpr_int_assert() (WINPR_NORETURN) → process terminated.
**Contrast — patched libusb_udev_control_transfer has the guard (line ~1456):**
if (*BufferSize > UINT16_MAX) // ← explicit check present here
{
WLog_Print(...);
return FALSE;
}libusb_udev_isoch_transfer has no equivalent check.
PoC
Malicious RDP server sends TS_URB_ISOCH_TRANSFER with:
TransferDirection = USBD_TRANSFER_DIRECTION_INNumberOfPackets = 1(valid, passes stream length check)OutputBufferSize = 0x80000001
Client reads OutputBufferSize without bounds check (IN path skips validation), passes it to libusb_udev_isoch_transfer, WINPR_ASSERTING_INT_CAST(int, 0x80000001) sign-check fails → assertion → client crashes.
Impact
A malicious or compromised RDP server can crash the FreeRDP client via the USB redirection channel (URBDRC). Denial of Service. No user interaction required beyond connecting to the server.
Proposed Fix
Add bounds check in libusb_udev_isoch_transfer before the cast:
if (BufferSize > (UINT32)INT32_MAX)
{
WLog_Print(urbdrc->log, WLOG_ERROR,
"BufferSize %" PRIu32 " > INT32_MAX, rejecting isoch transfer", BufferSize);
async_transfer_user_data_free(user_data);
return -1;
}Text from GitHub Advisory Database
Affected versions 1
- FreeRDP, c<= 3.32.0GitHub