Version in base suite: 3.15.0+dfsg-2.1 Version in overlay suite: 3.15.0+dfsg-2.1+deb13u1 Base version: freerdp3_3.15.0+dfsg-2.1+deb13u1 Target version: freerdp3_3.15.0+dfsg-2.1+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/f/freerdp3/freerdp3_3.15.0+dfsg-2.1+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/f/freerdp3/freerdp3_3.15.0+dfsg-2.1+deb13u2.dsc changelog | 69 ++ patches/cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch | 31 + patches/cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch | 46 + patches/cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch | 52 + patches/codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch | 56 ++ patches/codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch | 34 + patches/codec-dsp-add-format-checks-CVE-2026-31884.patch | 274 ++++++++++ patches/codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch | 79 ++ patches/codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch | 224 ++++++++ patches/codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch | 39 + patches/codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch | 78 ++ patches/codec-nsc-bounds-checks-and-doxygen.patch | 86 +++ patches/codec-nsc-fix-use-of-nsc_process_message.patch | 93 +++ patches/codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch | 38 + patches/codec-nsc-log-decoder-function-parameter-issues.patch | 54 + patches/codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch | 32 + patches/codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch | 88 +++ patches/core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch | 37 + patches/core-order-fix-const-correctness.patch | 33 + patches/core-orders-improve-input-validation-CVE-2026-29776.patch | 30 + patches/series | 22 patches/winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch | 159 +++++ 22 files changed, 1654 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpa9n2w4zx/freerdp3_3.15.0+dfsg-2.1+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpa9n2w4zx/freerdp3_3.15.0+dfsg-2.1+deb13u2.dsc: no acceptable signature found diff -Nru freerdp3-3.15.0+dfsg/debian/changelog freerdp3-3.15.0+dfsg/debian/changelog --- freerdp3-3.15.0+dfsg/debian/changelog 2026-03-28 17:59:33.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/changelog 2026-04-03 15:45:10.000000000 +0000 @@ -1,3 +1,72 @@ +freerdp3 (3.15.0+dfsg-2.1+deb13u2) trixie; urgency=medium + + * security fixes for client from 3.24.0 (medium): + + CVE-2026-29774 Heap-buffer-overflow in avc420_yuv_to_rgb via OOB regionRects + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-5q35-hv9x-7794 + codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch + CVE-2026-29775 Heap-buffer-overflow in bitmap_cache_put via OOB cacheId + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-h666-rfw3-jhvj + cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch + CVE-2026-29776 Integer Underflow in update_read_cache_bitmap_order + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-c747-x4wf-cqrr + core-order-fix-const-correctness.patch + core-orders-improve-input-validation-CVE-2026-29776.patch + CVE-2026-31806 Heap Buffer Overflow in nsc_process_message() via Unchecked + SURFACE_BITS_COMMAND Bitmap Dimensions + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-rrqm-46rj-cmx2 + codec-nsc-bounds-checks-and-doxygen.patch + codec-nsc-log-decoder-function-parameter-issues.patch + codec-nsc-fix-use-of-nsc_process_message.patch + codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch + CVE-2026-31883 `size_t` underflow in ADPCM decoder leads to + heap-buffer-overflow write + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-85x9-4xxp-xhm5 + CVE-2026-31885 Out-of-bounds read in ADPCM decoders due to + missing predictor/step_index bounds checks + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-85x9-4xxp-xhm5 + codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch + CVE-2026-31884 Division-by-zero in ADPCM decoders when `nBlockAlign` is 0 + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-jp7m-94ww-p56r + codec-dsp-add-format-checks-CVE-2026-31884.patch + CVE-2026-31897 Out-of-bounds read in `freerdp_bitmap_decompress_planar` + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-xgv6-r22m-7c9x + codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch + + * security fixes for client from 3.24.2 (medium): + + CVE-2026-33952 DoS via WINPR_ASSERT in + rts_read_auth_verifier_no_checks (rts.c:282) + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4v4p-9v5x-hc93 + core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch + CVE-2026-33977 DoS via WINPR_ASSERT in IMA ADPCM audio decoder (dsp.c:331) + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8f2g-3q27-6xm5 + codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch + CVE-2026-33995 double free in kerberos_AcceptSecurityContext + and kerberos_IntitalizeSecurityContextA + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-mv25-f4p2-5mxx + winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch + CVE-2026-33984 ClearCodec resize_vbar_entry() Heap OOB Write + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8469-2xcx-frf6 + codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch + CVE-2026-33983 Progressive Codec Quant BYTE Underflow - UB + CPU DoS + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4gfm-4p52-h478 + codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch + CVE-2026-33985 ClearCodec Glyph Cache Count Desync - Heap OOB Read + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-x6gr-8p7h-5h85 + codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch + CVE-2026-33986 H.264 YUV Buffer Dimension Desync - Heap OOB Write + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-h6qw-wxvm-hf97 + codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch + CVE-2026-33987 Persistent Cache bmpSize Desync - Heap OOB Write + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-ff8h-p5vc-wcwc + cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch + CVE-2026-33982 Persistent Cache Allocator Mismatch - Heap OOB Read + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8jm9-2925-g4v2 + cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch + + -- Michael Tokarev Fri, 03 Apr 2026 18:45:10 +0300 + freerdp3 (3.15.0+dfsg-2.1+deb13u1) trixie; urgency=medium * two patches from upstream (from 3.16) (Closes: #1112191): diff -Nru freerdp3-3.15.0+dfsg/debian/patches/cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch freerdp3-3.15.0+dfsg/debian/patches/cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch --- freerdp3-3.15.0+dfsg/debian/patches/cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,31 @@ +From: Armin Novak +Date: Sat, 28 Feb 2026 11:38:55 +0100 +Subject: [cache,bitmap] overallocate bitmap cache +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/ffad58fd2b329efd81a3239e9d7e3c927b8e503f +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-h666-rfw3-jhvj +Bug: https://security-tracker.debian.org/tracker/CVE-2026-29775 + +--- + libfreerdp/cache/bitmap.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libfreerdp/cache/bitmap.c b/libfreerdp/cache/bitmap.c +index 96607444e..3da912a41 100644 +--- a/libfreerdp/cache/bitmap.c ++++ b/libfreerdp/cache/bitmap.c +@@ -373,7 +373,10 @@ rdpBitmapCache* bitmap_cache_new(rdpContext* context) + const UINT32 BitmapCacheV2NumCells = + freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells); + bitmapCache->context = context; +- bitmapCache->cells = (BITMAP_V2_CELL*)calloc(BitmapCacheV2NumCells, sizeof(BITMAP_V2_CELL)); ++ ++ /* overallocate by 1. older RDP servers do send a off by 1 cache index. */ ++ bitmapCache->cells = ++ (BITMAP_V2_CELL*)calloc(BitmapCacheV2NumCells + 1ull, sizeof(BITMAP_V2_CELL)); + + if (!bitmapCache->cells) + goto fail; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch freerdp3-3.15.0+dfsg/debian/patches/cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch --- freerdp3-3.15.0+dfsg/debian/patches/cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,46 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 09:57:19 +0100 +Subject: [cache,persist] use winpr_aligned_calloc +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/a48dbde2c8a5b8b70a9d1c045d969a71afd6284c +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8jm9-2925-g4v2 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33982 + +Consistently use winpr_aligned_* family for allocating/freeing the +buffers. +--- + libfreerdp/cache/persistent.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/libfreerdp/cache/persistent.c b/libfreerdp/cache/persistent.c +--- a/libfreerdp/cache/persistent.c ++++ b/libfreerdp/cache/persistent.c +@@ -39,6 +39,7 @@ struct rdp_persistent_cache + size_t bmpSize; + }; + ++static const size_t PERSIST_ALIGN = 32; + static const char sig_str[] = "RDP8bmp"; + + int persistent_cache_get_version(rdpPersistentCache* persistent) +@@ -155,7 +156,7 @@ static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent, + { + persistent->bmpSize = size; + BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize, +- sizeof(BYTE), 32); ++ sizeof(BYTE), PERSIST_ALIGN); + + if (!bmpData) + return -1; +@@ -350,7 +351,7 @@ rdpPersistentCache* persistent_cache_new(void) + return NULL; + + persistent->bmpSize = 0x4000; +- persistent->bmpData = calloc(1, persistent->bmpSize); ++ persistent->bmpData = winpr_aligned_calloc(1, persistent->bmpSize, PERSIST_ALIGN); + + if (!persistent->bmpData) + { +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch freerdp3-3.15.0+dfsg/debian/patches/cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch --- freerdp3-3.15.0+dfsg/debian/patches/cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,52 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 09:41:17 +0100 +Subject: [cache,persistent] update PERSISTENT_CACHE_ENTRY::size after +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/1a890eb43492b5eb707cb3dd6fc908f696e8fc1c +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-ff8h-p5vc-wcwc +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33987 + realloc + +Avoid invalid PERSISTENT_CACHE_ENTRY::size values in case realloc fails. +--- + libfreerdp/cache/persistent.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/libfreerdp/cache/persistent.c b/libfreerdp/cache/persistent.c +--- a/libfreerdp/cache/persistent.c ++++ b/libfreerdp/cache/persistent.c +@@ -36,7 +36,7 @@ struct rdp_persistent_cache + int count; + char* filename; + BYTE* bmpData; +- UINT32 bmpSize; ++ size_t bmpSize; + }; + + static const char sig_str[] = "RDP8bmp"; +@@ -149,12 +149,11 @@ static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent, + const UINT64 size = 4ull * entry3.width * entry3.height; + if (size > UINT32_MAX) + return -1; +- entry->size = (UINT32)size; + entry->flags = 0; + +- if (entry->size > persistent->bmpSize) ++ if (size > persistent->bmpSize) + { +- persistent->bmpSize = entry->size; ++ persistent->bmpSize = size; + BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize, + sizeof(BYTE), 32); + +@@ -163,6 +162,7 @@ static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent, + + persistent->bmpData = bmpData; + } ++ entry->size = WINPR_ASSERTING_INT_CAST(UINT32, size); + + entry->data = persistent->bmpData; + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch freerdp3-3.15.0+dfsg/debian/patches/codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,56 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 09:53:38 +0100 +Subject: [codec,clear] Update CLEAR_GLYPH_ENTRY::count after alloc +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/c49d1ad43b8c7b32794d0250f2623c2dccd7ef25 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-x6gr-8p7h-5h85 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33985 + +Ensure the value is always properly related to an existing buffer. +--- + libfreerdp/codec/clear.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -979,20 +979,30 @@ static BOOL clear_decompress_glyph_data(CLEAR_CONTEXT* WINPR_RESTRICT clear, + { + const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format); + CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]); +- glyphEntry->count = nWidth * nHeight; ++ const size_t count = 1ull * nWidth * nHeight; ++ const size_t hlimit = SIZE_MAX / ((nWidth > 0) ? nWidth : 1); ++ if ((nWidth == 0) || (nHeight == 0) || (hlimit < nHeight)) ++ { ++ const char* exceeded = (hlimit < nHeight) ? "within" : "outside"; ++ WLog_ERR(TAG, ++ "CLEARCODEC_FLAG_GLYPH_INDEX: nWidth=%" PRIu32 ", nHeight=%" PRIu32 ++ ", nWidth * nHeight is %s allowed range", ++ nWidth, nHeight, exceeded); ++ return FALSE; ++ } + +- if (glyphEntry->count > glyphEntry->size) ++ if (count > glyphEntry->size) + { +- BYTE* tmp = +- winpr_aligned_recalloc(glyphEntry->pixels, glyphEntry->count, 1ull * bpp, 32); ++ BYTE* tmp = winpr_aligned_recalloc(glyphEntry->pixels, count, 1ull * bpp, 32); + + if (!tmp) + { +- WLog_ERR(TAG, "glyphEntry->pixels winpr_aligned_recalloc %" PRIu32 " failed!", +- glyphEntry->count * bpp); ++ WLog_ERR(TAG, "glyphEntry->pixels winpr_aligned_recalloc %" PRIuz " failed!", ++ count * bpp); + return FALSE; + } + ++ glyphEntry->count = WINPR_ASSERTING_INT_CAST(UINT32, count); + glyphEntry->size = glyphEntry->count; + glyphEntry->pixels = (UINT32*)tmp; + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch freerdp3-3.15.0+dfsg/debian/patches/codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,34 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 09:48:54 +0100 +Subject: [codec,clear] update CLEAR_VBAR_ENTRY::size after alloc +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/dc7fdb165095139be779a4000199bc1706b06ad5 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8469-2xcx-frf6 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33984 + +--- + libfreerdp/codec/clear.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -565,7 +565,6 @@ static BOOL resize_vbar_entry(CLEAR_CONTEXT* WINPR_RESTRICT clear, + const UINT32 oldPos = vBarEntry->size * bpp; + const UINT32 diffSize = (vBarEntry->count - vBarEntry->size) * bpp; + +- vBarEntry->size = vBarEntry->count; + BYTE* tmp = + (BYTE*)winpr_aligned_recalloc(vBarEntry->pixels, vBarEntry->count, 1ull * bpp, 32); + +@@ -578,6 +577,7 @@ static BOOL resize_vbar_entry(CLEAR_CONTEXT* WINPR_RESTRICT clear, + + memset(&tmp[oldPos], 0, diffSize); + vBarEntry->pixels = tmp; ++ vBarEntry->size = vBarEntry->count; + } + + if (!vBarEntry->pixels && vBarEntry->size) +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-add-format-checks-CVE-2026-31884.patch freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-add-format-checks-CVE-2026-31884.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-add-format-checks-CVE-2026-31884.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-add-format-checks-CVE-2026-31884.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,274 @@ +From: Armin Novak +Date: Tue, 10 Mar 2026 09:57:16 +0100 +Subject: [codec,dsp] add format checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/03b48b3601d867afccac1cdc6081de7a275edce7 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-jp7m-94ww-p56r +Bug: https://security-tracker.debian.org/tracker/CVE-2026-31884 + +To avoid issues with invalid audio format settings always check before +use. + +Mjt: backport to trixie version +--- + libfreerdp/codec/dsp.c | 148 +++++++++++++++++++++++++++++++---------- + 1 file changed, 112 insertions(+), 36 deletions(-) + +diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c +index ae5a76543..969c12ce3 100644 +--- a/libfreerdp/codec/dsp.c ++++ b/libfreerdp/codec/dsp.c +@@ -362,11 +362,28 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, unsigned + return (UINT16)d; + } + ++static BOOL valid_ima_adpcm_format(const FREERDP_DSP_CONTEXT* WINPR_RESTRICT context) ++{ ++ WINPR_ASSERT(context); ++ if (context->common.format.wFormatTag != WAVE_FORMAT_DVI_ADPCM) ++ return FALSE; ++ if (context->common.format.nBlockAlign <= 4ULL) ++ return FALSE; ++ if (context->common.format.nChannels < 1) ++ return FALSE; ++ if (context->common.format.wBitsPerSample == 0) ++ return FALSE; ++ return TRUE; ++} ++ + static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + const BYTE* WINPR_RESTRICT src, size_t size, + wStream* WINPR_RESTRICT out) + { +- size_t out_size = size * 4; ++ if (!valid_ima_adpcm_format(context)) ++ return FALSE; ++ ++ size_t out_size = size * 4ull; + const UINT32 block_size = context->common.format.nBlockAlign; + const UINT32 channels = context->common.format.nChannels; + +@@ -518,27 +535,38 @@ static BOOL freerdp_dsp_encode_gsm610(FREERDP_DSP_CONTEXT* WINPR_RESTRICT contex + #endif + + #if defined(WITH_LAME) ++static BOOL valid_mp3_format(const FREERDP_DSP_CONTEXT* WINPR_RESTRICT context) ++{ ++ WINPR_ASSERT(context); ++ if (context->common.format.wFormatTag != WAVE_FORMAT_MPEGLAYER3) ++ return FALSE; ++ if (context->common.format.nChannels < 1) ++ return FALSE; ++ if (context->common.format.wBitsPerSample == 0) ++ return FALSE; ++ if (context->common.format.nSamplesPerSec == 0) ++ return FALSE; ++ return TRUE; ++} ++ + static BOOL freerdp_dsp_decode_mp3(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + const BYTE* WINPR_RESTRICT src, size_t size, + wStream* WINPR_RESTRICT out) + { +- int rc; +- short* pcm_l; +- short* pcm_r; +- size_t buffer_size; +- + if (!context || !src || !out) + return FALSE; +- +- buffer_size = 2 * context->common.format.nChannels * context->common.format.nSamplesPerSec; ++ if (!valid_mp3_format(context)) ++ return FALSE; ++ const size_t buffer_size = ++ 2 * context->common.format.nChannels * context->common.format.nSamplesPerSec; + + if (!Stream_EnsureCapacity(context->common.buffer, 2 * buffer_size)) + return FALSE; + +- pcm_l = Stream_BufferAs(context->common.buffer, short); +- pcm_r = Stream_BufferAs(context->common.buffer, short) + buffer_size; +- rc = hip_decode(context->hip, (unsigned char*)/* API is not modifying content */ src, size, +- pcm_l, pcm_r); ++ short* pcm_l = Stream_BufferAs(context->common.buffer, short); ++ short* pcm_r = Stream_BufferAs(context->common.buffer, short) + buffer_size; ++ const int rc = hip_decode(context->hip, (unsigned char*)/* API is not modifying content */ src, ++ size, pcm_l, pcm_r); + + if (rc <= 0) + return FALSE; +@@ -559,13 +587,13 @@ static BOOL freerdp_dsp_encode_mp3(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + const BYTE* WINPR_RESTRICT src, size_t size, + wStream* WINPR_RESTRICT out) + { +- size_t samples_per_channel; +- int rc; +- + if (!context || !src || !out) + return FALSE; + +- samples_per_channel = ++ if (!valid_mp3_format(context)) ++ return FALSE; ++ ++ size_t samples_per_channel = + size / context->common.format.nChannels / context->common.format.wBitsPerSample / 8; + + /* Ensure worst case buffer size for mp3 stream taken from LAME header */ +@@ -573,8 +601,9 @@ static BOOL freerdp_dsp_encode_mp3(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + return FALSE; + + samples_per_channel = size / 2 /* size of a sample */ / context->common.format.nChannels; +- rc = lame_encode_buffer_interleaved(context->lame, (short*)src, samples_per_channel, +- Stream_Pointer(out), Stream_GetRemainingCapacity(out)); ++ const int rc = ++ lame_encode_buffer_interleaved(context->lame, (short*)src, samples_per_channel, ++ Stream_Pointer(out), Stream_GetRemainingCapacity(out)); + + if (rc < 0) + return FALSE; +@@ -834,6 +863,8 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con + const BYTE* WINPR_RESTRICT src, size_t size, + wStream* WINPR_RESTRICT out) + { ++ if (!valid_ima_adpcm_format(context)) ++ return FALSE; + if (!Stream_EnsureRemainingCapacity(out, size)) + return FALSE; + if (!Stream_EnsureRemainingCapacity(context->common.buffer, size + 64)) +@@ -957,10 +988,26 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adp + return (INT16)presample; + } + ++static BOOL valid_ms_adpcm_format(const FREERDP_DSP_CONTEXT* WINPR_RESTRICT context) ++{ ++ WINPR_ASSERT(context); ++ if (context->common.format.wFormatTag != WAVE_FORMAT_ADPCM) ++ return FALSE; ++ if (context->common.format.nBlockAlign <= 4ULL) ++ return FALSE; ++ if (context->common.format.nChannels < 1) ++ return FALSE; ++ if (context->common.format.wBitsPerSample == 0) ++ return FALSE; ++ return TRUE; ++} ++ + static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + const BYTE* WINPR_RESTRICT src, size_t size, + wStream* WINPR_RESTRICT out) + { ++ if (!valid_ms_adpcm_format(context)) ++ return FALSE; + const size_t out_size = size * 4; + const UINT32 channels = context->common.format.nChannels; + const UINT32 block_size = context->common.format.nBlockAlign; +@@ -1099,6 +1146,9 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont + const BYTE* WINPR_RESTRICT src, size_t size, + wStream* WINPR_RESTRICT out) + { ++ if (!valid_ms_adpcm_format(context)) ++ return FALSE; ++ + const size_t step = 8 + ((context->common.format.nChannels > 1) ? 4 : 0); + + if (!Stream_EnsureRemainingCapacity(out, size)) +@@ -1543,21 +1593,44 @@ BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + + context->common.format = *targetFormat; + +- if (context->common.format.wFormatTag == WAVE_FORMAT_DVI_ADPCM) ++ switch (context->common.format.wFormatTag) + { +- size_t min_frame_data = 1ull * context->common.format.wBitsPerSample * +- context->common.format.nChannels * FramesPerPacket; +- size_t data_per_block = +- (1ULL * context->common.format.nBlockAlign - 4ULL * context->common.format.nChannels) * +- 8ULL; +- size_t nb_block_per_packet = min_frame_data / data_per_block; +- +- if (min_frame_data % data_per_block) +- nb_block_per_packet++; +- +- context->adpcm.ima.packet_size = nb_block_per_packet * context->common.format.nBlockAlign; +- Stream_EnsureCapacity(context->common.buffer, context->adpcm.ima.packet_size); +- Stream_SetPosition(context->common.buffer, 0); ++#if defined(WITH_LAME) ++ case WAVE_FORMAT_MPEGLAYER3: ++ if (!valid_mp3_format(context)) ++ return FALSE; ++ break; ++#endif ++ case WAVE_FORMAT_ADPCM: ++ if (!valid_ms_adpcm_format(context)) ++ return FALSE; ++ break; ++ case WAVE_FORMAT_DVI_ADPCM: ++ { ++ if (!valid_ima_adpcm_format(context)) ++ return FALSE; ++ if (FramesPerPacket == 0) ++ return FALSE; ++ ++ const size_t min_frame_data = 1ull * context->common.format.wBitsPerSample * ++ context->common.format.nChannels * FramesPerPacket; ++ const size_t data_per_block = (1ULL * context->common.format.nBlockAlign - ++ 4ULL * context->common.format.nChannels) * ++ 8ULL; ++ size_t nb_block_per_packet = min_frame_data / data_per_block; ++ ++ if (min_frame_data % data_per_block) ++ nb_block_per_packet++; ++ ++ context->adpcm.ima.packet_size = ++ nb_block_per_packet * context->common.format.nBlockAlign; ++ if (!Stream_EnsureCapacity(context->common.buffer, context->adpcm.ima.packet_size)) ++ return FALSE; ++ Stream_SetPosition(context->common.buffer, 0); ++ } ++ break; ++ default: ++ break; + } + + #if defined(WITH_OPUS) +@@ -1600,7 +1673,7 @@ BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + + if (context->common.encoder) + { +- faacEncConfigurationPtr cfg; ++ faacEncConfigurationPtr cfg = nullptr; + + if (context->faac) + faacEncClose(context->faac); +@@ -1617,20 +1690,23 @@ BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context, + cfg->mpegVersion = MPEG4; + cfg->useTns = 1; + cfg->bandWidth = targetFormat->nAvgBytesPerSec; +- faacEncSetConfiguration(context->faac, cfg); ++ const int rc = faacEncSetConfiguration(context->faac, cfg); ++ if (rc <= 0) ++ return FALSE; + } + + #endif + #if defined(WITH_SOXR) + { + soxr_io_spec_t iospec = soxr_io_spec(SOXR_INT16, SOXR_INT16); +- soxr_error_t error; ++ soxr_error_t error = nullptr; ++ + soxr_delete(context->sox); + context->sox = + soxr_create(context->common.format.nSamplesPerSec, targetFormat->nSamplesPerSec, + targetFormat->nChannels, &error, &iospec, NULL, NULL); + +- if (!context->sox || (error != 0)) ++ if (!context->sox || (error != nullptr)) + return FALSE; + } + #endif +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,79 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 09:23:18 +0100 +Subject: [codec,dsp] fix IMA ADPCM sample clamping +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/9be3f03d94a50892fd58a9f7dee72b2313c69b47 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8f2g-3q27-6xm5 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33977 + +--- + libfreerdp/codec/dsp.c | 26 ++++++++++++++++++-------- + 1 file changed, 18 insertions(+), 8 deletions(-) + +diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c +--- a/libfreerdp/codec/dsp.c ++++ b/libfreerdp/codec/dsp.c +@@ -318,6 +318,17 @@ static const INT16 ima_step_size_table[] = { + 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + }; + ++static inline void dsp_ima_clamp_step(ADPCM* WINPR_RESTRICT adpcm, unsigned int channel) ++{ ++ WINPR_ASSERT(adpcm); ++ if (adpcm->ima.last_step[channel] < 0) ++ adpcm->ima.last_step[channel] = 0; ++ ++ const size_t size = ARRAYSIZE(ima_step_size_table); ++ if (adpcm->ima.last_step[channel] > size) ++ adpcm->ima.last_step[channel] = size; ++} ++ + static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, unsigned int channel, + BYTE sample) + { +@@ -354,10 +365,7 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, unsigned + WINPR_ASSERT(sample < ARRAYSIZE(ima_step_index_table)); + adpcm->ima.last_step[channel] += ima_step_index_table[sample]; + +- if (adpcm->ima.last_step[channel] < 0) +- adpcm->ima.last_step[channel] = 0; +- else if (adpcm->ima.last_step[channel] > 88) +- adpcm->ima.last_step[channel] = 88; ++ dsp_ima_clamp_step(adpcm, channel); + + return (UINT16)d; + } +@@ -400,6 +408,9 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con + context->adpcm.ima.last_sample[0] = + (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + context->adpcm.ima.last_step[0] = (INT16)(*(src + 2)); ++ ++ dsp_ima_clamp_step(&context->adpcm, 0); ++ + src += 4; + size -= 4; + out_size -= 16; +@@ -411,6 +422,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con + context->adpcm.ima.last_sample[1] = + (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + context->adpcm.ima.last_step[1] = (INT16)(*(src + 2)); ++ ++ dsp_ima_clamp_step(&context->adpcm, 1); + src += 4; + size -= 4; + out_size -= 16; +@@ -851,10 +864,7 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, size_t chan + WINPR_ASSERT(enc < ARRAYSIZE(ima_step_index_table)); + adpcm->ima.last_step[channel] += ima_step_index_table[enc]; + +- if (adpcm->ima.last_step[channel] < 0) +- adpcm->ima.last_step[channel] = 0; +- else if (adpcm->ima.last_step[channel] > 88) +- adpcm->ima.last_step[channel] = 88; ++ dsp_ima_clamp_step(adpcm, channel); + + return enc; + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,224 @@ +From: Armin Novak +Date: Tue, 10 Mar 2026 10:21:40 +0100 +Subject: [codec,dsp] fix array bounds checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/83d9aedea278a74af3e490ff5eeb889c016dbb2b +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-85x9-4xxp-xhm5 +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-h23r-3988-3wf3 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-31883 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-31885 + +* assert array indices where caller value is an internal constant +* add missing length/bounds checks + +Mjt: back-port to debian trixie version +--- + libfreerdp/codec/dsp.c | 77 +++++++++++++++++++++++++++++++++++++----- + 1 file changed, 68 insertions(+), 9 deletions(-) + +diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c +index dbd11f1b0..ae5a76543 100644 +--- a/libfreerdp/codec/dsp.c ++++ b/libfreerdp/codec/dsp.c +@@ -321,7 +321,14 @@ static const INT16 ima_step_size_table[] = { + static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, unsigned int channel, + BYTE sample) + { +- const INT32 ss = ima_step_size_table[adpcm->ima.last_step[channel]]; ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_step)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_sample)); ++ ++ const INT16 offset = adpcm->ima.last_step[channel]; ++ WINPR_ASSERT(offset >= 0); ++ WINPR_ASSERT(offset < ARRAYSIZE(ima_step_size_table)); ++ ++ const INT32 ss = ima_step_size_table[offset]; + INT32 d = (ss >> 3); + + if (sample & 1) +@@ -344,6 +351,7 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, unsigned + d = 32767; + + adpcm->ima.last_sample[channel] = (INT16)d; ++ WINPR_ASSERT(sample < ARRAYSIZE(ima_step_index_table)); + adpcm->ima.last_step[channel] += ima_step_index_table[sample]; + + if (adpcm->ima.last_step[channel] < 0) +@@ -369,6 +377,9 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con + { + if (size % block_size == 0) + { ++ if (size < 4) ++ return FALSE; ++ + context->adpcm.ima.last_sample[0] = + (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + context->adpcm.ima.last_step[0] = (INT16)(*(src + 2)); +@@ -378,6 +389,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con + + if (channels > 1) + { ++ if (size < 4) ++ return FALSE; + context->adpcm.ima.last_sample[1] = + (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + context->adpcm.ima.last_step[1] = (INT16)(*(src + 2)); +@@ -389,6 +402,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con + + if (channels > 1) + { ++ if (size < 8) ++ return FALSE; + for (size_t i = 0; i < 8; i++) + { + BYTE* dst = Stream_Pointer(out); +@@ -417,6 +432,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con + } + else + { ++ if (size < 1) ++ return FALSE; + BYTE* dst = Stream_Pointer(out); + if (!Stream_SafeSeek(out, 4)) + return FALSE; +@@ -748,7 +765,14 @@ static const struct + + static BYTE dsp_encode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, size_t channel, INT16 sample) + { +- INT32 ss = ima_step_size_table[adpcm->ima.last_step[channel]]; ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_step)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_sample)); ++ ++ const INT16 offset = adpcm->ima.last_step[channel]; ++ WINPR_ASSERT(offset >= 0); ++ WINPR_ASSERT(offset < ARRAYSIZE(ima_step_size_table)); ++ ++ INT32 ss = ima_step_size_table[offset]; + INT32 e = sample - adpcm->ima.last_sample[channel]; + INT32 d = e; + INT32 diff = ss >> 3; +@@ -795,6 +819,7 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, size_t chan + diff = 32767; + + adpcm->ima.last_sample[channel] = (INT16)diff; ++ WINPR_ASSERT(enc < ARRAYSIZE(ima_step_index_table)); + adpcm->ima.last_step[channel] += ima_step_index_table[enc]; + + if (adpcm->ima.last_step[channel] < 0) +@@ -894,11 +919,22 @@ static const INT32 ms_adpcm_coeffs2[7] = { 0, -256, 0, 64, 0, -208, -232 }; + static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, BYTE sample, + size_t channel) + { ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample1)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample2)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.delta)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.predictor)); ++ + const INT8 nibble = (sample & 0x08 ? (INT8)sample - 16 : (INT8)sample); ++ const BYTE predictor = adpcm->ms.predictor[channel]; ++ INT32 coeff1 = 0; ++ if (predictor < ARRAYSIZE(ms_adpcm_coeffs1)) ++ coeff1 = ms_adpcm_coeffs1[predictor]; ++ ++ INT32 coeff2 = 0; ++ if (predictor < ARRAYSIZE(ms_adpcm_coeffs2)) ++ coeff2 = ms_adpcm_coeffs2[predictor]; + INT32 presample = +- ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + +- (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / +- 256; ++ ((adpcm->ms.sample1[channel] * coeff1) + (adpcm->ms.sample2[channel] * coeff2)) / 256; + presample += nibble * adpcm->ms.delta[channel]; + + if (presample > 32767) +@@ -908,7 +944,12 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adp + + adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel]; + adpcm->ms.sample1[channel] = presample; +- adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[sample] / 256; ++ ++ INT32 tableval = 0; ++ if (sample < ARRAYSIZE(ms_adpcm_adaptation_table)) ++ tableval = ms_adpcm_adaptation_table[sample]; ++ ++ adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * tableval / 256; + + if (adpcm->ms.delta[channel] < 16) + adpcm->ms.delta[channel] = 16; +@@ -933,6 +974,9 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont + { + if (channels > 1) + { ++ if (size < 14) ++ return FALSE; ++ + context->adpcm.ms.predictor[0] = *src++; + context->adpcm.ms.predictor[1] = *src++; + context->adpcm.ms.delta[0] = read_int16(src); +@@ -955,6 +999,9 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont + } + else + { ++ if (size < 7) ++ return FALSE; ++ + context->adpcm.ms.predictor[0] = *src++; + context->adpcm.ms.delta[0] = read_int16(src); + src += 2; +@@ -971,6 +1018,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont + if (channels > 1) + { + { ++ if (size < 1) ++ return FALSE; + const BYTE sample = *src++; + size--; + Stream_Write_INT16( +@@ -979,6 +1028,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont + out, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1)); + } + { ++ if (size < 1) ++ return FALSE; + const BYTE sample = *src++; + size--; + Stream_Write_INT16( +@@ -989,6 +1040,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont + } + else + { ++ if (size < 1) ++ return FALSE; + const BYTE sample = *src++; + size--; + Stream_Write_INT16(out, +@@ -1002,8 +1055,13 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont + } + + static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, INT32 sample, +- int channel) ++ size_t channel) + { ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample1)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample2)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.delta)); ++ WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.predictor)); ++ + INT32 presample = + ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + + (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / +@@ -1027,8 +1085,9 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, INT3 + + adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel]; + adpcm->ms.sample1[channel] = presample; +- adpcm->ms.delta[channel] = +- adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[(((BYTE)errordelta) & 0x0F)] / 256; ++ const size_t offset = (((BYTE)errordelta) & 0x0F); ++ WINPR_ASSERT(offset < ARRAYSIZE(ms_adpcm_adaptation_table)); ++ adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[offset] / 256; + + if (adpcm->ms.delta[channel] < 16) + adpcm->ms.delta[channel] = 16; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch freerdp3-3.15.0+dfsg/debian/patches/codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,39 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 09:45:56 +0100 +Subject: [codec,h264] update H264_CONTEXT::width,height after alloc +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/f6e43e208958140074ae9bb93cd0c9045a371c77 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-h6qw-wxvm-hf97 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33986 + +Ensure the width/height values are only updated after the buffers were +successfully allocated. +--- + libfreerdp/codec/h264.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c +--- a/libfreerdp/codec/h264.c ++++ b/libfreerdp/codec/h264.c +@@ -83,9 +83,6 @@ static BOOL yuv_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, U + h264->iStride[2] = (stride + 1) / 2; + } + +- h264->width = width; +- h264->height = height; +- + for (size_t x = 0; x < nPlanes; x++) + { + BYTE* tmp1 = winpr_aligned_recalloc(h264->pYUVData[x], h264->iStride[x], pheight, 16); +@@ -98,6 +95,8 @@ static BOOL yuv_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, U + if (!tmp1 || !tmp2) + return FALSE; + } ++ h264->width = width; ++ h264->height = height; + } + + return TRUE; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch freerdp3-3.15.0+dfsg/debian/patches/codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,78 @@ +From: Armin Novak +Date: Sat, 28 Feb 2026 11:38:23 +0100 +Subject: [codec,h264] validate rectangles before use +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/6482b7a92fff3959582cef052d1967ad6bde3738 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-5q35-hv9x-7794 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-29774 + +--- + libfreerdp/codec/h264.c | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c +index 4c09503f8..434d0cfa7 100644 +--- a/libfreerdp/codec/h264.c ++++ b/libfreerdp/codec/h264.c +@@ -108,6 +108,36 @@ BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT3 + return yuv_ensure_buffer(h264, stride, width, height); + } + ++static BOOL isRectValid(UINT32 width, UINT32 height, const RECTANGLE_16* rect) ++{ ++ WINPR_ASSERT(rect); ++ if (rect->left > width) ++ return FALSE; ++ if (rect->right > width) ++ return FALSE; ++ if (rect->left >= rect->right) ++ return FALSE; ++ if (rect->top > height) ++ return FALSE; ++ if (rect->bottom > height) ++ return FALSE; ++ if (rect->top >= rect->bottom) ++ return FALSE; ++ return TRUE; ++} ++ ++static BOOL areRectsValid(UINT32 width, UINT32 height, const RECTANGLE_16* rects, UINT32 count) ++{ ++ WINPR_ASSERT(rects || (count == 0)); ++ for (size_t x = 0; x < count; x++) ++ { ++ const RECTANGLE_16* rect = &rects[x]; ++ if (!isRectValid(width, height, rect)) ++ return FALSE; ++ } ++ return TRUE; ++} ++ + INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, + DWORD DstFormat, UINT32 nDstStep, WINPR_ATTR_UNUSED UINT32 nDstWidth, + WINPR_ATTR_UNUSED UINT32 nDstHeight, const RECTANGLE_16* regionRects, +@@ -119,6 +149,9 @@ INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize + if (!h264 || h264->Compressor) + return -1001; + ++ if (!areRectsValid(nDstWidth, nDstHeight, regionRects, numRegionRects)) ++ return -1013; ++ + status = h264->subsystem->Decompress(h264, pSrcData, SrcSize); + + if (status == 0) +@@ -569,6 +602,11 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, const RECTANGLE_16* regionR + if (!h264 || !regionRects || !pSrcData || !pDstData || h264->Compressor) + return -1001; + ++ if (!areRectsValid(nDstWidth, nDstHeight, regionRects, numRegionRects)) ++ return -1013; ++ if (!areRectsValid(nDstWidth, nDstHeight, auxRegionRects, numAuxRegionRect)) ++ return -1014; ++ + switch (op) + { + case 0: /* YUV420 in stream 1 +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-bounds-checks-and-doxygen.patch freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-bounds-checks-and-doxygen.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-bounds-checks-and-doxygen.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-bounds-checks-and-doxygen.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,86 @@ +From: Armin Novak +Date: Sun, 15 Feb 2026 19:32:38 +0100 +Subject: [codec,nsc] bounds checks and doxygen +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/f4d74c33fd58e9e9e4e52d75b0d1255af8fa4b53 +Forwarded: not-needed +Comment: preparation for CVE-2026-31806 fix + +* Improve doxygen for nsc_process_message +* Improve bounds checks for nsc_process_message +--- + include/freerdp/codec/nsc.h | 22 ++++++++++++++++++++++ + libfreerdp/codec/nsc.c | 12 +++++++++--- + 2 files changed, 31 insertions(+), 3 deletions(-) + +diff --git a/include/freerdp/codec/nsc.h b/include/freerdp/codec/nsc.h +--- a/include/freerdp/codec/nsc.h ++++ b/include/freerdp/codec/nsc.h +@@ -53,11 +53,33 @@ extern "C" + FREERDP_API BOOL nsc_context_set_parameters(NSC_CONTEXT* WINPR_RESTRICT context, + NSC_PARAMETER what, UINT32 value); + ++ /** @brief decode a NSC message ++ * ++ * @param context The context to work on ++ * @param bpp The bit depth of the data ++ * @param width The width in pixels of the NSC surface ++ * @param height The height in pixels of the NSC surface ++ * @param data The data to decode ++ * @param length The length of \ref data in bytes ++ * @param pDstData The destination buffer. Must be at least \n nDstStride * nHeight in size. ++ * @param DstFormat The color format of the destination ++ * @param nDstStride The number of bytes per destination buffer line. Must be larger than ++ * bytes(DstFormat) * nWidth or \0 (in which case it is set to former minimum bound) ++ * @param nXDst The X offset in the destination buffer in pixels ++ * @param nYDst The Y offset in the destination buffer in pixels ++ * @param nWidth The width of the destination buffer in pixels ++ * @param nHeight The height of the destination buffer in pixels ++ * @param flip Image flipping flags FREERDP_FLIP_NONE et al passed on to \ref ++ * freerdp_image_copy ++ * ++ * @return \b TRUE in case of success, \b FALSE for any error. Check WLog for details. ++ */ + FREERDP_API BOOL nsc_process_message(NSC_CONTEXT* WINPR_RESTRICT context, UINT16 bpp, + UINT32 width, UINT32 height, const BYTE* data, + UINT32 length, BYTE* WINPR_RESTRICT pDstData, + UINT32 DstFormat, UINT32 nDstStride, UINT32 nXDst, + UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 flip); ++ + FREERDP_API BOOL nsc_compose_message(NSC_CONTEXT* WINPR_RESTRICT context, + wStream* WINPR_RESTRICT s, + const BYTE* WINPR_RESTRICT bmpdata, UINT32 width, +diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c +--- a/libfreerdp/codec/nsc.c ++++ b/libfreerdp/codec/nsc.c +@@ -436,19 +436,25 @@ BOOL nsc_process_message(NSC_CONTEXT* WINPR_RESTRICT context, UINT16 bpp, UINT32 + UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, + WINPR_ATTR_UNUSED UINT32 nHeight, UINT32 flip) + { +- wStream* s = NULL; + wStream sbuffer = { 0 }; + BOOL ret = 0; + if (!context || !data || !pDstData) + return FALSE; + +- s = Stream_StaticConstInit(&sbuffer, data, length); ++ if (nXDst > nWidth) ++ return FALSE; ++ if (nYDst > nHeight) ++ return FALSE; + ++ wStream* s = Stream_StaticConstInit(&sbuffer, data, length); + if (!s) + return FALSE; + ++ const UINT32 minStride = nWidth * FreeRDPGetBytesPerPixel(DstFormat); + if (nDstStride == 0) +- nDstStride = nWidth * FreeRDPGetBytesPerPixel(DstFormat); ++ nDstStride = minStride; ++ if (nDstStride < minStride) ++ return FALSE; + + switch (bpp) + { +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-fix-use-of-nsc_process_message.patch freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-fix-use-of-nsc_process_message.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-fix-use-of-nsc_process_message.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-fix-use-of-nsc_process_message.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,93 @@ +From: Armin Novak +Date: Tue, 17 Feb 2026 08:38:04 +0100 +Subject: [codec,nsc] fix use of nsc_process_message +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/169971607cece48384cb94632b829bd57336af0f +Forwarded: not-needed +Comment: preparation for CVE-2026-31806 fix + +the second width/height argument should reflect the destination buffer +pixel size +--- + libfreerdp/codec/clear.c | 10 ++++++---- + libfreerdp/codec/nsc.c | 12 +++++++----- + libfreerdp/gdi/gdi.c | 5 +++-- + 3 files changed, 16 insertions(+), 11 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -133,7 +133,8 @@ static BOOL convert_color(BYTE* WINPR_RESTRICT dst, UINT32 nDstStep, UINT32 DstF + static BOOL clear_decompress_nscodec(NSC_CONTEXT* WINPR_RESTRICT nsc, UINT32 width, UINT32 height, + wStream* WINPR_RESTRICT s, UINT32 bitmapDataByteCount, + BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, +- UINT32 nDstStep, UINT32 nXDstRel, UINT32 nYDstRel) ++ UINT32 nDstStep, UINT32 nXDstRel, UINT32 nYDstRel, ++ UINT32 nDstWidth, UINT32 nDstHeight) + { + BOOL rc = 0; + +@@ -141,8 +142,8 @@ static BOOL clear_decompress_nscodec(NSC_CONTEXT* WINPR_RESTRICT nsc, UINT32 wid + return FALSE; + + rc = nsc_process_message(nsc, 32, width, height, Stream_Pointer(s), bitmapDataByteCount, +- pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel, width, height, +- FREERDP_FLIP_NONE); ++ pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel, nDstWidth, ++ nDstHeight, FREERDP_FLIP_NONE); + Stream_Seek(s, bitmapDataByteCount); + return rc; + } +@@ -532,7 +533,8 @@ static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* WINPR_RESTRICT clear, + + case 1: /* NSCodec */ + if (!clear_decompress_nscodec(clear->nsc, width, height, s, bitmapDataByteCount, +- pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel)) ++ pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel, ++ nDstWidth, nDstHeight)) + return FALSE; + + break; +diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c +--- a/libfreerdp/codec/nsc.c ++++ b/libfreerdp/codec/nsc.c +@@ -433,15 +433,17 @@ BOOL nsc_context_set_parameters(NSC_CONTEXT* WINPR_RESTRICT context, NSC_PARAMET + BOOL nsc_process_message(NSC_CONTEXT* WINPR_RESTRICT context, UINT16 bpp, UINT32 width, + UINT32 height, const BYTE* data, UINT32 length, + BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStride, +- UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, +- WINPR_ATTR_UNUSED UINT32 nHeight, UINT32 flip) ++ UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 flip) + { ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(context->priv); ++ + wStream sbuffer = { 0 }; + BOOL ret = 0; +- if (!context || !data || !pDstData) ++ if (!data || !pDstData) + { +- WLog_ERR(TAG, "Invalid argument: context=%p, data=%p, pDstData=%p", (void*)context, +- (const void*)data, (void*)pDstData); ++ WLog_Print(context->priv->log, WLOG_ERROR, "Invalid argument: data=%p, pDstData=%p", ++ (const void*)data, (void*)pDstData); + return FALSE; + } + +diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c +--- a/libfreerdp/gdi/gdi.c ++++ b/libfreerdp/gdi/gdi.c +@@ -1144,8 +1144,9 @@ static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cm + if (!nsc_process_message( + context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height, + cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format, +- gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left, +- cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL)) ++ gdi->stride, cmdRect.left, cmdRect.top, ++ WINPR_ASSERTING_INT_CAST(UINT32, gdi->width), ++ WINPR_ASSERTING_INT_CAST(UINT32, gdi->height), FREERDP_FLIP_VERTICAL)) + { + WLog_ERR(TAG, "Failed to process NSCodec message"); + goto out; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,38 @@ +From: Armin Novak +Date: Mon, 9 Mar 2026 08:11:19 +0100 +Subject: [codec,nsc] limit copy area in nsc_process_message +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/83d9aedea278a74af3e490ff5eeb889c016dbb2b +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-rrqm-46rj-cmx2 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-31806 + +the rectangle decoded might not fit into the destination buffer. Limit +width and height of the area to copy to the one fitting. +(Mjt: backport to debian trixie version) +--- + libfreerdp/codec/nsc.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c +--- a/libfreerdp/codec/nsc.c ++++ b/libfreerdp/codec/nsc.c +@@ -504,7 +504,15 @@ BOOL nsc_process_message(NSC_CONTEXT* WINPR_RESTRICT context, UINT16 bpp, UINT32 + return FALSE; + } + +- if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStride, nXDst, nYDst, width, height, ++ uint32_t cwidth = width; ++ if (1ull * nXDst + width > nWidth) ++ cwidth = nWidth - nXDst; ++ ++ uint32_t cheight = height; ++ if (1ull * nYDst + height > nHeight) ++ cheight = nHeight - nYDst; ++ ++ if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStride, nXDst, nYDst, cwidth, cheight, + context->BitmapData, PIXEL_FORMAT_BGRA32, 0, 0, 0, NULL, + flip)) + return FALSE; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-log-decoder-function-parameter-issues.patch freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-log-decoder-function-parameter-issues.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-log-decoder-function-parameter-issues.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-log-decoder-function-parameter-issues.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,54 @@ +From: Armin Novak +Date: Tue, 17 Feb 2026 08:17:33 +0100 +Subject: [codec,nsc] log decoder function parameter issues +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/caf6e7f2ecd2d71cd70719956f7d60bcacb1701b +Forwarded: not-needed +Comment: preparation for CVE-2026-31806 fix + +--- + libfreerdp/codec/nsc.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c +--- a/libfreerdp/codec/nsc.c ++++ b/libfreerdp/codec/nsc.c +@@ -439,12 +439,24 @@ BOOL nsc_process_message(NSC_CONTEXT* WINPR_RESTRICT context, UINT16 bpp, UINT32 + wStream sbuffer = { 0 }; + BOOL ret = 0; + if (!context || !data || !pDstData) ++ { ++ WLog_ERR(TAG, "Invalid argument: context=%p, data=%p, pDstData=%p", (void*)context, ++ (const void*)data, (void*)pDstData); + return FALSE; ++ } + + if (nXDst > nWidth) ++ { ++ WLog_Print(context->priv->log, WLOG_ERROR, "nXDst %" PRIu32 " > nWidth %" PRIu32, nXDst, ++ nWidth); + return FALSE; ++ } + if (nYDst > nHeight) ++ { ++ WLog_Print(context->priv->log, WLOG_ERROR, "nYDst %" PRIu32 " > nHeight %" PRIu32, nYDst, ++ nHeight); + return FALSE; ++ } + + wStream* s = Stream_StaticConstInit(&sbuffer, data, length); + if (!s) +@@ -454,7 +466,11 @@ BOOL nsc_process_message(NSC_CONTEXT* WINPR_RESTRICT context, UINT16 bpp, UINT32 + if (nDstStride == 0) + nDstStride = minStride; + if (nDstStride < minStride) ++ { ++ WLog_Print(context->priv->log, WLOG_ERROR, ++ "nDstStride %" PRIu32 " < minimum stride %" PRIu32, nDstStride, minStride); + return FALSE; ++ } + + switch (bpp) + { +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch freerdp3-3.15.0+dfsg/debian/patches/codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,32 @@ +From: Armin Novak +Date: Tue, 10 Mar 2026 09:17:23 +0100 +Subject: [codec,planar] add early length check to avoid oob read +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/cd27c8faca0eeb0d4309cc5837dfdf3c42eba4e7 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-xgv6-r22m-7c9x +Bug: https://security-tracker.debian.org/tracker/CVE-2026-31897 + +Mjt: adjust for debian trixie version +--- + libfreerdp/codec/planar.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c +index 6e2246040..190ad43ca 100644 +--- a/libfreerdp/codec/planar.c ++++ b/libfreerdp/codec/planar.c +@@ -718,9 +718,9 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT planar, + + const BYTE* srcp = pSrcData; + +- if (!pSrcData) ++ if (!pSrcData || (SrcSize < 1)) + { +- WLog_ERR(TAG, "Invalid argument pSrcData=NULL"); ++ WLog_ERR(TAG, "Invalid argument pSrcData=%p [size=%" PRIu32 "]", pSrcData, SrcSize); + return FALSE; + } + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch freerdp3-3.15.0+dfsg/debian/patches/codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,88 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 10:03:56 +0100 +Subject: [codec,progressive] Fail progressive_rfx_quant_sub on invalid values +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/78188ab479c8e6eb9ba2475b3732c76b4bbe5425 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4gfm-4p52-h478 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33983 +Comment: mjt: back-port to the debian trixie version + +--- + libfreerdp/codec/progressive.c | 41 +++++++++++++++++++++++++++++++--- + 1 file changed, 38 insertions(+), 3 deletions(-) + +diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c +--- a/libfreerdp/codec/progressive.c ++++ b/libfreerdp/codec/progressive.c +@@ -108,20 +108,51 @@ static INLINE void progressive_rfx_quant_lsub(RFX_COMPONENT_CODEC_QUANT* WINPR_R + q->LL3 -= val; /* LL3 */ + } + +-static INLINE void progressive_rfx_quant_sub(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1, ++static INLINE BOOL progressive_rfx_quant_sub(const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q1, + const RFX_COMPONENT_CODEC_QUANT* WINPR_RESTRICT q2, + RFX_COMPONENT_CODEC_QUANT* dst) + { ++ if (q1->HH1 < q2->HL1) ++ return FALSE; + dst->HL1 = q1->HL1 - q2->HL1; /* HL1 */ ++ ++ if (q1->LH1 < q2->LH1) ++ return FALSE; + dst->LH1 = q1->LH1 - q2->LH1; /* LH1 */ ++ ++ if (q1->HH1 < q2->HH1) ++ return FALSE; + dst->HH1 = q1->HH1 - q2->HH1; /* HH1 */ ++ ++ if (q1->HL2 < q2->HL2) ++ return FALSE; + dst->HL2 = q1->HL2 - q2->HL2; /* HL2 */ ++ ++ if (q1->LH2 < q2->LH2) ++ return FALSE; + dst->LH2 = q1->LH2 - q2->LH2; /* LH2 */ ++ ++ if (q1->HH2 < q2->HH2) ++ return FALSE; + dst->HH2 = q1->HH2 - q2->HH2; /* HH2 */ ++ ++ if (q1->HL3 < q2->HL3) ++ return FALSE; + dst->HL3 = q1->HL3 - q2->HL3; /* HL3 */ ++ ++ if (q1->LH3 < q2->LH3) ++ return FALSE; + dst->LH3 = q1->LH3 - q2->LH3; /* LH3 */ ++ ++ if (q1->HH3 < q2->HH3) ++ return FALSE; + dst->HH3 = q1->HH3 - q2->HH3; /* HH3 */ ++ ++ if (q1->LL3 < q2->LL3) ++ return FALSE; + dst->LL3 = q1->LL3 - q2->LL3; /* LL3 */ ++ ++ return TRUE; + } + + static INLINE BOOL +@@ -1360,9 +1392,12 @@ progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* WINPR_RESTRICT progress + progressive_rfx_quant_add(quantY, quantProgY, &yBitPos); + progressive_rfx_quant_add(quantCb, quantProgCb, &cbBitPos); + progressive_rfx_quant_add(quantCr, quantProgCr, &crBitPos); +- progressive_rfx_quant_sub(&(tile->yBitPos), &yBitPos, &yNumBits); +- progressive_rfx_quant_sub(&(tile->cbBitPos), &cbBitPos, &cbNumBits); +- progressive_rfx_quant_sub(&(tile->crBitPos), &crBitPos, &crNumBits); ++ if (!progressive_rfx_quant_sub(&(tile->yBitPos), &yBitPos, &yNumBits)) ++ goto fail; ++ if (!progressive_rfx_quant_sub(&(tile->cbBitPos), &cbBitPos, &cbNumBits)) ++ goto fail; ++ if (!progressive_rfx_quant_sub(&(tile->crBitPos), &crBitPos, &crNumBits)) ++ goto fail; + progressive_rfx_quant_add(quantY, quantProgY, &shiftY); + progressive_rfx_quant_lsub(&shiftY, 1); /* -6 + 5 = -1 */ + progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch freerdp3-3.15.0+dfsg/debian/patches/core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch --- freerdp3-3.15.0+dfsg/debian/patches/core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,37 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 09:04:43 +0100 +Subject: [core,gateway] Check rpcconn_common_hdr_t::auth_length is valid +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/4ac0b6467d371a1ad47c1f751c5b305e4c068adb +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4v4p-9v5x-hc93 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33952 +Comment: mjt: backport to debian trixie version + +Do sanity checks for rpcconn_common_hdr_t::auth_length read from +network, abort if the value is out of range. +--- + libfreerdp/core/gateway/rts.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c +--- a/libfreerdp/core/gateway/rts.c ++++ b/libfreerdp/core/gateway/rts.c +@@ -254,6 +254,15 @@ BOOL rts_read_common_pdu_header(wStream* s, rpcconn_common_hdr_t* header, BOOL i + header->frag_length, sizeof(rpcconn_common_hdr_t)); + return FALSE; + } ++ if (header->auth_length > header->frag_length - 8ull) ++ { ++ if (!ignoreErrors) ++ WLog_WARN(TAG, ++ "Invalid header->auth_length(%" PRIu16 ") > header->frag_length(%" PRIu16 ++ ") - 8ull", ++ header->frag_length, header->auth_length); ++ return FALSE; ++ } + + if (!ignoreErrors) + { +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/core-order-fix-const-correctness.patch freerdp3-3.15.0+dfsg/debian/patches/core-order-fix-const-correctness.patch --- freerdp3-3.15.0+dfsg/debian/patches/core-order-fix-const-correctness.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/core-order-fix-const-correctness.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,33 @@ +From: Armin Novak +Date: Wed, 23 Apr 2025 10:08:58 +0200 +Subject: [core,order] fix const correctness +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/b8f5b9c719c269010caf6dbd5929cef684e154b4 +Forwarded: not-needed +Comment: preparation for CVE-2026-29776 fix + + +diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c +index 3085765ec..c27b474ae 100644 +--- a/libfreerdp/core/orders.c ++++ b/libfreerdp/core/orders.c +@@ -268,7 +268,7 @@ static BYTE get_bpp_bmf(UINT32 bpp, BOOL* pValid) + } + } + +-static BOOL check_order_activated(wLog* log, rdpSettings* settings, const char* orderName, ++static BOOL check_order_activated(wLog* log, const rdpSettings* settings, const char* orderName, + BOOL condition, const char* extendedMessage) + { + if (!condition) +@@ -407,7 +407,7 @@ static BOOL check_secondary_order_supported(wLog* log, rdpSettings* settings, BY + return check_order_activated(log, settings, orderName, condition, extendedMessage); + } + +-static BOOL check_primary_order_supported(wLog* log, rdpSettings* settings, UINT32 orderType, ++static BOOL check_primary_order_supported(wLog* log, const rdpSettings* settings, UINT32 orderType, + const char* orderName) + { + const char* extendedMessage = NULL; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/core-orders-improve-input-validation-CVE-2026-29776.patch freerdp3-3.15.0+dfsg/debian/patches/core-orders-improve-input-validation-CVE-2026-29776.patch --- freerdp3-3.15.0+dfsg/debian/patches/core-orders-improve-input-validation-CVE-2026-29776.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/core-orders-improve-input-validation-CVE-2026-29776.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,30 @@ +From: Armin Novak +Date: Tue, 3 Mar 2026 13:58:09 +0100 +Subject: [core,orders] improve input validation +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/a9e0abf2eac8c2e370fa155bf1abb9d044c0ca8a +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-c747-x4wf-cqrr +Bug: https://security-tracker.debian.org/tracker/CVE-2026-29776 + +check length before subtracting. Might underflow and be cought by the +next check, but lets be strict. +--- + libfreerdp/core/orders.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c +index 3085765ec..7e7e510ac 100644 +--- a/libfreerdp/core/orders.c ++++ b/libfreerdp/core/orders.c +@@ -2371,6 +2371,8 @@ static CACHE_BITMAP_ORDER* update_read_cache_bitmap_order(rdpUpdate* update, wSt + goto fail; + + Stream_Read(s, bitmapComprHdr, 8); /* bitmapComprHdr (8 bytes) */ ++ if (cache_bitmap->bitmapLength < 8) ++ goto fail; + cache_bitmap->bitmapLength -= 8; + } + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/series freerdp3-3.15.0+dfsg/debian/patches/series --- freerdp3-3.15.0+dfsg/debian/patches/series 2026-02-25 20:34:19.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/series 2026-04-03 15:45:10.000000000 +0000 @@ -78,3 +78,25 @@ codec-clear-fix-missing-destination-boundary-checks-CVE-2026-26955.patch codec-clear-fix-destination-checks-CVE-2026-26955.patch codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch +# 3.24.0: +codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch +cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch +core-order-fix-const-correctness.patch +core-orders-improve-input-validation-CVE-2026-29776.patch +codec-nsc-bounds-checks-and-doxygen.patch +codec-nsc-log-decoder-function-parameter-issues.patch +codec-nsc-fix-use-of-nsc_process_message.patch +codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch +codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch +codec-dsp-add-format-checks-CVE-2026-31884.patch +codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch +# 3.24.2: +core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch +codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch +winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch +codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch +codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch +codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch +codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch +cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch +cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch diff -Nru freerdp3-3.15.0+dfsg/debian/patches/winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch freerdp3-3.15.0+dfsg/debian/patches/winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch --- freerdp3-3.15.0+dfsg/debian/patches/winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch 2026-04-03 15:45:10.000000000 +0000 @@ -0,0 +1,159 @@ +From: Armin Novak +Date: Wed, 25 Mar 2026 14:00:28 +0100 +Subject: [winpr,sspi] Fix context nullptr handling +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/8078b8af1359055972e4fb2f509f543b69169391 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-mv25-f4p2-5mxx +Bug: https://security-tracker.debian.org/tracker/CVE-2026-33995 +Comment: mjt: backport to debian trixie version + +Unify reset of PCredHandle and PCtxtHandle in all +DeleteSecurityContext and FreeCredentialsHandle implementations. + +--- + winpr/libwinpr/sspi/CredSSP/credssp.c | 7 +++---- + winpr/libwinpr/sspi/Kerberos/kerberos.c | 5 ++++- + winpr/libwinpr/sspi/NTLM/ntlm.c | 3 ++- + winpr/libwinpr/sspi/Negotiate/negotiate.c | 7 ++++--- + winpr/libwinpr/sspi/Schannel/schannel.c | 11 +++++------ + 5 files changed, 18 insertions(+), 15 deletions(-) + +diff --git a/winpr/libwinpr/sspi/CredSSP/credssp.c b/winpr/libwinpr/sspi/CredSSP/credssp.c +--- a/winpr/libwinpr/sspi/CredSSP/credssp.c ++++ b/winpr/libwinpr/sspi/CredSSP/credssp.c +@@ -194,13 +194,12 @@ static SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA( + + static SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential) + { +- SSPI_CREDENTIALS* credentials = NULL; +- + if (!phCredential) + return SEC_E_INVALID_HANDLE; + +- credentials = (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential); +- ++ SSPI_CREDENTIALS* credentials = ++ (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential); ++ sspi_SecureHandleInvalidate(phCredential); + if (!credentials) + return SEC_E_INVALID_HANDLE; + +diff --git a/winpr/libwinpr/sspi/Kerberos/kerberos.c b/winpr/libwinpr/sspi/Kerberos/kerberos.c +--- a/winpr/libwinpr/sspi/Kerberos/kerberos.c ++++ b/winpr/libwinpr/sspi/Kerberos/kerberos.c +@@ -540,12 +540,12 @@ static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle(PCredHandle phCr + { + #ifdef WITH_KRB5 + KRB_CREDENTIALS* credentials = sspi_SecureHandleGetLowerPointer(phCredential); ++ sspi_SecureHandleInvalidate(phCredential); + if (!credentials) + return SEC_E_INVALID_HANDLE; + + credentials_unref(credentials); + +- sspi_SecureHandleInvalidate(phCredential); + return SEC_E_OK; + #else + return SEC_E_UNSUPPORTED_FUNCTION; +@@ -1212,6 +1212,7 @@ cleanup: + break; + default: + kerberos_ContextFree(context, TRUE); ++ sspi_SecureHandleInvalidate(phNewContext); + break; + } + } +@@ -1501,6 +1502,7 @@ cleanup: + break; + default: + kerberos_ContextFree(context, TRUE); ++ sspi_SecureHandleInvalidate(phNewContext); + break; + } + } +@@ -1550,6 +1552,7 @@ static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(PCtxtHandle phCo + { + #ifdef WITH_KRB5 + KRB_CONTEXT* context = get_context(phContext); ++ sspi_SecureHandleInvalidate(phContext); + if (!context) + return SEC_E_INVALID_HANDLE; + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c +--- a/winpr/libwinpr/sspi/NTLM/ntlm.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c +@@ -450,7 +450,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCreden + + SSPI_CREDENTIALS* credentials = + (SSPI_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential); +- ++ sspi_SecureHandleInvalidate(phCredential); + if (!credentials) + return SEC_E_INVALID_HANDLE; + +@@ -761,6 +761,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( + static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext) + { + NTLM_CONTEXT* context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); ++ sspi_SecureHandleInvalidate(phContext); + ntlm_ContextFree(context); + return SEC_E_OK; + } +diff --git a/winpr/libwinpr/sspi/Negotiate/negotiate.c b/winpr/libwinpr/sspi/Negotiate/negotiate.c +--- a/winpr/libwinpr/sspi/Negotiate/negotiate.c ++++ b/winpr/libwinpr/sspi/Negotiate/negotiate.c +@@ -1224,10 +1224,10 @@ static SECURITY_STATUS SEC_ENTRY negotiate_CompleteAuthToken(PCtxtHandle phConte + + static SECURITY_STATUS SEC_ENTRY negotiate_DeleteSecurityContext(PCtxtHandle phContext) + { +- NEGOTIATE_CONTEXT* context = NULL; + SECURITY_STATUS status = SEC_E_OK; +- context = (NEGOTIATE_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); ++ NEGOTIATE_CONTEXT* context = (NEGOTIATE_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); ++ sspi_SecureHandleInvalidate(phContext); + const SecPkg* pkg = NULL; + + if (!context) + return SEC_E_INVALID_HANDLE; +@@ -1507,6 +1507,7 @@ static SECURITY_STATUS SEC_ENTRY negotiate_FreeCredentialsHandle(PCredHandle phC + MechCred* creds = NULL; + + creds = sspi_SecureHandleGetLowerPointer(phCredential); ++ sspi_SecureHandleInvalidate(phCredential); + if (!creds) + return SEC_E_INVALID_HANDLE; + +diff --git a/winpr/libwinpr/sspi/Schannel/schannel.c b/winpr/libwinpr/sspi/Schannel/schannel.c +--- a/winpr/libwinpr/sspi/Schannel/schannel.c ++++ b/winpr/libwinpr/sspi/Schannel/schannel.c +@@ -183,13 +183,12 @@ static SECURITY_STATUS SEC_ENTRY schannel_AcquireCredentialsHandleA( + + static SECURITY_STATUS SEC_ENTRY schannel_FreeCredentialsHandle(PCredHandle phCredential) + { +- SCHANNEL_CREDENTIALS* credentials = NULL; +- + if (!phCredential) + return SEC_E_INVALID_HANDLE; + +- credentials = (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential); +- ++ SCHANNEL_CREDENTIALS* credentials = ++ (SCHANNEL_CREDENTIALS*)sspi_SecureHandleGetLowerPointer(phCredential); ++ sspi_SecureHandleInvalidate(phCredential); + if (!credentials) + return SEC_E_INVALID_HANDLE; + +@@ -289,8 +288,8 @@ static SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext( + + static SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext) + { +- SCHANNEL_CONTEXT* context = NULL; +- context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); ++ SCHANNEL_CONTEXT* context = (SCHANNEL_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); ++ sspi_SecureHandleInvalidate(phContext); + + if (!context) + return SEC_E_INVALID_HANDLE; +-- +2.47.3 +