From e593f58a82bf79b556601ae08e9e25e366a662fb Mon Sep 17 00:00:00 2001
From: matt335672 <30179339+matt335672@users.noreply.github.com>
Date: Fri, 12 Jun 2020 09:56:47 +0100
Subject: [PATCH] Fix for CVE-2020-4044

Reported by: Ashley Newson
---
 sesman/libscp/libscp_types.h   |   4 +
 sesman/libscp/libscp_v0.c      | 335 ++++++++++++++++++++------------
 sesman/libscp/libscp_v1s.c     | 336 +++++++++++++++++++++++----------
 sesman/libscp/libscp_v1s_mng.c | 164 +++++++++++++---
 sesman/scp.c                   |  12 +-
 5 files changed, 592 insertions(+), 259 deletions(-)

Index: xrdp-0.9.6/sesman/libscp/libscp_types.h
===================================================================
--- xrdp-0.9.6.orig/sesman/libscp/libscp_types.h
+++ xrdp-0.9.6/sesman/libscp/libscp_types.h
@@ -59,6 +59,10 @@
 
 #include "libscp_types_mng.h"
 
+/* Max server incoming and outgoing message size, used to stop memory
+   exhaustion attempts (CVE-2020-4044) */
+#define SCP_MAX_MESSAGE_SIZE 8192
+
 struct SCP_CONNECTION
 {
   int in_sck;
Index: xrdp-0.9.6/sesman/libscp/libscp_v0.c
===================================================================
--- xrdp-0.9.6.orig/sesman/libscp/libscp_v0.c
+++ xrdp-0.9.6/sesman/libscp/libscp_v0.c
@@ -34,6 +34,65 @@
 
 extern struct log_config *s_log;
 
+/** Maximum length of a string (two bytes + len), excluding the terminator
+ *
+ * Practially this is limited by [MS-RDPBCGR] TS_INFO_PACKET
+ * */
+#define STRING16_MAX_LEN 512
+
+/**
+ * Reads a big-endian uint16 followed by a string into a buffer
+ *
+ * Buffer is null-terminated on success
+ *
+ * @param s Input stream
+ * @param [out] Output buffer (must be >= (STRING16_MAX_LEN+1) chars)
+ * @param param Parameter we're reading
+ * @param line Line number reference
+ * @return != 0 if string read OK
+ */
+static
+int in_string16(struct stream *s, char str[], const char *param, int line)
+{
+    int result;
+
+    if (!s_check_rem(s, 2))
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v0:%d] connection aborted: %s len missing",
+                    line, param);
+        result = 0;
+    }
+    else
+    {
+        unsigned int sz;
+
+        in_uint16_be(s, sz);
+        if (sz > STRING16_MAX_LEN)
+        {
+            log_message(LOG_LEVEL_WARNING,
+                        "[v0:%d] connection aborted: %s too long (%u chars)",
+                        line, param, sz);
+            result = 0;
+        }
+        else
+        {
+            result = s_check_rem(s, sz);
+            if (!result)
+            {
+                log_message(LOG_LEVEL_WARNING,
+                            "[v0:%d] connection aborted: %s data missing",
+                            line, param);
+            }
+            else
+            {
+                in_uint8a(s, str, sz);
+                str[sz] = '\0';
+            }
+        }
+    }
+    return result;
+}
 /* client API */
 /******************************************************************************/
 enum SCP_CLIENT_STATES_E
@@ -71,10 +130,24 @@ scp_v0c_connect(struct SCP_CONNECTION *c
     }
 
     sz = g_strlen(s->username);
+    if (sz > STRING16_MAX_LEN)
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v0:%d] connection aborted: username too long",
+                    __LINE__);
+        return SCP_CLIENT_STATE_SIZE_ERR;
+    }
     out_uint16_be(c->out_s, sz);
     out_uint8a(c->out_s, s->username, sz);
 
     sz = g_strlen(s->password);
+    if (sz > STRING16_MAX_LEN)
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v0:%d] connection aborted: password too long",
+                    __LINE__);
+        return SCP_CLIENT_STATE_SIZE_ERR;
+    }
     out_uint16_be(c->out_s, sz);
     out_uint8a(c->out_s, s->password, sz);
     out_uint16_be(c->out_s, s->width);
