Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:freerdp3
User: [email protected]
Usertags: pu
[ Reason ]
Compared with the version currently being reviewed for trixie-pu,
there are a number of new security fixes in freerdp3 package, all
taken from the upstream, namely:
* security fixes for client from 3.24.0:
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
CVE-2026-29775 Heap-buffer-overflow in bitmap_cache_put via OOB cacheId
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-h666-rfw3-jhvj
CVE-2026-29776 Integer Underflow in update_read_cache_bitmap_order
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-c747-x4wf-cqrr
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
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
CVE-2026-31884 Division-by-zero in ADPCM decoders when `nBlockAlign` is 0
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-jp7m-94ww-p56r
CVE-2026-31897 Out-of-bounds read in `freerdp_bitmap_decompress_planar`
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-xgv6-r22m-7c9x
* security fixes for client from 3.24.2:
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
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
CVE-2026-33995 double free in kerberos_AcceptSecurityContext
and kerberos_IntitalizeSecurityContextA
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-mv25-f4p2-5mxx
CVE-2026-33984 ClearCodec resize_vbar_entry() Heap OOB Write
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8469-2xcx-frf6
CVE-2026-33983 Progressive Codec Quant BYTE Underflow - UB + CPU DoS
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4gfm-4p52-h478
CVE-2026-33985 ClearCodec Glyph Cache Count Desync - Heap OOB Read
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-x6gr-8p7h-5h85
CVE-2026-33986 H.264 YUV Buffer Dimension Desync - Heap OOB Write
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-h6qw-wxvm-hf97
CVE-2026-33987 Persistent Cache bmpSize Desync - Heap OOB Write
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-ff8h-p5vc-wcwc
CVE-2026-33982 Persistent Cache Allocator Mismatch - Heap OOB Read
https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8jm9-2925-g4v2
All these are relatively minor, but they're security issues anyway
and requires fixing.
[ Tests ]
I did run the resulting binaries (xfreerdp3 & sdl-freerdp3) to connect to
our RDP servers (and this initially revealed an additional issue which I
fixed by picking up a few more changes from the upstream). The result works
fine. I didn't try more aggressive testing though. The result passes all
upstream testing too.
[ Risks ]
The update is large, touching many areas in the codebase, I had to back-port
many changes from current upstream version to the trixie version of freerdp3
package. So there is a risk to break something.
This is why it'd be nice to have this release in trixie-proposed-updates
for a while.
[ Checklist ]
[x] *all* changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in (old)stable
[x] the issue is verified as fixed in unstable
[ Changes ]
The changelog entry explain every change in detail.
Thanks,
/mjt
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 20:59:33.000000000
+0300
+++ freerdp3-3.15.0+dfsg/debian/changelog 2026-04-03 18:45:10.000000000
+0300
@@ -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 <[email protected]> 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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/cache-bitmap-overallocate-bitmap-cache-CVE-2026-29775.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,31 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/cache-persist-use-winpr_aligned_calloc-CVE-2026-33982.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,46 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/cache-persistent-update-PERSISTENT_CACHE_ENTRY-size--CVE-2026-33987.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,52 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-clear-Update-CLEAR_GLYPH_ENTRY-count-after-all-CVE-2026-33985.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,56 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-clear-update-CLEAR_VBAR_ENTRY-size-after-alloc-CVE-2026-33984.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,34 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-add-format-checks-CVE-2026-31884.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,274 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-IMA-ADPCM-sample-clamping-CVE-2026-33977.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,79 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-dsp-fix-array-bounds-checks-CVE-2026-31883-CVE-2026-31885.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,224 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-h264-update-H264_CONTEXT-width-height-after-al-CVE-2026-33986.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,39 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-h264-validate-rectangles-before-use-CVE-2026-29774.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,78 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-bounds-checks-and-doxygen.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,86 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-fix-use-of-nsc_process_message.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,93 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-limit-copy-area-in-nsc_process_message-CVE-2026-31806.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,38 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-nsc-log-decoder-function-parameter-issues.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,54 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-planar-add-early-length-check-to-avoid-oob-rea-CVE-2026-31897.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,32 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/codec-progressive-Fail-progressive_rfx_quant_sub-on--CVE-2026-33983.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,88 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/core-gateway-Check-rpcconn_common_hdr_t-auth_length--CVE-2026-33952.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,37 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++ freerdp3-3.15.0+dfsg/debian/patches/core-order-fix-const-correctness.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,33 @@
+From: Armin Novak <[email protected]>
+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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/core-orders-improve-input-validation-CVE-2026-29776.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,30 @@
+From: Armin Novak <[email protected]>
+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-03-28 20:59:33.000000000
+0300
+++ freerdp3-3.15.0+dfsg/debian/patches/series 2026-04-03 18:45:10.000000000
+0300
@@ -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 03:00:00.000000000 +0300
+++
freerdp3-3.15.0+dfsg/debian/patches/winpr-sspi-Fix-context-nullptr-handling-CVE-2026-33995.patch
2026-04-03 18:45:10.000000000 +0300
@@ -0,0 +1,159 @@
+From: Armin Novak <[email protected]>
+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
+