freerdp: patch CVE-2023-39352

Details: https://nvd.nist.gov/vuln/detail/CVE-2023-39352

Backport the commit that was identified[1] by Debian as the solution.

Note: WINPR_ASSERT macro calls have been changed to assert calls, as this
macro doesn't exist yet in this version. Looking at the implementation[2],
it is basically an assert call with a bit verbose logs.
Even though the original implementation also defines a no-op version, the
assert version is enabled by default.

[1]: https://security-tracker.debian.org/tracker/CVE-2023-39352
[2]: https://github.com/FreeRDP/FreeRDP/blob/2.11.0/winpr/include/winpr/assert.h#L31

Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
This commit is contained in:
Gyorgy Sarvari
2026-01-21 08:04:36 +01:00
parent f4a93a4c96
commit c793926ade
2 changed files with 125 additions and 0 deletions
@@ -0,0 +1,124 @@
From 5fbd3aa27780d4c1e4610d1e5f1515f50fc3674b Mon Sep 17 00:00:00 2001
From: Gyorgy Sarvari <skandigraun@gmail.com>
Date: Mon, 22 May 2023 16:03:54 +0800
Subject: [PATCH] add bound check in gdi_SolidFill
From: houchengqiu <houchengqiu@uniontech.com>
In Windows remote run vulnerabillities exe program, to create
Micorosoft::Windows::RDS::Graphics channel, case Remmina crash.
So, add bound check, limit the size of the requested rect, no larger than the surface data buffer.
(cherry picked from commit 6a63441e4ee8e2bf333361f5d24156a183b14ecd)
CVE: CVE-2023-39352
Upstream-Status: Backport [https://github.com/FreeRDP/FreeRDP/commit/856ecaa463e963ecfebc9734423d69139e7b3916]
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
---
libfreerdp/gdi/gfx.c | 70 ++++++++++++++++++++++++++++----------------
1 file changed, 45 insertions(+), 25 deletions(-)
diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c
index a3b7505c5..d2ca9cb63 100644
--- a/libfreerdp/gdi/gfx.c
+++ b/libfreerdp/gdi/gfx.c
@@ -25,6 +25,8 @@
#include "../core/update.h"
+#include <assert.h>
+
#include <freerdp/log.h>
#include <freerdp/gdi/gfx.h>
#include <freerdp/gdi/region.h>
@@ -1079,6 +1081,28 @@ static UINT gdi_DeleteSurface(RdpgfxClientContext* context,
return rc;
}
+static BOOL intersect_rect(const RECTANGLE_16* rect, const gdiGfxSurface* surface,
+ RECTANGLE_16* prect)
+{
+ assert((rect) && "Assert fail: rect");
+ assert((surface) && "Assert fail: surface");
+ assert((prect) && "Assert fail: prect");
+
+ if (rect->left > rect->right)
+ return FALSE;
+ if (rect->left > surface->width)
+ return FALSE;
+ if (rect->top > rect->bottom)
+ return FALSE;
+ if (rect->top > surface->height)
+ return FALSE;
+ prect->left = rect->left;
+ prect->top = rect->top;
+ prect->right = MIN(rect->right, surface->width);
+ prect->bottom = MIN(rect->bottom, surface->height);
+ return TRUE;
+}
+
/**
* Function description
*
@@ -1087,40 +1111,36 @@ static UINT gdi_DeleteSurface(RdpgfxClientContext* context,
static UINT gdi_SolidFill(RdpgfxClientContext* context, const RDPGFX_SOLID_FILL_PDU* solidFill)
{
UINT status = ERROR_INTERNAL_ERROR;
- UINT16 index;
- UINT32 color;
- BYTE a, r, g, b;
- UINT32 nWidth, nHeight;
- RECTANGLE_16* rect;
- gdiGfxSurface* surface;
- RECTANGLE_16 invalidRect;
+ BYTE a = 0;
+ RECTANGLE_16 invalidRect = { 0 };
rdpGdi* gdi = (rdpGdi*)context->custom;
+
EnterCriticalSection(&context->mux);
- surface = (gdiGfxSurface*)context->GetSurfaceData(context, solidFill->surfaceId);
+
+ assert((context->GetSurfaceData) && "Assert fail: context->GetSurfaceData");
+ gdiGfxSurface* surface = (gdiGfxSurface*)context->GetSurfaceData(context, solidFill->surfaceId);
if (!surface)
goto fail;
- b = solidFill->fillPixel.B;
- g = solidFill->fillPixel.G;
- r = solidFill->fillPixel.R;
- /* a = solidFill->fillPixel.XA;
- * Ignore alpha channel, this is a solid fill. */
+ const BYTE b = solidFill->fillPixel.B;
+ const BYTE g = solidFill->fillPixel.G;
+ const BYTE r = solidFill->fillPixel.R;
a = 0xFF;
- color = FreeRDPGetColor(surface->format, r, g, b, a);
+ const UINT32 color = FreeRDPGetColor(surface->format, r, g, b, a);
- for (index = 0; index < solidFill->fillRectCount; index++)
+ for (UINT16 index = 0; index < solidFill->fillRectCount; index++)
{
- rect = &(solidFill->fillRects[index]);
- nWidth = rect->right - rect->left;
- nHeight = rect->bottom - rect->top;
- invalidRect.left = rect->left;
- invalidRect.top = rect->top;
- invalidRect.right = rect->right;
- invalidRect.bottom = rect->bottom;
-
- if (!freerdp_image_fill(surface->data, surface->format, surface->scanline, rect->left,
- rect->top, nWidth, nHeight, color))
+ const RECTANGLE_16* rect = &(solidFill->fillRects[index]);
+
+ if (!intersect_rect(rect, surface, &invalidRect))
+ goto fail;
+
+ const UINT32 nWidth = invalidRect.right - invalidRect.left;
+ const UINT32 nHeight = invalidRect.bottom - invalidRect.top;
+
+ if (!freerdp_image_fill(surface->data, surface->format, surface->scanline, invalidRect.left,
+ invalidRect.top, nWidth, nHeight, color))
goto fail;
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
@@ -23,6 +23,7 @@ SRC_URI = "git://github.com/FreeRDP/FreeRDP.git;branch=stable-2.0;protocol=https
file://CVE-2022-39320.patch \
file://CVE-2023-39350.patch \
file://CVE-2023-39351.patch \
file://CVE-2023-39352.patch \
"
S = "${WORKDIR}/git"