@@ -111,14 +184,16 @@ scp_v0c_connect(struct SCP_CONNECTION *c
 
     in_uint32_be(c->in_s, size);
 
-    if (size < 14)
+    if (size < (8 + 2 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
     {
-        log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: packet size error", __LINE__);
+        log_message(LOG_LEVEL_WARNING,
+                    "[v0:%d] connection aborted: msg size = %u",
+                    __LINE__, (unsigned int)size);
         return SCP_CLIENT_STATE_SIZE_ERR;
     }
 
     /* getting payload */
-    init_stream(c->in_s, c->in_s->size);
+    init_stream(c->in_s, size - 8);
 
     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8))
     {
@@ -126,6 +201,8 @@ scp_v0c_connect(struct SCP_CONNECTION *c
         return SCP_CLIENT_STATE_NETWORK_ERR;
     }
 
+    c->in_s->end = c->in_s->data + (size - 8);
+
     /* check code */
     in_uint16_be(c->in_s, sz);
 
@@ -151,43 +228,38 @@ scp_v0c_connect(struct SCP_CONNECTION *c
     return SCP_CLIENT_STATE_END;
 }
 
-/* server API */
-/******************************************************************************/
-enum SCP_SERVER_STATES_E
-scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
+/**
+ * Initialises a V0 session object
+ *
+ * At the time of the call, the version has been read from the connection
+ *
+ * @param c Connection
+ * @param [out] session pre-allocated session object
+ * @return SCP_SERVER_STATE_OK for success
+ */
+static enum SCP_SERVER_STATES_E
+scp_v0s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session)
 {
-    tui32 version = 0;
     tui32 size;
-    struct SCP_SESSION *session = 0;
-    tui16 sz;
+    tui16 height;
+    tui16 width;
+    tui16 bpp;
     tui32 code = 0;
-    char *buf = 0;
+    char buf[STRING16_MAX_LEN + 1];
 
-    if (!skipVchk)
-    {
-        LOG_DBG("[v0:%d] starting connection", __LINE__);
-
-        if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
-        {
-            c->in_s->end = c->in_s->data + 8;
-            in_uint32_be(c->in_s, version);
-
-            if (version != 0)
-            {
-                log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__);
-                return SCP_SERVER_STATE_VERSION_ERR;
-            }
-        }
-        else
-        {
-            log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
-            return SCP_SERVER_STATE_NETWORK_ERR;
-        }
-    }
+    scp_session_set_version(session, 0);
 
+    /* Check for a header and a code value in the length */
     in_uint32_be(c->in_s, size);
+    if (size < (8 + 2) || size > SCP_MAX_MESSAGE_SIZE)
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v0:%d] connection aborted: msg size = %u",
+                    __LINE__, (unsigned int)size);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
-    init_stream(c->in_s, 8196);
+    init_stream(c->in_s, size - 8);
 
     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8))
     {
@@ -201,16 +273,6 @@ scp_v0s_accept(struct SCP_CONNECTION *c,
 
     if (code == 0 || code == 10 || code == 20)
     {
-        session = scp_session_create();
-
-        if (0 == session)
-        {
-            log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
-            return SCP_SERVER_STATE_INTERNAL_ERR;
-        }
-
-        scp_session_set_version(session, version);
-
         if (code == 0)
         {
             scp_session_set_type(session, SCP_SESSION_TYPE_XVNC);
@@ -225,154 +287,130 @@ scp_v0s_accept(struct SCP_CONNECTION *c,
         }
 
         /* reading username */
-        in_uint16_be(c->in_s, sz);
-        buf = g_new0(char, sz + 1);
-        in_uint8a(c->in_s, buf, sz);
-        buf[sz] = '\0';
+        if (!in_string16(c->in_s, buf, "username", __LINE__))
+        {
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
         if (0 != scp_session_set_username(session, buf))
         {
-            scp_session_destroy(session);
             log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting username", __LINE__);
-            g_free(buf);
             return SCP_SERVER_STATE_INTERNAL_ERR;
         }
-        g_free(buf);
 
         /* reading password */
-        in_uint16_be(c->in_s, sz);
-        buf = g_new0(char, sz + 1);
-        in_uint8a(c->in_s, buf, sz);
-        buf[sz] = '\0';
+        if (!in_string16(c->in_s, buf, "passwd", __LINE__))
+        {
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
         if (0 != scp_session_set_password(session, buf))
         {
-            scp_session_destroy(session);
             log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__);
-            g_free(buf);
             return SCP_SERVER_STATE_INTERNAL_ERR;
         }
-        g_free(buf);
 
-        /* width */
-        in_uint16_be(c->in_s, sz);
-        scp_session_set_width(session, sz);
-        /* height */
-        in_uint16_be(c->in_s, sz);
-        scp_session_set_height(session, sz);
-        /* bpp */
-        in_uint16_be(c->in_s, sz);
-        if (0 != scp_session_set_bpp(session, (tui8)sz))
+        /* width  + height + bpp */
+        if (!s_check_rem(c->in_s, 2 + 2 + 2))
+        {
+            log_message(LOG_LEVEL_WARNING,
+                        "[v0:%d] connection aborted: width+height+bpp missing",
+                        __LINE__);
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
+        in_uint16_be(c->in_s, width);
+        scp_session_set_width(session, width);
+        in_uint16_be(c->in_s, height);
+        scp_session_set_height(session, height);
+        in_uint16_be(c->in_s, bpp);
+        if (0 != scp_session_set_bpp(session, (tui8)bpp))
         {
-            scp_session_destroy(session);
             log_message(LOG_LEVEL_WARNING,
                         "[v0:%d] connection aborted: unsupported bpp: %d",
-                        __LINE__, (tui8)sz);
+                        __LINE__, (tui8)bpp);
             return SCP_SERVER_STATE_INTERNAL_ERR;
         }
 
         if (s_check_rem(c->in_s, 2))
         {
             /* reading domain */
-            in_uint16_be(c->in_s, sz);
-
-            if (sz > 0)
+            if (!in_string16(c->in_s, buf, "domain", __LINE__))
+            {
+                return SCP_SERVER_STATE_SIZE_ERR;
+            }
+            if (buf[0] != '\0')
             {
-                buf = g_new0(char, sz + 1);
-                in_uint8a(c->in_s, buf, sz);
-                buf[sz] = '\0';
                 scp_session_set_domain(session, buf);
-                g_free(buf);
             }
         }
 
         if (s_check_rem(c->in_s, 2))
         {
             /* reading program */
-            in_uint16_be(c->in_s, sz);
+            if (!in_string16(c->in_s, buf, "program", __LINE__))
+            {
+                return SCP_SERVER_STATE_SIZE_ERR;
+            }
 
-            if (sz > 0)
+            if (buf[0] != '\0')
             {
-                buf = g_new0(char, sz + 1);
-                in_uint8a(c->in_s, buf, sz);
-                buf[sz] = '\0';
                 scp_session_set_program(session, buf);
-                g_free(buf);
             }
         }
 
         if (s_check_rem(c->in_s, 2))
         {
             /* reading directory */
-            in_uint16_be(c->in_s, sz);
+            if (!in_string16(c->in_s, buf, "directory", __LINE__))
+            {
+                return SCP_SERVER_STATE_SIZE_ERR;
+            }
 
-            if (sz > 0)
+            if (buf[0] != '\0')
             {
-                buf = g_new0(char, sz + 1);
-                in_uint8a(c->in_s, buf, sz);
-                buf[sz] = '\0';
                 scp_session_set_directory(session, buf);
-                g_free(buf);
             }
         }
 
         if (s_check_rem(c->in_s, 2))
         {
             /* reading client IP address */
-            in_uint16_be(c->in_s, sz);
-
-            if (sz > 0)
+            if (!in_string16(c->in_s, buf, "client IP", __LINE__))
+            {
+                return SCP_SERVER_STATE_SIZE_ERR;
+            }
+            if (buf[0] != '\0')
             {
-                buf = g_new0(char, sz + 1);
-                in_uint8a(c->in_s, buf, sz);
-                buf[sz] = '\0';
                 scp_session_set_client_ip(session, buf);
-                g_free(buf);
             }
         }
     }
     else if (code == SCP_GW_AUTHENTICATION)
     {
-        /* g_writeln("Command is SCP_GW_AUTHENTICATION"); */
-        session = scp_session_create();
-
-        if (0 == session)
-        {
-            /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error",      __LINE__);*/
-            return SCP_SERVER_STATE_INTERNAL_ERR;
-        }
-
-        scp_session_set_version(session, version);
         scp_session_set_type(session, SCP_GW_AUTHENTICATION);
         /* reading username */
-        in_uint16_be(c->in_s, sz);
-        buf = g_new0(char, sz + 1);
-        in_uint8a(c->in_s, buf, sz);
-        buf[sz] = '\0';
+        if (!in_string16(c->in_s, buf, "username", __LINE__))
+        {
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
 
         /* g_writeln("Received user name: %s",buf); */
         if (0 != scp_session_set_username(session, buf))
         {
-            scp_session_destroy(session);
             /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting        username", __LINE__);*/
-            g_free(buf);
             return SCP_SERVER_STATE_INTERNAL_ERR;
         }
-        g_free(buf);
 
         /* reading password */
-        in_uint16_be(c->in_s, sz);
-        buf = g_new0(char, sz + 1);
-        in_uint8a(c->in_s, buf, sz);
-        buf[sz] = '\0';
+        if (!in_string16(c->in_s, buf, "passwd", __LINE__))
+        {
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
 
         /* g_writeln("Received password: %s",buf); */
         if (0 != scp_session_set_password(session, buf))
         {
-            scp_session_destroy(session);
             /* until syslog merge log_message(s_log, LOG_LEVEL_WARNING, "[v0:%d] connection aborted: error setting password", __LINE__); */
-            g_free(buf);
             return SCP_SERVER_STATE_INTERNAL_ERR;
         }
-        g_free(buf);
     }
     else
     {
@@ -380,10 +418,67 @@ scp_v0s_accept(struct SCP_CONNECTION *c,
         return SCP_SERVER_STATE_SEQUENCE_ERR;
     }
 
-    (*s) = session;
     return SCP_SERVER_STATE_OK;
 }
 
+
+/* server API */
+/******************************************************************************/
+enum SCP_SERVER_STATES_E
+scp_v0s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
+{
+    enum SCP_SERVER_STATES_E result = SCP_SERVER_STATE_OK;
+    struct SCP_SESSION *session = NULL;
+    tui32 version = 0;
+
+    if (!skipVchk)
+    {
+        LOG_DBG("[v0:%d] starting connection", __LINE__);
+
+        if (0 == scp_tcp_force_recv(c->in_sck, c->in_s->data, 8))
+        {
+            c->in_s->end = c->in_s->data + 8;
+            in_uint32_be(c->in_s, version);
+
+            if (version != 0)
+            {
+                log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: version error", __LINE__);
+                result = SCP_SERVER_STATE_VERSION_ERR;
+            }
+        }
+        else
+        {
+            log_message(LOG_LEVEL_WARNING, "[v0:%d] connection aborted: network error", __LINE__);
+            result = SCP_SERVER_STATE_NETWORK_ERR;
+        }
+    }
+
+    if (result == SCP_SERVER_STATE_OK)
+    {
+        session = scp_session_create();
+        if (NULL == session)
+        {
+            log_message(LOG_LEVEL_WARNING,
+                        "[v0:%d] connection aborted: no memory",
+                        __LINE__);
+            result = SCP_SERVER_STATE_INTERNAL_ERR;
+        }
+        else
+        {
+            result = scp_v0s_init_session(c, session);
+            if (result != SCP_SERVER_STATE_OK)
+            {
+                scp_session_destroy(session);
+                session = NULL;
+            }
+        }
+    }
+
+    (*s) = session;
+
+    return result;
+}
+
 /******************************************************************************/
 enum SCP_SERVER_STATES_E
 scp_v0s_allow_connection(struct SCP_CONNECTION *c, SCP_DISPLAY d, const tui8 *guid)
Index: xrdp-0.9.6/sesman/libscp/libscp_v1s.c
===================================================================
--- xrdp-0.9.6.orig/sesman/libscp/libscp_v1s.c
+++ xrdp-0.9.6/sesman/libscp/libscp_v1s.c
@@ -35,16 +35,194 @@
 
 //extern struct log_config* s_log;
 
+/**
+ * Reads a uint8 followed by a string into a buffer
+ *
+ * Buffer is null-terminated on success
+ *
+ * @param s Input stream
+ * @param [out] Output buffer (must be >= 256 chars)
+ * @param param Parameter we're reading
+ * @param line Line number reference
+ * @return != 0 if string read OK
+ *
+ * @todo
+ *     This needs to be merged with the func of the same name in
+ *     libscp_v1s_mng.c
+ */
+static
+int in_string8(struct stream *s, char str[], const char *param, int line)
+{
+    int result;
+
+    if (!s_check_rem(s, 1))
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: %s len missing",
+                    line, param);
+        result = 0;
+    }
+    else
+    {
+        unsigned int sz;
+
+        in_uint8(s, sz);
+        result = s_check_rem(s, sz);
+        if (!result)
+        {
+            log_message(LOG_LEVEL_WARNING,
+                        "[v1s:%d] connection aborted: %s data missing",
+                        line, param);
+        }
+        else
+        {
+            in_uint8a(s, str, sz);
+            str[sz] = '\0';
+        }
+    }
+    return result;
+}
+/* server API */
+
+/**
+ * Initialises a V1 session object
+ *
+ * This is called after the V1 header, command set and command have been read
+ *
+ * @param c Connection
+ * @param [out] session pre-allocated session object
+ * @return SCP_SERVER_STATE_OK for success
+ */
+static enum SCP_SERVER_STATES_E
+scp_v1s_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session)
+{
+    tui8 type;
+    tui16 height;
+    tui16 width;
+    tui8 bpp;
+    tui8 sz;
+    char buf[256];
+
+    scp_session_set_version(session, 1);
+
+    /* Check there's data for the session type, the height, the width, the
+     * bpp, the resource sharing indicator and the locale */
+    if (!s_check_rem(c->in_s, 1 + 2 + 2 + 1 + 1 + 17))
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: short packet",
+                    __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    in_uint8(c->in_s, type);
+
+    if ((type != SCP_SESSION_TYPE_XVNC) && (type != SCP_SESSION_TYPE_XRDP))
+    {
+        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__);
+        return SCP_SERVER_STATE_SESSION_TYPE_ERR;
+    }
+
+    scp_session_set_type(session, type);
+
+    in_uint16_be(c->in_s, height);
+    scp_session_set_height(session, height);
+    in_uint16_be(c->in_s, width);
+    scp_session_set_width(session, width);
+    in_uint8(c->in_s, bpp);
+    if (0 != scp_session_set_bpp(session, bpp))
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: unsupported bpp: %d",
+                    __LINE__, bpp);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+    in_uint8(c->in_s, sz);
+    scp_session_set_rsr(session, sz);
+    in_uint8a(c->in_s, buf, 17);
+    buf[17] = '\0';
+    scp_session_set_locale(session, buf);
+
+    /* Check there's enough data left for at least an IPv4 address (+len) */
+    if (!s_check_rem(c->in_s, 1 + 4))
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: IP addr len missing",
+                    __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    in_uint8(c->in_s, sz);
+
+    if (sz == SCP_ADDRESS_TYPE_IPV4)
+    {
+        tui32 ipv4;
+        in_uint32_be(c->in_s, ipv4);
+        scp_session_set_addr(session, sz, &ipv4);
+    }
+    else if (sz == SCP_ADDRESS_TYPE_IPV6)
+    {
+        if (!s_check_rem(c->in_s, 16))
+        {
+            log_message(LOG_LEVEL_WARNING,
+                        "[v1s:%d] connection aborted: IP addr missing",
+                        __LINE__);
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
+        in_uint8a(c->in_s, buf, 16);
+        scp_session_set_addr(session, sz, buf);
+    }
+
+    /* reading hostname */
+    if (!in_string8(c->in_s, buf, "hostname", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    if (0 != scp_session_set_hostname(session, buf))
+    {
+        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+
+    /* reading username */
+    if (!in_string8(c->in_s, buf, "username", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    if (0 != scp_session_set_username(session, buf))
+    {
+        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+
+    /* reading password */
+    if (!in_string8(c->in_s, buf, "passwd", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    if (0 != scp_session_set_password(session, buf))
+    {
+        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
+        return SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+
+    return SCP_SERVER_STATE_OK;
+}
+
 /* server API */
 enum SCP_SERVER_STATES_E scp_v1s_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s, int skipVchk)
 {
+    enum SCP_SERVER_STATES_E result;
     struct SCP_SESSION *session;
     tui32 version;
     tui32 size;
     tui16 cmdset;
     tui16 cmd;
-    tui8 sz;
-    char buf[257];
+
+    (*s) = NULL;
 
     if (!skipVchk)
     {
@@ -68,13 +246,15 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(
 
     in_uint32_be(c->in_s, size);
 
-    if (size < 12)
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
     {
         log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
         return SCP_SERVER_STATE_SIZE_ERR;
     }
 
-    init_stream(c->in_s, c->in_s->size);
+    init_stream(c->in_s, size - 8);
 
     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
     {
@@ -82,6 +262,8 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(
         return SCP_SERVER_STATE_NETWORK_ERR;
     }
 
+    c->in_s->end = c->in_s->data + (size - 8);
+
     /* reading command set */
     in_uint16_be(c->in_s, cmdset);
 
@@ -111,98 +293,27 @@ enum SCP_SERVER_STATES_E scp_v1s_accept(
 
     session = scp_session_create();
 
-    if (0 == session)
-    {
-        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error (malloc returned NULL)", __LINE__);
-        return SCP_SERVER_STATE_INTERNAL_ERR;
-    }
-
-    scp_session_set_version(session, 1);
-
-    in_uint8(c->in_s, sz);
-
-    if ((sz != SCP_SESSION_TYPE_XVNC) && (sz != SCP_SESSION_TYPE_XRDP))
-    {
-        scp_session_destroy(session);
-        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: unknown session type", __LINE__);
-        return SCP_SERVER_STATE_SESSION_TYPE_ERR;
-    }
-
-    scp_session_set_type(session, sz);
-
-    in_uint16_be(c->in_s, cmd);
-    scp_session_set_height(session, cmd);
-    in_uint16_be(c->in_s, cmd);
-    scp_session_set_height(session, cmd);
-    in_uint8(c->in_s, sz);
-    if (0 != scp_session_set_bpp(session, sz))
+    if (NULL == session)
     {
-        scp_session_destroy(session);
         log_message(LOG_LEVEL_WARNING,
-                    "[v1s:%d] connection aborted: unsupported bpp: %d",
-                    __LINE__, sz);
-        return SCP_SERVER_STATE_INTERNAL_ERR;
-    }
-    in_uint8(c->in_s, sz);
-    scp_session_set_rsr(session, sz);
-    in_uint8a(c->in_s, buf, 17);
-    buf[17] = '\0';
-    scp_session_set_locale(session, buf);
-
-    in_uint8(c->in_s, sz);
-
-    if (sz == SCP_ADDRESS_TYPE_IPV4)
-    {
-        in_uint32_be(c->in_s, size);
-        scp_session_set_addr(session, sz, &size);
-    }
-    else if (sz == SCP_ADDRESS_TYPE_IPV6)
-    {
-        in_uint8a(c->in_s, buf, 16);
-        scp_session_set_addr(session, sz, buf);
-    }
-
-    buf[256] = '\0';
-    /* reading hostname */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
-
-    if (0 != scp_session_set_hostname(session, buf))
-    {
-        scp_session_destroy(session);
-        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-        return SCP_SERVER_STATE_INTERNAL_ERR;
+                    "[v1s:%d] connection aborted: internal error "
+                    "(malloc returned NULL)", __LINE__);
+        result = SCP_SERVER_STATE_INTERNAL_ERR;
     }
-
-    /* reading username */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
-
-    if (0 != scp_session_set_username(session, buf))
+    else
     {
-        scp_session_destroy(session);
-        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-        return SCP_SERVER_STATE_INTERNAL_ERR;
-    }
-
-    /* reading password */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
-
-    if (0 != scp_session_set_password(session, buf))
-    {
-        scp_session_destroy(session);
-        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: internal error", __LINE__);
-        return SCP_SERVER_STATE_INTERNAL_ERR;
+        result = scp_v1s_init_session(c, session);
+        if (result != SCP_SERVER_STATE_OK)
+        {
+            scp_session_destroy(session);
+            session = NULL;
+        }
     }
 
     /* returning the struct */
     (*s) = session;
 
-    return SCP_SERVER_STATE_OK;
+    return result;
 }
 
 enum SCP_SERVER_STATES_E
@@ -242,13 +353,12 @@ enum SCP_SERVER_STATES_E
 scp_v1s_request_password(struct SCP_CONNECTION *c, struct SCP_SESSION *s,
                          const char *reason)
 {
-    tui8 sz;
     tui32 version;
     tui32 size;
     tui16 cmdset;
     tui16 cmd;
     int rlen;
-    char buf[257];
+    char buf[256];
 
     init_stream(c->in_s, c->in_s->size);
     init_stream(c->out_s, c->out_s->size);
@@ -296,13 +406,17 @@ scp_v1s_request_password(struct SCP_CONN
 
     in_uint32_be(c->in_s, size);
 
-    if (size < 12)
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
     {
-        log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
+        log_message(LOG_LEVEL_WARNING,
+                    "[v1s:%d] connection aborted: size error",
+                    __LINE__);
         return SCP_SERVER_STATE_SIZE_ERR;
     }
 
-    init_stream(c->in_s, c->in_s->size);
+    init_stream(c->in_s, size - 8);
 
     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
     {
@@ -310,6 +424,8 @@ scp_v1s_request_password(struct SCP_CONN
         return SCP_SERVER_STATE_NETWORK_ERR;
     }
 
+    c->in_s->end = c->in_s->data + (size - 8);
+
     in_uint16_be(c->in_s, cmdset);
 
     if (cmdset != SCP_COMMAND_SET_DEFAULT)
@@ -326,11 +442,11 @@ scp_v1s_request_password(struct SCP_CONN
         return SCP_SERVER_STATE_SEQUENCE_ERR;
     }
 
-    buf[256] = '\0';
     /* reading username */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
+    if (!in_string8(c->in_s, buf, "username", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
     if (0 != scp_session_set_username(s, buf))
     {
@@ -339,9 +455,10 @@ scp_v1s_request_password(struct SCP_CONN
     }
 
     /* reading password */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
+    if (!in_string8(c->in_s, buf, "passwd", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
     if (0 != scp_session_set_password(s, buf))
     {
@@ -468,13 +585,15 @@ scp_v1s_list_sessions(struct SCP_CONNECT
 
     in_uint32_be(c->in_s, size);
 
-    if (size < 12)
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
     {
         log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
         return SCP_SERVER_STATE_SIZE_ERR;
     }
 
-    init_stream(c->in_s, c->in_s->size);
+    init_stream(c->in_s, size - 8);
 
     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
     {
@@ -482,6 +601,8 @@ scp_v1s_list_sessions(struct SCP_CONNECT
         return SCP_SERVER_STATE_NETWORK_ERR;
     }
 
+    c->in_s->end = c->in_s->data + (size - 8);
+
     in_uint16_be(c->in_s, cmd);
 
     if (cmd != SCP_COMMAND_SET_DEFAULT)
@@ -606,14 +727,16 @@ scp_v1s_list_sessions(struct SCP_CONNECT
 
     in_uint32_be(c->in_s, size);
 
-    if (size < 12)
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
     {
         log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: size error", __LINE__);
         return SCP_SERVER_STATE_SIZE_ERR;
     }
 
     /* rest of the packet */
-    init_stream(c->in_s, c->in_s->size);
+    init_stream(c->in_s, size - 8);
 
     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, (size - 8)))
     {
@@ -621,6 +744,8 @@ scp_v1s_list_sessions(struct SCP_CONNECT
         return SCP_SERVER_STATE_NETWORK_ERR;
     }
 
+    c->in_s->end = c->in_s->data + (size - 8);
+
     in_uint16_be(c->in_s, cmd);
 
     if (cmd != SCP_COMMAND_SET_DEFAULT)
@@ -633,6 +758,11 @@ scp_v1s_list_sessions(struct SCP_CONNECT
 
     if (cmd == 43)
     {
+        if (!s_check_rem(c->in_s, 4))
+        {
+            log_message(LOG_LEVEL_WARNING, "[v1s:%d] connection aborted: missing session", __LINE__);
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
         /* select session */
         in_uint32_be(c->in_s, (*sid));
 
Index: xrdp-0.9.6/sesman/libscp/libscp_v1s_mng.c
===================================================================
--- xrdp-0.9.6.orig/sesman/libscp/libscp_v1s_mng.c
+++ xrdp-0.9.6/sesman/libscp/libscp_v1s_mng.c
@@ -38,17 +38,79 @@
 static enum SCP_SERVER_STATES_E
 _scp_v1s_mng_check_response(struct SCP_CONNECTION *c, struct SCP_SESSION *s);
 
-/* server API */
-enum SCP_SERVER_STATES_E
-scp_v1s_mng_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s)
+/**
+ * Reads a uint8 followed by a string into a buffer
+ *
+ * Buffer is null-terminated on success
+ *
+ * @param s Input stream
+ * @param [out] Output buffer (must be >= 256 chars)
+ * @param param Parameter we're reading
+ * @param line Line number reference
+ * @return != 0 if string read OK
+ *
+ * @todo
+ *     This needs to be merged with the func of the same name in
+ *     libscp_v1s.c
+ */
+static
+int in_string8(struct stream *s, char str[], const char *param, int line)
+{
+    int result;
+
+    if (!s_check_rem(s, 1))
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v1s_mng:%d] connection aborted: %s len missing",
+                    line, param);
+        result = 0;
+    }
+    else
+    {
+        unsigned int sz;
+
+        in_uint8(s, sz);
+        result = s_check_rem(s, sz);
+        if (!result)
+        {
+            log_message(LOG_LEVEL_WARNING,
+                        "[v1s_mng:%d] connection aborted: %s data missing",
+                        line, param);
+        }
+        else
+        {
+            in_uint8a(s, str, sz);
+            str[sz] = '\0';
+        }
+    }
+    return result;
+}
+/**
+ * Initialises a V1 management session object
+ *
+ * At call time, the command set value has been read from the wire, and
+ * the command still needs to be processed.
+ *
+ * @param c Connection
+ * @param [out] session pre-allocated session object
+ * @return SCP_SERVER_STATE_START_MANAGE for success
+ */
+static enum SCP_SERVER_STATES_E
+scp_v1s_mng_init_session(struct SCP_CONNECTION *c, struct SCP_SESSION *session)
 {
-    struct SCP_SESSION *session;
     tui32 ipaddr;
     tui16 cmd;
     tui8 sz;
-    char buf[257];
+    char buf[256];
+
+    scp_session_set_version(session, 1);
 
     /* reading command */
+    if (!s_check_rem(c->in_s, 2))
+    {
+        /* Caller should have checked this */
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
     in_uint16_be(c->in_s, cmd);
 
     if (cmd != 1) /* manager login */
@@ -56,41 +118,39 @@ scp_v1s_mng_accept(struct SCP_CONNECTION
         return SCP_SERVER_STATE_SEQUENCE_ERR;
     }
 
-    session = scp_session_create();
-
-    if (0 == session)
+    /* reading username */
+    if (!in_string8(c->in_s, buf, "username", __LINE__))
     {
-        return SCP_SERVER_STATE_INTERNAL_ERR;
+        return SCP_SERVER_STATE_SIZE_ERR;
     }
 
-    scp_session_set_version(session, 1);
-    scp_session_set_type(session, SCP_SESSION_TYPE_MANAGE);
-
-    /* reading username */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
-
     if (0 != scp_session_set_username(session, buf))
     {
-        scp_session_destroy(session);
         return SCP_SERVER_STATE_INTERNAL_ERR;
     }
 
     /* reading password */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
+    if (!in_string8(c->in_s, buf, "passwd", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
     if (0 != scp_session_set_password(session, buf))
     {
-        scp_session_destroy(session);
         return SCP_SERVER_STATE_INTERNAL_ERR;
     }
 
-    /* reading remote address */
-    in_uint8(c->in_s, sz);
+    /* reading remote address
+     * Check there's enough data left for at least an IPv4 address (+len) */
+    if (!s_check_rem(c->in_s, 1 + 4))
+    {
+        log_message(LOG_LEVEL_WARNING,
+                    "[v1s_mng:%d] connection aborted: IP addr len missing",
+                    __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
+    in_uint8(c->in_s, sz);
     if (sz == SCP_ADDRESS_TYPE_IPV4)
     {
         in_uint32_be(c->in_s, ipaddr);
@@ -98,25 +158,57 @@ scp_v1s_mng_accept(struct SCP_CONNECTION
     }
     else if (sz == SCP_ADDRESS_TYPE_IPV6)
     {
+        if (!s_check_rem(c->in_s, 16))
+        {
+            log_message(LOG_LEVEL_WARNING,
+                        "[v1s_mng:%d] connection aborted: IP addr missing",
+                        __LINE__);
+            return SCP_SERVER_STATE_SIZE_ERR;
+        }
         in_uint8a(c->in_s, buf, 16);
         scp_session_set_addr(session, sz, buf);
     }
 
     /* reading hostname */
-    in_uint8(c->in_s, sz);
-    buf[sz] = '\0';
-    in_uint8a(c->in_s, buf, sz);
+    if (!in_string8(c->in_s, buf, "hostname", __LINE__))
+    {
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
 
     if (0 != scp_session_set_hostname(session, buf))
     {
-        scp_session_destroy(session);
         return SCP_SERVER_STATE_INTERNAL_ERR;
     }
 
-    /* returning the struct */
+    return SCP_SERVER_STATE_START_MANAGE;
+}
+
+enum SCP_SERVER_STATES_E
+scp_v1s_mng_accept(struct SCP_CONNECTION *c, struct SCP_SESSION **s)
+{
+    enum SCP_SERVER_STATES_E result;
+    struct SCP_SESSION *session;
+
+    session = scp_session_create();
+    if (NULL == session)
+    {
+        result = SCP_SERVER_STATE_INTERNAL_ERR;
+    }
+    else
+    {
+        scp_session_set_type(session, SCP_SESSION_TYPE_MANAGE);
+
+        result = scp_v1s_mng_init_session(c, session);
+        if (result != SCP_SERVER_STATE_START_MANAGE)
+        {
+            scp_session_destroy(session);
+            session = NULL;
+        }
+    }
+
     (*s) = session;
 
-    return SCP_SERVER_STATE_START_MANAGE;
+    return result;
 }
 
 /* 002 */
@@ -312,7 +404,15 @@ _scp_v1s_mng_check_response(struct SCP_C
 
     in_uint32_be(c->in_s, size);
 
-    init_stream(c->in_s, c->in_s->size);
+    /* Check the message is big enough for the header, the command set, and
+     * the command (but not too big) */
+    if (size < (8 + 2 + 2) || size > SCP_MAX_MESSAGE_SIZE)
+    {
+        log_message(LOG_LEVEL_WARNING, "[v1s_mng:%d] connection aborted: size error", __LINE__);
+        return SCP_SERVER_STATE_SIZE_ERR;
+    }
+
+    init_stream(c->in_s, size - 8);
 
     /* read the rest of the packet */
     if (0 != scp_tcp_force_recv(c->in_sck, c->in_s->data, size - 8))
@@ -321,6 +421,8 @@ _scp_v1s_mng_check_response(struct SCP_C
         return SCP_SERVER_STATE_NETWORK_ERR;
     }
 
+    c->in_s->end = c->in_s->data + (size - 8);
+
     in_uint16_be(c->in_s, cmd);
 
     if (cmd != SCP_COMMAND_SET_MANAGE)
Index: xrdp-0.9.6/sesman/scp.c
===================================================================
--- xrdp-0.9.6.orig/sesman/scp.c
+++ xrdp-0.9.6/sesman/scp.c
@@ -48,8 +48,8 @@ scp_process_start(void *sck)
     make_stream(scon.in_s);
     make_stream(scon.out_s);
 
-    init_stream(scon.in_s, 8192);
-    init_stream(scon.out_s, 8192);
+    init_stream(scon.in_s, SCP_MAX_MESSAGE_SIZE);
+    init_stream(scon.out_s, SCP_MAX_MESSAGE_SIZE);
 
     switch (scp_vXs_accept(&scon, &(sdata)))
     {
@@ -76,10 +76,12 @@ scp_process_start(void *sck)
             scp_v1_mng_process(&scon, sdata);
             break;
         case SCP_SERVER_STATE_VERSION_ERR:
-            /* an unknown scp version was requested, so we shut down the */
-            /* connection (and log the fact)                             */
+        case SCP_SERVER_STATE_SIZE_ERR:
+            /* an unknown scp version was requested, or the message sizes
+               are inconsistent. Shut down the connection and log the
+               fact */
             log_message(LOG_LEVEL_WARNING,
-                        "unknown protocol version specified. connection refused.");
+                        "protocol violation. connection refused.");
             break;
         case SCP_SERVER_STATE_NETWORK_ERR:
             log_message(LOG_LEVEL_WARNING, "libscp network error.");
