From 1d7477b5a5db0cfef482ce43a7752df9feaf67a4 Mon Sep 17 00:00:00 2001
From: matt335672 <30179339+matt335672@users.noreply.github.com>
Date: Thu, 11 Jun 2026 16:32:06 +0100
Subject: [PATCH] CVE-2026-55238: Possible OOB reads in capability processing

Add missing per-capability length checks in the RDP Confirm Active PDU
parser, and abort the parser if a buffer length violation is discovered.

(cherry picked from commit 4aa8bdf1eac3aab7e166393913019edf9616008c)
---
 libxrdp/xrdp_caps.c | 132 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 108 insertions(+), 24 deletions(-)

--- a/libxrdp/xrdp_caps.c
+++ b/libxrdp/xrdp_caps.c
@@ -373,6 +373,11 @@ xrdp_caps_process_input(struct xrdp_rdp
     int inputFlags;
     int client_does_fastpath_input;
 
+    if (len < 2)
+    {
+        LOG(LOG_LEVEL_ERROR, "xrdp_caps_process_input: missing data");
+        return 1;
+    }
     in_uint16_le(s, inputFlags);
     client_does_fastpath_input = (inputFlags & INPUT_FLAG_FASTPATH_INPUT) ||
                                  (inputFlags & INPUT_FLAG_FASTPATH_INPUT2);
@@ -613,6 +618,11 @@ xrdp_caps_process_multifragmentupdate(st
 {
     int MaxRequestSize;
 
+    if (len < 4)
+    {
+        LOG(LOG_LEVEL_ERROR, "xrdp_caps_process_multifragmentupdate: missing data");
+        return 1;
+    }
     in_uint32_le(s, MaxRequestSize);
     if (self->client_info.use_fast_path & 1)
     {
@@ -625,16 +635,25 @@ xrdp_caps_process_multifragmentupdate(st
 static int
 xrdp_caps_process_frame_ack(struct xrdp_rdp *self, struct stream *s, int len)
 {
+    int max_count;
     LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_process_frame_ack:");
-    self->client_info.use_frame_acks = 1;
-    in_uint32_le(s, self->client_info.max_unacknowledged_frame_count);
-    if (self->client_info.max_unacknowledged_frame_count < 0)
+    if (len < 4)
     {
-        LOG(LOG_LEVEL_WARNING, "  invalid max_unacknowledged_frame_count value (%d), setting to 0",
-            self->client_info.max_unacknowledged_frame_count);
-        self->client_info.max_unacknowledged_frame_count = 0;
+        LOG(LOG_LEVEL_ERROR, "xrdp_caps_process_frame_ack: missing data");
+        return 1;
     }
-    LOG_DEVEL(LOG_LEVEL_TRACE, "  max_unacknowledged_frame_count %d", self->client_info.max_unacknowledged_frame_count);
+    self->client_info.use_frame_acks = 1;
+    in_uint32_le(s, max_count);
+    if (max_count < 0)
+    {
+        LOG(LOG_LEVEL_WARNING,
+            "  invalid max_unacknowledged_frame_count value (%d), setting to 0",
+            max_count);
+        max_count = 0;
+    }
+    LOG_DEVEL(LOG_LEVEL_TRACE,
+              "  max_unacknowledged_frame_count %d", max_count);
+    self->client_info.max_unacknowledged_frame_count = max_count;
     return 0;
 }
 
@@ -648,6 +667,12 @@ xrdp_caps_process_surface_cmds(struct xr
     logging in debug mode */
     UNUSED_VAR(cmdFlags);
 #endif
+    // Check the data is there, whether or not we are logging it
+    if (len < 8)
+    {
+        LOG(LOG_LEVEL_ERROR, "xrdp_caps_process_surface_cmds: missing data");
+        return 1;
+    }
 
     LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_process_surface_cmds:");
     in_uint32_le(s, cmdFlags);
@@ -735,7 +760,10 @@ xrdp_caps_process_confirm_active(struct
             case CAPSTYPE_GENERAL:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_GENERAL");
-                xrdp_caps_process_general(self, s, len);
+                if (xrdp_caps_process_general(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_BITMAP:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
@@ -744,12 +772,18 @@ xrdp_caps_process_confirm_active(struct
             case CAPSTYPE_ORDER:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_ORDER");
-                xrdp_caps_process_order(self, s, len);
+                if (xrdp_caps_process_order(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_BITMAPCACHE:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_BITMAPCACHE");
-                xrdp_caps_process_bmpcache(self, s, len);
+                if (xrdp_caps_process_bmpcache(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_CONTROL:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
@@ -758,7 +792,10 @@ xrdp_caps_process_confirm_active(struct
             case 6:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = 6");
-                xrdp_caps_process_cache_v3_codec_id(self, s, len);
+                if (xrdp_caps_process_cache_v3_codec_id(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_ACTIVATION:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
@@ -767,7 +804,10 @@ xrdp_caps_process_confirm_active(struct
             case CAPSTYPE_POINTER:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_POINTER");
-                xrdp_caps_process_pointer(self, s, len);
+                if (xrdp_caps_process_pointer(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_SHARE:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
@@ -784,7 +824,10 @@ xrdp_caps_process_confirm_active(struct
             case CAPSTYPE_INPUT:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_INPUT");
-                xrdp_caps_process_input(self, s, len);
+                if (xrdp_caps_process_input(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_FONT:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
@@ -793,22 +836,34 @@ xrdp_caps_process_confirm_active(struct
             case CAPSTYPE_BRUSH:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_BRUSH");
-                xrdp_caps_process_brushcache(self, s, len);
+                if (xrdp_caps_process_brushcache(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_GLYPHCACHE:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_GLYPHCACHE");
-                xrdp_caps_process_glyphcache(self, s, len);
+                if (xrdp_caps_process_glyphcache(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_OFFSCREENCACHE:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_OFFSCREENCACHE");
-                xrdp_caps_process_offscreen_bmpcache(self, s, len);
+                if (xrdp_caps_process_offscreen_bmpcache(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_BITMAPCACHE_REV2:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_BITMAPCACHE_REV2");
-                xrdp_caps_process_bmpcache2(self, s, len);
+                if (xrdp_caps_process_bmpcache2(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_VIRTUALCHANNEL:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
@@ -825,32 +880,50 @@ xrdp_caps_process_confirm_active(struct
             case CAPSTYPE_RAIL:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_RAIL");
-                xrdp_caps_process_rail(self, s, len);
+                if (xrdp_caps_process_rail(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_WINDOW:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_WINDOW");
-                xrdp_caps_process_window(self, s, len);
+                if (xrdp_caps_process_window(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSSETTYPE_MULTIFRAGMENTUPDATE:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSSETTYPE_MULTIFRAGMENTUPDATE");
-                xrdp_caps_process_multifragmentupdate(self, s, len);
+                if (xrdp_caps_process_multifragmentupdate(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSETTYPE_SURFACE_COMMANDS:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSETTYPE_SURFACE_COMMANDS");
-                xrdp_caps_process_surface_cmds(self, s, len);
+                if (xrdp_caps_process_surface_cmds(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSSETTYPE_BITMAP_CODECS:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSSETTYPE_BITMAP_CODECS");
-                xrdp_caps_process_codecs(self, s, len);
+                if (xrdp_caps_process_codecs(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             case CAPSTYPE_FRAME_ACKNOWLEDGE:
                 LOG_DEVEL(LOG_LEVEL_INFO, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
                           "capabilitySetType = CAPSTYPE_FRAME_ACKNOWLEDGE");
-                xrdp_caps_process_frame_ack(self, s, len);
+                if (xrdp_caps_process_frame_ack(self, s, len) != 0)
+                {
+                    return 1;
+                }
                 break;
             default:
                 LOG(LOG_LEVEL_WARNING, "Received [MS-RDPBCGR] TS_CONFIRM_ACTIVE_PDU - TS_CAPS_SET "
