From 3392ca130c4e66e570ae5d758b8155e10dd9dd95 Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Thu, 6 Aug 2026 01:24:12 -0400 Subject: [PATCH] import Oracle_OSS freerdp-3.10.3-12.el10_2.7 --- core-orders-add-codecID-checks.patch | 163 ++++++++++++++++ freerdp.spec | 14 +- gdi-graphics-fix-gdi_Bitmap_Decompress.patch | 185 +++++++++++++++++++ 3 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 core-orders-add-codecID-checks.patch create mode 100644 gdi-graphics-fix-gdi_Bitmap_Decompress.patch diff --git a/core-orders-add-codecID-checks.patch b/core-orders-add-codecID-checks.patch new file mode 100644 index 0000000..4e94f64 --- /dev/null +++ b/core-orders-add-codecID-checks.patch @@ -0,0 +1,163 @@ +From 64649715f9aa691c8435d05cc17ccf468cbb3afa Mon Sep 17 00:00:00 2001 +From: Armin Novak +Date: Tue, 16 Jun 2026 10:53:16 +0200 +Subject: [PATCH] [core,orders] add codecID checks + +Abort early if an unsupported/deactivated codecID value is found for a +CACHE_BITMAP_V3_ORDER. +--- + libfreerdp/core/orders.c | 94 +++++++++++++++++++++++++++++++++++----- + 1 file changed, 82 insertions(+), 12 deletions(-) + +diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c +index 6c5f98ab6..c725aa790 100644 +--- a/libfreerdp/core/orders.c ++++ b/libfreerdp/core/orders.c +@@ -2446,7 +2446,7 @@ static CACHE_BITMAP_V2_ORDER* update_read_cache_bitmap_v2_order(rdpUpdate* updat + if (!cache_bitmap_v2) + goto fail; + +- cache_bitmap_v2->cacheId = flags & 0x0003; ++ cache_bitmap_v2->cacheId = flags & 0x0007; + cache_bitmap_v2->flags = (flags & 0xFF80) >> 7; + bitsPerPixelId = (flags & 0x0078) >> 3; + cache_bitmap_v2->bitmapBpp = get_cbr2_bpp(bitsPerPixelId, &rc); +@@ -2620,27 +2620,43 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat + UINT16 flags) + { + BOOL rc = 0; +- BYTE bitsPerPixelId = 0; +- BITMAP_DATA_EX* bitmapData = NULL; + UINT32 new_len = 0; + BYTE* new_data = NULL; +- CACHE_BITMAP_V3_ORDER* cache_bitmap_v3 = NULL; + rdp_update_internal* up = update_cast(update); + + if (!update || !s) + return NULL; + +- cache_bitmap_v3 = calloc(1, sizeof(CACHE_BITMAP_V3_ORDER)); ++ WINPR_ASSERT(update->context); ++ ++ const rdpSettings* settings = update->context->settings; ++ WINPR_ASSERT(settings); ++ ++ if (!freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheV3Enabled)) ++ { ++ WLog_Print(up->log, WLOG_ERROR, "BitmapCacheV3 not enabled for this connection, aborting"); ++ return NULL; ++ } ++ ++ CACHE_BITMAP_V3_ORDER* cache_bitmap_v3 = calloc(1, sizeof(CACHE_BITMAP_V3_ORDER)); + + if (!cache_bitmap_v3) + goto fail; + +- cache_bitmap_v3->cacheId = flags & 0x00000003; +- cache_bitmap_v3->flags = (flags & 0x0000FF80) >> 7; +- bitsPerPixelId = (flags & 0x00000078) >> 3; +- cache_bitmap_v3->bpp = get_cbr2_bpp(bitsPerPixelId, &rc); +- if (!rc) ++ cache_bitmap_v3->cacheId = flags & 0x00000007; ++ const UINT32 NumCellCaches = ++ freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells); ++ if (cache_bitmap_v3->cacheId >= NumCellCaches) ++ { ++ WLog_Print(up->log, WLOG_ERROR, ++ "BitmapCacheV3::cacheId %" PRIu32 " > NumCellCaches %" PRIu32, ++ cache_bitmap_v3->cacheId, NumCellCaches); + goto fail; ++ } ++ cache_bitmap_v3->flags = (flags >> 7) & 0x000001FF; ++ ++ const BYTE bitsPerPixelId = (flags >> 3) & 0x000000F; ++ cache_bitmap_v3->bpp = get_cbr2_bpp(bitsPerPixelId, &rc); + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 21)) + goto fail; +@@ -2648,7 +2664,20 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat + Stream_Read_UINT16(s, cache_bitmap_v3->cacheIndex); /* cacheIndex (2 bytes) */ + Stream_Read_UINT32(s, cache_bitmap_v3->key1); /* key1 (4 bytes) */ + Stream_Read_UINT32(s, cache_bitmap_v3->key2); /* key2 (4 bytes) */ +- bitmapData = &cache_bitmap_v3->bitmapData; ++ ++ if ((cache_bitmap_v3->flags & CBR3_DO_NOT_CACHE) != 0) ++ { ++ rdpCache* cache = update->context->cache; ++ WINPR_ASSERT(cache); ++ ++ if (cache_bitmap_v3->cacheId >= cache->bitmap->maxCells) ++ goto fail; ++ ++ BITMAP_V2_CELL* cell = &cache->bitmap->cells[cache_bitmap_v3->cacheId]; ++ cache_bitmap_v3->cacheIndex = cell->number; ++ } ++ ++ BITMAP_DATA_EX* bitmapData = &cache_bitmap_v3->bitmapData; + Stream_Read_UINT8(s, bitmapData->bpp); + + if ((bitmapData->bpp < 1) || (bitmapData->bpp > 32)) +@@ -2657,6 +2686,13 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat + goto fail; + } + ++ /* [MS-RDPEGDI] 2.2.2.2.1.2.8 Cache Bitmap - Revision 3 (CACHE_BITMAP_REV3_ORDER) ++ * tells this should not be 0, but it is for some windows versions. ++ * fall back to setting color depth from bitmapData ++ */ ++ if (!rc) ++ cache_bitmap_v3->bpp = bitmapData->bpp; ++ + Stream_Seek_UINT8(s); /* reserved1 (1 byte) */ + Stream_Seek_UINT8(s); /* reserved2 (1 byte) */ + Stream_Read_UINT8(s, bitmapData->codecID); /* codecID (1 byte) */ +@@ -2664,6 +2700,40 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat + Stream_Read_UINT16(s, bitmapData->height); /* height (2 bytes) */ + Stream_Read_UINT32(s, new_len); /* length (4 bytes) */ + ++ switch (bitmapData->codecID) ++ { ++ case RDP_CODEC_ID_IMAGE_REMOTEFX: ++ if (!freerdp_settings_get_bool(settings, FreeRDP_RemoteFxImageCodec)) ++ { ++ WLog_Print(up->log, WLOG_ERROR, ++ "codecID RDP_CODEC_ID_IMAGE_REMOTEFX not enabled for this " ++ "connection, aborting"); ++ goto fail; ++ } ++ break; ++ case RDP_CODEC_ID_REMOTEFX: ++ if (!freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec)) ++ { ++ WLog_ERR(TAG, ++ "codecID RDP_CODEC_ID_REMOTEFX not enabled for this connection, aborting"); ++ goto fail; ++ } ++ break; ++ case RDP_CODEC_ID_NSCODEC: ++ if (!freerdp_settings_get_bool(settings, FreeRDP_NSCodec)) ++ { ++ WLog_ERR(TAG, ++ "codecID RDP_CODEC_ID_NSCODEC not enabled for this connection, aborting"); ++ goto fail; ++ } ++ break; ++ case RDP_CODEC_ID_NONE: ++ break; ++ default: ++ WLog_ERR(TAG, "Unsupported codecID 0x%08" PRIx32, bitmapData->codecID); ++ goto fail; ++ } ++ + if ((new_len == 0) || (!Stream_CheckAndLogRequiredLength(TAG, s, new_len))) + goto fail; + +@@ -2706,7 +2776,7 @@ BOOL update_write_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache + bitsPerPixelId = get_bpp_bmf(cache_bitmap_v3->bpp, &rc); + if (!rc) + return FALSE; +- *flags = (cache_bitmap_v3->cacheId & 0x00000003) | ++ *flags = (cache_bitmap_v3->cacheId & 0x00000007) | + ((cache_bitmap_v3->flags << 7) & 0x0000FF80) | ((bitsPerPixelId << 3) & 0x00000078); + Stream_Write_UINT16(s, + get_checked_uint16(cache_bitmap_v3->cacheIndex)); /* cacheIndex (2 bytes) */ diff --git a/freerdp.spec b/freerdp.spec index 161a9dc..edab8e7 100644 --- a/freerdp.spec +++ b/freerdp.spec @@ -30,7 +30,7 @@ Name: freerdp Epoch: 2 Version: 3.10.3 -Release: 12%{?dist}.6 +Release: 12%{?dist}.7 Summary: Free implementation of the Remote Desktop Protocol (RDP) # The effective license is Apache-2.0 but: @@ -270,6 +270,13 @@ Patch: channels-cliprdr-abort-on-duplicate-caps.patch Patch: channels-rdpear-fix-ndr_read-checks.patch Patch: channels-rdpear-disable-ndr-pointer-aliasing.patch +# CVE-2026-55827 +# https://github.com/FreeRDP/FreeRDP/pull/12899 +# https://github.com/FreeRDP/FreeRDP/commit/7bbb52a193deed5943a041c9859db7ee036044a4 +# https://github.com/FreeRDP/FreeRDP/commit/3c4ae49f38aa0ea9b073025eb468131375e518ff +Patch: core-orders-add-codecID-checks.patch +Patch: gdi-graphics-fix-gdi_Bitmap_Decompress.patch + BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: alsa-lib-devel @@ -593,6 +600,11 @@ find %{buildroot} -name "*.a" -delete %{_libdir}/pkgconfig/winpr-tools3.pc %changelog +* Sat Jul 11 2026 RHEL Packaging Agent - 2:3.10.3-12.7 +- Add codecID checks for CACHE_BITMAP_V3_ORDER (CVE-2026-55827) +- Fix boundary checks in gdi_Bitmap_Decompress (CVE-2026-55827) + Resolves: RHEL-194327 + * Mon Jun 29 2026 Ondrej Holy - 2:3.10.3-12.6 - Backport several CVE fixes (CVE-2026-40033, CVE-2026-44420, CVE-2026-44421, CVE-2026-44422, CVE-2026-45700) diff --git a/gdi-graphics-fix-gdi_Bitmap_Decompress.patch b/gdi-graphics-fix-gdi_Bitmap_Decompress.patch new file mode 100644 index 0000000..cfea30b --- /dev/null +++ b/gdi-graphics-fix-gdi_Bitmap_Decompress.patch @@ -0,0 +1,185 @@ +From 053e4d7a9984d607b086816f1732bcc2619677c8 Mon Sep 17 00:00:00 2001 +From: Armin Novak +Date: Tue, 16 Jun 2026 10:59:40 +0200 +Subject: [PATCH] [gdi,graphics] fix gdi_Bitmap_Decompress + +* Properly check boundaries when decoding data +--- + libfreerdp/gdi/graphics.c | 131 +++++++++++++++++++++++--------------- + 1 file changed, 78 insertions(+), 53 deletions(-) + +diff --git a/libfreerdp/gdi/graphics.c b/libfreerdp/gdi/graphics.c +index eec5cd6b9..6f82c2eda 100644 +--- a/libfreerdp/gdi/graphics.c ++++ b/libfreerdp/gdi/graphics.c +@@ -130,26 +130,55 @@ static BOOL gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) + gdi_bitmap->hdc, 0, 0, GDI_SRCCOPY, &context->gdi->palette); + } + ++static BOOL gdi_Bitmap_Rfx(rdpContext* context, rdpBitmap* bitmap, const BYTE* pSrcData, ++ UINT32 SrcSize) ++{ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(bitmap); ++ WINPR_ASSERT(pSrcData || (SrcSize == 0)); ++ ++ REGION16 invalidRegion; ++ region16_init(&invalidRegion); ++ ++ const UINT32 stride = bitmap->width * FreeRDPGetBytesPerPixel(bitmap->format); ++ ++ const BOOL rc = ++ rfx_process_message(context->codecs->rfx, pSrcData, SrcSize, bitmap->left, bitmap->top, ++ bitmap->data, bitmap->format, stride, bitmap->height, &invalidRegion); ++ region16_uninit(&invalidRegion); ++ ++ if (!rc) ++ { ++ WLog_ERR(TAG, "rfx_process_message failed"); ++ return FALSE; ++ } ++ return TRUE; ++} ++ + static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const BYTE* pSrcData, + UINT32 DstWidth, UINT32 DstHeight, UINT32 bpp, UINT32 length, + BOOL compressed, UINT32 codecId) + { ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(bitmap); ++ + UINT32 SrcSize = length; + rdpGdi* gdi = context->gdi; +- UINT32 size = DstWidth * DstHeight; ++ WINPR_ASSERT(gdi); ++ + bitmap->compressed = FALSE; + bitmap->format = gdi->dstFormat; + + if ((FreeRDPGetBytesPerPixel(bitmap->format) == 0) || (DstWidth == 0) || (DstHeight == 0) || + (DstWidth > UINT32_MAX / DstHeight) || +- (size > (UINT32_MAX / FreeRDPGetBytesPerPixel(bitmap->format)))) ++ ((DstWidth * DstHeight) > (UINT32_MAX / FreeRDPGetBytesPerPixel(bitmap->format)))) + { + WLog_ERR(TAG, "invalid input data"); + return FALSE; + } + +- size *= FreeRDPGetBytesPerPixel(bitmap->format); +- bitmap->length = size; ++ const UINT32 stride = DstWidth * FreeRDPGetBytesPerPixel(bitmap->format); ++ bitmap->length = stride * DstHeight; + bitmap->data = (BYTE*)winpr_aligned_malloc(bitmap->length, 16); + + if (!bitmap->data) +@@ -157,57 +186,53 @@ static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const + + if (compressed) + { +- if ((codecId == RDP_CODEC_ID_REMOTEFX) || (codecId == RDP_CODEC_ID_IMAGE_REMOTEFX)) ++ WINPR_ASSERT(context->codecs); ++ switch (codecId) + { +- REGION16 invalidRegion; +- region16_init(&invalidRegion); +- +- if (!rfx_process_message(context->codecs->rfx, pSrcData, SrcSize, bitmap->left, +- bitmap->top, bitmap->data, bitmap->format, gdi->stride, +- gdi->height, &invalidRegion)) ++ case RDP_CODEC_ID_REMOTEFX: ++ case RDP_CODEC_ID_IMAGE_REMOTEFX: ++ if (!gdi_Bitmap_Rfx(context, bitmap, pSrcData, SrcSize)) ++ return FALSE; ++ break; ++ case RDP_CODEC_ID_NSCODEC: + { +- WLog_ERR(TAG, "rfx_process_message failed"); +- return FALSE; +- } +- } +- else if (codecId == RDP_CODEC_ID_NSCODEC) +- { +- const int status = nsc_process_message( +- context->codecs->nsc, 32, DstWidth, DstHeight, pSrcData, SrcSize, bitmap->data, +- bitmap->format, 0, 0, 0, DstWidth, DstHeight, FREERDP_FLIP_VERTICAL); +- +- if (status < 1) +- { +- WLog_ERR(TAG, "nsc_process_message failed"); +- return FALSE; +- } +- +- return freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, 0, 0, 0, DstWidth, +- DstHeight, pSrcData, PIXEL_FORMAT_XRGB32, 0, 0, 0, +- &gdi->palette, FREERDP_FLIP_VERTICAL); +- } +- else if (bpp < 32) +- { +- if (!interleaved_decompress(context->codecs->interleaved, pSrcData, SrcSize, DstWidth, +- DstHeight, bpp, bitmap->data, bitmap->format, 0, 0, 0, +- DstWidth, DstHeight, &gdi->palette)) +- { +- WLog_ERR(TAG, "interleaved_decompress failed"); +- return FALSE; +- } +- } +- else +- { +- const BOOL fidelity = +- freerdp_settings_get_bool(context->settings, FreeRDP_DrawAllowDynamicColorFidelity); +- freerdp_planar_switch_bgr(context->codecs->planar, fidelity); +- if (!planar_decompress(context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight, +- bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight, +- TRUE)) +- { +- WLog_ERR(TAG, "planar_decompress failed"); +- return FALSE; ++ const int status = nsc_process_message( ++ context->codecs->nsc, 32, DstWidth, DstHeight, pSrcData, SrcSize, bitmap->data, ++ bitmap->format, stride, 0, 0, DstWidth, DstHeight, FREERDP_FLIP_VERTICAL); ++ ++ if (status < 1) ++ { ++ WLog_ERR(TAG, "nsc_process_message failed"); ++ return FALSE; ++ } + } ++ break; ++ default: ++ if (bpp < 32) ++ { ++ if (!interleaved_decompress(context->codecs->interleaved, pSrcData, SrcSize, ++ DstWidth, DstHeight, bpp, bitmap->data, ++ bitmap->format, stride, 0, 0, DstWidth, DstHeight, ++ &gdi->palette)) ++ { ++ WLog_ERR(TAG, "interleaved_decompress failed"); ++ return FALSE; ++ } ++ } ++ else ++ { ++ const BOOL fidelity = freerdp_settings_get_bool( ++ context->settings, FreeRDP_DrawAllowDynamicColorFidelity); ++ freerdp_planar_switch_bgr(context->codecs->planar, fidelity); ++ if (!planar_decompress( ++ context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight, ++ bitmap->data, bitmap->format, stride, 0, 0, DstWidth, DstHeight, TRUE)) ++ { ++ WLog_ERR(TAG, "planar_decompress failed"); ++ return FALSE; ++ } ++ } ++ break; + } + } + else +@@ -230,7 +255,7 @@ static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const + } + } + +- if (!freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, 0, 0, 0, DstWidth, ++ if (!freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, stride, 0, 0, DstWidth, + DstHeight, pSrcData, SrcFormat, 0, 0, 0, &gdi->palette, + FREERDP_FLIP_VERTICAL)) + {