File freerdp-CVE-2020-15103.patch of Package freerdp.27686
From efdc99528f6fb6d56537a5420bfa8e735219eba0 Mon Sep 17 00:00:00 2001
From: Bernhard Miklautz <bernhard.miklautz@thincast.com>
Date: Wed, 15 Jul 2020 18:04:02 +0200
Subject: [PATCH 1/3] new [orders]: BMF_24BPP support and some comments
* cached brush orders missed the BMF_24BPP documented case
([MS-RDPEGDI] 2.2.2.2.1.2.7)
* add some comments on secondary (brush) order details
---
libfreerdp/core/orders.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c
index 74870fae6..1608b7ccb 100644
--- a/libfreerdp/core/orders.c
+++ b/libfreerdp/core/orders.c
@@ -2676,6 +2676,7 @@ static CACHE_BRUSH_ORDER* update_read_cache_brush_order(rdpUpdate* update, wStre
Stream_Read_UINT8(s, cache_brush->cx); /* cx (1 byte) */
Stream_Read_UINT8(s, cache_brush->cy); /* cy (1 byte) */
+ /* according to Section 2.2.2.2.1.2.7 errata the windows implementation sets this filed is set to 0x00 */
Stream_Read_UINT8(s, cache_brush->style); /* style (1 byte) */
Stream_Read_UINT8(s, cache_brush->length); /* iBytes (1 byte) */
@@ -2690,14 +2691,12 @@ static CACHE_BRUSH_ORDER* update_read_cache_brush_order(rdpUpdate* update, wStre
goto fail;
}
- /* rows are encoded in reverse order */
if (Stream_GetRemainingLength(s) < 8)
goto fail;
+ /* rows are encoded in reverse order */
for (i = 7; i >= 0; i--)
- {
Stream_Read_UINT8(s, cache_brush->data[i]);
- }
}
else
{
@@ -2705,6 +2704,8 @@ static CACHE_BRUSH_ORDER* update_read_cache_brush_order(rdpUpdate* update, wStre
compressed = TRUE;
else if ((iBitmapFormat == BMF_16BPP) && (cache_brush->length == 24))
compressed = TRUE;
+ else if ((iBitmapFormat == BMF_24BPP) && (cache_brush->length == 28))
+ compressed = TRUE;
else if ((iBitmapFormat == BMF_32BPP) && (cache_brush->length == 32))
compressed = TRUE;
@@ -3635,6 +3636,10 @@ static BOOL update_recv_secondary_order(rdpUpdate* update, wStream* s, BYTE flag
Stream_Read_UINT16(s, orderLength); /* orderLength (2 bytes) */
Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
Stream_Read_UINT8(s, orderType); /* orderType (1 byte) */
+ /*
+ * According to [MS-RDPEGDI] 2.2.2.2.1.2.1.1 the order length must be increased by 13 bytes
+ * including the header. As we already read the header 7 left
+ */
if (Stream_GetRemainingLength(s) < orderLength + 7U)
{
WLog_Print(update->log, WLOG_ERROR, "Stream_GetRemainingLength(s) %" PRIuz " < %" PRIu16,
--
2.28.0
From 40393700642ad38437982e8a3afc34ff33ccf28e Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Fri, 3 Jul 2020 10:26:38 +0200
Subject: [PATCH 2/3] Fixed input sanitation in rdpgfx_recv_solid_fill_pdu
The input rectangle must be checked for plausibility.
Thanks to Sunglin and HuanGMz of the Knownsec 404 security team and pangzi of pwnzen
---
channels/rdpgfx/rdpgfx_common.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c
index 090aa50ab..e0a50a606 100644
--- a/channels/rdpgfx/rdpgfx_common.c
+++ b/channels/rdpgfx/rdpgfx_common.c
@@ -182,6 +182,10 @@ UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16)
Stream_Read_UINT16(s, rect16->top); /* top (2 bytes) */
Stream_Read_UINT16(s, rect16->right); /* right (2 bytes) */
Stream_Read_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
+ if (rect16->left >= rect16->right)
+ return ERROR_INVALID_DATA;
+ if (rect16->top >= rect16->bottom)
+ return ERROR_INVALID_DATA;
return CHANNEL_RC_OK;
}
--
2.28.0
From e08a23f93136f59a52651f66d064b8d4303872e1 Mon Sep 17 00:00:00 2001
From: akallabeth <akallabeth@posteo.net>
Date: Fri, 3 Jul 2020 10:29:13 +0200
Subject: [PATCH 3/3] Fixed missing input sanitation for GFX surfaces.
Thanks to Sunglin and HuanGMz of the Knownsec 404 security team and pangzi of pwnzen
---
libfreerdp/gdi/gfx.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c
index e3a6e66e0..f368165b6 100644
--- a/libfreerdp/gdi/gfx.c
+++ b/libfreerdp/gdi/gfx.c
@@ -31,6 +31,17 @@
#define TAG FREERDP_TAG("gdi")
+static BOOL is_rect_valid(const RECTANGLE_16* rect, size_t width, size_t height)
+{
+ if (!rect)
+ return FALSE;
+ if ((rect->left > rect->right) || (rect->right > width))
+ return FALSE;
+ if ((rect->top > rect->bottom) || (rect->bottom > height))
+ return FALSE;
+ return TRUE;
+}
+
static DWORD gfx_align_scanline(DWORD widthInBytes, DWORD alignment)
{
const UINT32 align = alignment;
@@ -1114,7 +1125,6 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context,
BOOL sameSurface;
UINT32 nWidth, nHeight;
const RECTANGLE_16* rectSrc;
- RDPGFX_POINT16* destPt;
RECTANGLE_16 invalidRect;
gdiGfxSurface* surfaceSrc;
gdiGfxSurface* surfaceDst;
@@ -1134,12 +1144,18 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context,
if (!surfaceSrc || !surfaceDst)
goto fail;
+ if (!is_rect_valid(rectSrc, surfaceSrc->width, surfaceSrc->height))
+ goto fail;
+
nWidth = rectSrc->right - rectSrc->left;
nHeight = rectSrc->bottom - rectSrc->top;
for (index = 0; index < surfaceToSurface->destPtsCount; index++)
{
- destPt = &surfaceToSurface->destPts[index];
+ const RDPGFX_POINT16* destPt = &surfaceToSurface->destPts[index];
+ const RECTANGLE_16 rect = { destPt->x, destPt->y, destPt->x + nWidth, destPt->y + nHeight };
+ if (!is_rect_valid(&rect, surfaceDst->width, surfaceDst->height))
+ goto fail;
if (!freerdp_image_copy(surfaceDst->data, surfaceDst->format, surfaceDst->scanline,
destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data,
@@ -1192,6 +1208,9 @@ static UINT gdi_SurfaceToCache(RdpgfxClientContext* context,
if (!surface)
goto fail;
+ if (!is_rect_valid(rect, surface->width, surface->height))
+ goto fail;
+
cacheEntry = (gdiGfxCacheEntry*)calloc(1, sizeof(gdiGfxCacheEntry));
if (!cacheEntry)
@@ -1234,7 +1253,6 @@ static UINT gdi_CacheToSurface(RdpgfxClientContext* context,
{
UINT status = ERROR_INTERNAL_ERROR;
UINT16 index;
- RDPGFX_POINT16* destPt;
gdiGfxSurface* surface;
gdiGfxCacheEntry* cacheEntry;
RECTANGLE_16 invalidRect;
@@ -1248,7 +1266,12 @@ static UINT gdi_CacheToSurface(RdpgfxClientContext* context,
for (index = 0; index < cacheToSurface->destPtsCount; index++)
{
- destPt = &cacheToSurface->destPts[index];
+ const RDPGFX_POINT16* destPt = &cacheToSurface->destPts[index];
+ const RECTANGLE_16 rect = { destPt->x, destPt->y, destPt->x + cacheEntry->width,
+ destPt->y + cacheEntry->height };
+
+ if (!is_rect_valid(&rect, surface->width, surface->height))
+ goto fail;
if (!freerdp_image_copy(surface->data, surface->format, surface->scanline, destPt->x,
destPt->y, cacheEntry->width, cacheEntry->height, cacheEntry->data,
--
2.28.0