CVE-2023-39350: Integer Underflow (Wrap or Wraparound) (CWE-191)
value: FreeRDP is a free implementation of the Remote Desktop Protocol (RDP), released under the Apache license. This issue affects Clients only. Integer underflow leading to DOS (e.g. abort due to `WINPR_ASSERT` with default compilation flags). When an insufficient blockLen is provided, and proper length validation is not performed, an Integer Underflow occurs, leading to a Denial of Service (DOS) vulnerability. This issue has been addressed in versions 2.11.0 and 3.0.0-beta3. Users are advised to upgrade. There are no known workarounds for this vulnerability.

CWE description: The product subtracts one value from another, such that the result is less than the minimum allowable integer value, which produces a value that is not equal to the correct result.
CVSS v3 base score: 7.5
Published: 2023-08-31T20:15Z
Repository: https://github.com/FreeRDP/FreeRDP
Language: C
Files changed: libfreerdp/codec/rfx.c
Commit date: 2023-08-21 11:41:06 +0200
Commit message: [coded,rfx] check indices are within range

reported by @pwn2carr

Diff: diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c
index 58ab10d21b5..3716084b52e 100644
--- a/libfreerdp/codec/rfx.c
+++ b/libfreerdp/codec/rfx.c
@@ -992,10 +992,35 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa
 			}
 
 			Stream_Read_UINT8(sub, tile->quantIdxY);  /* quantIdxY (1 byte) */
 			Stream_Read_UINT8(sub, tile->quantIdxCb); /* quantIdxCb (1 byte) */
 			Stream_Read_UINT8(sub, tile->quantIdxCr); /* quantIdxCr (1 byte) */
+			if (tile->quantIdxY >= context->numQuant)
+			{
+				WLog_Print(context->priv->log, WLOG_ERROR,
+				           "quantIdxY %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxY,
+				           context->numQuant);
+				rc = FALSE;
+				break;
+			}
+			if (tile->quantIdxCb >= context->numQuant)
+			{
+				WLog_Print(context->priv->log, WLOG_ERROR,
+				           "quantIdxCb %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCb,
+				           context->numQuant);
+				rc = FALSE;
+				break;
+			}
+			if (tile->quantIdxCr >= context->numQuant)
+			{
+				WLog_Print(context->priv->log, WLOG_ERROR,
+				           "quantIdxCr %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCr,
+				           context->numQuant);
+				rc = FALSE;
+				break;
+			}
+
 			Stream_Read_UINT16(sub, tile->xIdx);      /* xIdx (2 bytes) */
 			Stream_Read_UINT16(sub, tile->yIdx);      /* yIdx (2 bytes) */
 			Stream_Read_UINT16(sub, tile->YLen);      /* YLen (2 bytes) */
 			Stream_Read_UINT16(sub, tile->CbLen);     /* CbLen (2 bytes) */
 			Stream_Read_UINT16(sub, tile->CrLen);     /* CrLen (2 bytes) */

Fixed code: 			if (tile->quantIdxY >= context->numQuant)
			{
				WLog_Print(context->priv->log, WLOG_ERROR,
				           "quantIdxY %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxY,
				           context->numQuant);
				rc = FALSE;
				break;
			}
			if (tile->quantIdxCb >= context->numQuant)
			{
				WLog_Print(context->priv->log, WLOG_ERROR,
				           "quantIdxCb %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCb,
				           context->numQuant);
				rc = FALSE;
				break;
			}
			if (tile->quantIdxCr >= context->numQuant)
			{
				WLog_Print(context->priv->log, WLOG_ERROR,
				           "quantIdxCr %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCr,
				           context->numQuant);
				rc = FALSE;
				break;
			}