diff --git a/cache-offscreen-invalidate-bitmap-before-free.patch b/cache-offscreen-invalidate-bitmap-before-free.patch new file mode 100644 index 0000000..26527c0 --- /dev/null +++ b/cache-offscreen-invalidate-bitmap-before-free.patch @@ -0,0 +1,45 @@ +From 52106a26726a2aba77aa6d86014d2eb3507f0783 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Mon, 19 Jan 2026 08:58:22 +0100 +Subject: [PATCH] [cache,offscreen] invalidate bitmap before free + +First ensure the bitmap is no longer used for drawing before calling the +free function. +--- + libfreerdp/cache/offscreen.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/libfreerdp/cache/offscreen.c b/libfreerdp/cache/offscreen.c +index 91fa38f32..d3c85f95d 100644 +--- a/libfreerdp/cache/offscreen.c ++++ b/libfreerdp/cache/offscreen.c +@@ -164,8 +164,6 @@ void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBit + + void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index) + { +- rdpBitmap* prevBitmap = NULL; +- + WINPR_ASSERT(offscreenCache); + + if (index >= offscreenCache->maxEntries) +@@ -174,10 +172,16 @@ void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index) + return; + } + +- prevBitmap = offscreenCache->entries[index]; ++ rdpBitmap* prevBitmap = offscreenCache->entries[index]; + + if (prevBitmap != NULL) ++ { ++ WINPR_ASSERT(offscreenCache->context); ++ ++ /* Ensure that the bitmap is no longer used in GDI */ ++ IFCALL(prevBitmap->SetSurface, offscreenCache->context, NULL, FALSE); + Bitmap_Free(offscreenCache->context, prevBitmap); ++ } + + offscreenCache->entries[index] = NULL; + } +-- +2.52.0 + diff --git a/client-x11-fix-double-free-in-case-of-invalid-pointe.patch b/client-x11-fix-double-free-in-case-of-invalid-pointe.patch new file mode 100644 index 0000000..5a12e67 --- /dev/null +++ b/client-x11-fix-double-free-in-case-of-invalid-pointe.patch @@ -0,0 +1,48 @@ +From 0421b53fcb4a80c95f51342e4a2c40c68a4101d3 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Mon, 19 Jan 2026 08:52:51 +0100 +Subject: [PATCH] [client,x11] fix double free in case of invalid pointer + +--- + client/X11/xf_graphics.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c +index df95a22b5..9d432c98b 100644 +--- a/client/X11/xf_graphics.c ++++ b/client/X11/xf_graphics.c +@@ -289,7 +289,6 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) + + #ifdef WITH_XCURSOR + UINT32 CursorFormat = 0; +- size_t size = 0; + xfContext* xfc = (xfContext*)context; + xfPointer* xpointer = (xfPointer*)pointer; + +@@ -304,19 +303,18 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) + xpointer->nCursors = 0; + xpointer->mCursors = 0; + +- size = 1ull * pointer->height * pointer->width * FreeRDPGetBytesPerPixel(CursorFormat); ++ const size_t size = ++ 1ull * pointer->height * pointer->width * FreeRDPGetBytesPerPixel(CursorFormat); + +- if (!(xpointer->cursorPixels = (XcursorPixel*)winpr_aligned_malloc(size, 16))) ++ xpointer->cursorPixels = (XcursorPixel*)winpr_aligned_malloc(size, 16); ++ if (!xpointer->cursorPixels) + goto fail; + + if (!freerdp_image_copy_from_pointer_data( + (BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0, pointer->width, pointer->height, + pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData, + pointer->lengthAndMask, pointer->xorBpp, &context->gdi->palette)) +- { +- winpr_aligned_free(xpointer->cursorPixels); + goto fail; +- } + + #endif + +-- +2.52.0 + diff --git a/codec-clear-check-clear_decomress-glyphData.patch b/codec-clear-check-clear_decomress-glyphData.patch new file mode 100644 index 0000000..2a9be7c --- /dev/null +++ b/codec-clear-check-clear_decomress-glyphData.patch @@ -0,0 +1,78 @@ +From 4498861d2b180cae552b5e2daedebe14312c2141 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 26 Jan 2026 16:32:13 +0100 +Subject: [PATCH] [codec,clear] check clear_decomress glyphData + +Backport of commit 243ecf804bb122e8e643a5c142ad5a49d7aa19ee. + +Co-Authored-By: Claude +--- + libfreerdp/codec/clear.c | 52 ++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 50 insertions(+), 2 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +index 603863c36..ca821f575 100644 +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -1139,8 +1139,56 @@ INT32 clear_decompress(CLEAR_CONTEXT* WINPR_RESTRICT clear, const BYTE* WINPR_RE + + if (glyphData) + { +- if (!freerdp_image_copy_no_overlap(glyphData, clear->format, 0, 0, 0, nWidth, nHeight, +- pDstData, DstFormat, nDstStep, nXDst, nYDst, palette, ++ uint32_t w = MIN(nWidth, nDstWidth); ++ if (nXDst > nDstWidth) ++ { ++ WLog_WARN(TAG, "glyphData copy area x exceeds destination: x=%" PRIu32 " > %" PRIu32, ++ nXDst, nDstWidth); ++ w = 0; ++ } ++ else if (nXDst + w > nDstWidth) ++ { ++ WLog_WARN(TAG, ++ "glyphData copy area x + width exceeds destination: x=%" PRIu32 " + %" PRIu32 ++ " > %" PRIu32, ++ nXDst, w, nDstWidth); ++ w = nDstWidth - nXDst; ++ } ++ ++ if (w != nWidth) ++ { ++ WLog_WARN(TAG, ++ "glyphData copy area width truncated: requested=%" PRIu32 ++ ", truncated to %" PRIu32, ++ nWidth, w); ++ } ++ ++ uint32_t h = MIN(nHeight, nDstHeight); ++ if (nYDst > nDstHeight) ++ { ++ WLog_WARN(TAG, "glyphData copy area y exceeds destination: y=%" PRIu32 " > %" PRIu32, ++ nYDst, nDstHeight); ++ h = 0; ++ } ++ else if (nYDst + h > nDstHeight) ++ { ++ WLog_WARN(TAG, ++ "glyphData copy area y + height exceeds destination: x=%" PRIu32 " + %" PRIu32 ++ " > %" PRIu32, ++ nYDst, h, nDstHeight); ++ h = nDstHeight - nYDst; ++ } ++ ++ if (h != nHeight) ++ { ++ WLog_WARN(TAG, ++ "glyphData copy area height truncated: requested=%" PRIu32 ++ ", truncated to %" PRIu32, ++ nHeight, h); ++ } ++ ++ if (!freerdp_image_copy_no_overlap(glyphData, clear->format, 0, 0, 0, w, h, pDstData, ++ DstFormat, nDstStep, nXDst, nYDst, palette, + FREERDP_KEEP_DST_ALPHA)) + goto fail; + } +-- +2.52.0 + diff --git a/codec-clear-fix-clear_resize_buffer-checks.patch b/codec-clear-fix-clear_resize_buffer-checks.patch new file mode 100644 index 0000000..9d32e9e --- /dev/null +++ b/codec-clear-fix-clear_resize_buffer-checks.patch @@ -0,0 +1,62 @@ +From 94235a5297db9cb83c2c23ade8a69cabe3e5f9f4 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Tue, 27 Jan 2026 16:15:28 +0100 +Subject: [PATCH] [codec,clear] fix clear_resize_buffer checks + +Backport of commit c4391827d7facfc874ca7f61a92afb82232a5748. + +Co-Authored-By: Claude +--- + libfreerdp/codec/clear.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +index b0813937d..28450b357 100644 +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -58,7 +58,7 @@ struct S_CLEAR_CONTEXT + NSC_CONTEXT* nsc; + UINT32 seqNumber; + BYTE* TempBuffer; +- UINT32 TempSize; ++ size_t TempSize; + UINT32 nTempStep; + UINT32 TempFormat; + UINT32 format; +@@ -328,25 +328,26 @@ static BOOL clear_decompress_subcode_rlex(wStream* WINPR_RESTRICT s, UINT32 bitm + + static BOOL clear_resize_buffer(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 width, UINT32 height) + { +- UINT32 size = 0; +- + if (!clear) + return FALSE; + +- size = ((width + 16) * (height + 16) * FreeRDPGetBytesPerPixel(clear->format)); ++ const UINT64 size = 1ull * (width + 16ull) * (height + 16ull); ++ const size_t bpp = FreeRDPGetBytesPerPixel(clear->format); ++ if (size > UINT32_MAX / bpp) ++ return FALSE; + +- if (size > clear->TempSize) ++ if (size > clear->TempSize / bpp) + { +- BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer, size, sizeof(BYTE), 32); ++ BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer, size, bpp, 32); + + if (!tmp) + { +- WLog_ERR(TAG, "clear->TempBuffer winpr_aligned_recalloc failed for %" PRIu32 " bytes", ++ WLog_ERR(TAG, "clear->TempBuffer winpr_aligned_recalloc failed for %" PRIu64 " bytes", + size); + return FALSE; + } + +- clear->TempSize = size; ++ clear->TempSize = size * bpp; + clear->TempBuffer = tmp; + } + +-- +2.52.0 + diff --git a/codec-clear-fix-off-by-one-length-check.patch b/codec-clear-fix-off-by-one-length-check.patch new file mode 100644 index 0000000..36b4d51 --- /dev/null +++ b/codec-clear-fix-off-by-one-length-check.patch @@ -0,0 +1,31 @@ +From f8688b57f6cfad9a0b05475a6afbde355ffab720 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 15 Jan 2026 12:19:53 +0100 +Subject: [PATCH] [codec,clear] fix off by one length check + +--- + libfreerdp/codec/clear.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +index 4a67a8ed6..0efa89f8d 100644 +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -876,12 +876,12 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* WINPR_RESTRICT clear, + if (count > nHeight) + count = nHeight; + +- if (nXDstRel + i > nDstWidth) ++ if (nXDstRel + i >= nDstWidth) + return FALSE; + + for (UINT32 y = 0; y < count; y++) + { +- if (nYDstRel + y > nDstHeight) ++ if (nYDstRel + y >= nDstHeight) + return FALSE; + + BYTE* pDstPixel8 = +-- +2.52.0 + diff --git a/codec-planar-fix-decoder-length-checks.patch b/codec-planar-fix-decoder-length-checks.patch new file mode 100644 index 0000000..a8a9fee --- /dev/null +++ b/codec-planar-fix-decoder-length-checks.patch @@ -0,0 +1,28 @@ +From 1bab198a2edd0d0e6e1627d21a433151ea190500 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 15 Jan 2026 12:02:02 +0100 +Subject: [PATCH] [codec,planar] fix decoder length checks + +--- + libfreerdp/codec/planar.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c +index 1a06e36ed..94a640a55 100644 +--- a/libfreerdp/codec/planar.c ++++ b/libfreerdp/codec/planar.c +@@ -727,6 +727,11 @@ BOOL freerdp_bitmap_decompress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT plan + WINPR_ASSERT(planar); + WINPR_ASSERT(prims); + ++ if (planar->maxWidth < nSrcWidth) ++ return FALSE; ++ if (planar->maxHeight < nSrcHeight) ++ return FALSE; ++ + if (nDstStep <= 0) + nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat); + +-- +2.52.0 + diff --git a/freerdp.spec b/freerdp.spec index 3f44b1b..8e07170 100644 --- a/freerdp.spec +++ b/freerdp.spec @@ -30,7 +30,7 @@ Name: freerdp Epoch: 2 Version: 3.10.3 -Release: 7%{?dist} +Release: 8%{?dist} Summary: Free implementation of the Remote Desktop Protocol (RDP) # The effective license is Apache-2.0 but: @@ -65,6 +65,27 @@ Patch: core-tcp-Don-t-ignore-connect-errors.patch Patch: core-tcp-Fix-PreferIPv6OverIPv4-fallback-to-IPv4-add.patch Patch: core-tcp-fix-double-free-in-get_next_addrinfo.patch +# https://github.com/FreeRDP/FreeRDP/commit/c4a7c371342edf0d307cea728f56d3302f0ab38c +Patch: gdi-gfx-properly-clamp-SurfaceToSurface.patch + +# https://github.com/FreeRDP/FreeRDP/commit/c4391827d7facfc874ca7f61a92afb82232a5748 +Patch: codec-clear-fix-clear_resize_buffer-checks.patch + +# https://github.com/FreeRDP/FreeRDP/commit/f8688b57f6cfad9a0b05475a6afbde355ffab720 +Patch: codec-clear-fix-off-by-one-length-check.patch + +# https://github.com/FreeRDP/FreeRDP/commit/1bab198a2edd0d0e6e1627d21a433151ea190500 +Patch: codec-planar-fix-decoder-length-checks.patch + +# https://github.com/FreeRDP/FreeRDP/commit/243ecf804bb122e8e643a5c142ad5a49d7aa19ee +Patch: codec-clear-check-clear_decomress-glyphData.patch + +# https://github.com/FreeRDP/FreeRDP/commit/0421b53fcb4a80c95f51342e4a2c40c68a4101d3 +Patch: client-x11-fix-double-free-in-case-of-invalid-pointe.patch + +# https://github.com/FreeRDP/FreeRDP/commit/52106a26726a2aba77aa6d86014d2eb3507f0783 +Patch: cache-offscreen-invalidate-bitmap-before-free.patch + BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: alsa-lib-devel @@ -388,6 +409,11 @@ find %{buildroot} -name "*.a" -delete %{_libdir}/pkgconfig/winpr-tools3.pc %changelog +* Tue Jan 27 2026 Ondrej Holy - 2:3.10.3-8 +- Backport several CVE fixes + Resolves: RHEL-142414, RHEL-142398, RHEL-142382, RHEL-142366, RHEL-142350 + Resolves: RHEL-142334, RHEL-142318 + * Fri Jan 16 2026 Ondrej Holy - 2:3.10.3-7 - Try next DNS entry on connect failure Resolves: RHEL-140099 diff --git a/gdi-gfx-properly-clamp-SurfaceToSurface.patch b/gdi-gfx-properly-clamp-SurfaceToSurface.patch new file mode 100644 index 0000000..8d51104 --- /dev/null +++ b/gdi-gfx-properly-clamp-SurfaceToSurface.patch @@ -0,0 +1,48 @@ +From c4a7c371342edf0d307cea728f56d3302f0ab38c Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 15 Jan 2026 12:04:36 +0100 +Subject: [PATCH] [gdi,gfx] properly clamp SurfaceToSurface + +--- + libfreerdp/gdi/gfx.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c +index 56e6ff9ed..96ce10070 100644 +--- a/libfreerdp/gdi/gfx.c ++++ b/libfreerdp/gdi/gfx.c +@@ -1335,8 +1335,6 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, + { + UINT status = ERROR_INTERNAL_ERROR; + BOOL sameSurface = 0; +- UINT32 nWidth = 0; +- UINT32 nHeight = 0; + const RECTANGLE_16* rectSrc = NULL; + RECTANGLE_16 invalidRect; + gdiGfxSurface* surfaceSrc = NULL; +@@ -1362,8 +1360,8 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, + if (!is_rect_valid(rectSrc, surfaceSrc->width, surfaceSrc->height)) + goto fail; + +- nWidth = rectSrc->right - rectSrc->left; +- nHeight = rectSrc->bottom - rectSrc->top; ++ const UINT32 nWidth = rectSrc->right - rectSrc->left; ++ const UINT32 nHeight = rectSrc->bottom - rectSrc->top; + + for (UINT16 index = 0; index < surfaceToSurface->destPtsCount; index++) + { +@@ -1374,8 +1372,10 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, + if (!is_rect_valid(&rect, surfaceDst->width, surfaceDst->height)) + goto fail; + ++ const UINT32 rwidth = rect.right - rect.left; ++ const UINT32 rheight = rect.bottom - rect.top; + if (!freerdp_image_copy(surfaceDst->data, surfaceDst->format, surfaceDst->scanline, +- destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data, ++ destPt->x, destPt->y, rwidth, rheight, surfaceSrc->data, + surfaceSrc->format, surfaceSrc->scanline, rectSrc->left, + rectSrc->top, NULL, FREERDP_FLIP_NONE)) + goto fail; +-- +2.52.0 +