Version in base suite: 0.9.21.1-1 Base version: xrdp_0.9.21.1-1 Target version: xrdp_0.9.21.1-1+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/x/xrdp/xrdp_0.9.21.1-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/x/xrdp/xrdp_0.9.21.1-1+deb12u1.dsc changelog | 16 ++ patches/CVE-2023-40184.patch | 56 ++++++++ patches/CVE-2023-42822.patch | 300 +++++++++++++++++++++++++++++++++++++++++++ patches/CVE-2024-39917.patch | 101 ++++++++++++++ patches/series | 3 5 files changed, 476 insertions(+) diff -Nru xrdp-0.9.21.1/debian/changelog xrdp-0.9.21.1/debian/changelog --- xrdp-0.9.21.1/debian/changelog 2022-12-20 10:09:50.000000000 +0000 +++ xrdp-0.9.21.1/debian/changelog 2025-05-25 09:46:34.000000000 +0000 @@ -1,3 +1,19 @@ +xrdp (0.9.21.1-1+deb12u1) bookworm; urgency=high + + * Non-maintainer upload + * Fix CVE-2023-40184: Improper handling of session establishment + errors allows bypassing OS-level session restrictions. The + `auth_start_session` function can return non-zero. PAM error + which may result in session restrictions such as max concurrent + sessions per user by PAM (ex ./etc/security/limits.conf) to be + bypassed (Closes: #1051061) + * Fix CVE-2023-42822: Access to the font glyphs in xrdp_painter.c + is not bounds-checked. (Closes: #1053284) + * Fix CVE-2024-39917: vulnerability that allows attackers to make + an infinite number of login attempts. (Closes: #1076769) + + -- Abhijith PA Sun, 25 May 2025 15:16:34 +0530 + xrdp (0.9.21.1-1) unstable; urgency=medium * New upstream version. (Closes: #1025879) diff -Nru xrdp-0.9.21.1/debian/patches/CVE-2023-40184.patch xrdp-0.9.21.1/debian/patches/CVE-2023-40184.patch --- xrdp-0.9.21.1/debian/patches/CVE-2023-40184.patch 1970-01-01 00:00:00.000000000 +0000 +++ xrdp-0.9.21.1/debian/patches/CVE-2023-40184.patch 2025-05-25 09:46:34.000000000 +0000 @@ -0,0 +1,56 @@ +--- a/sesman/session.c ++++ b/sesman/session.c +@@ -526,7 +526,12 @@ session_start_fork(tbus data, tui8 type, + g_delete_wait_obj(g_sigchld_event); + g_delete_wait_obj(g_term_event); + +- auth_start_session(data, display); ++ if (auth_start_session(data, display) != 0) ++ { ++ // Errors are logged by the auth module, as they are ++ // specific to that module ++ g_exit(1); ++ } + sesman_close_all(); + g_sprintf(geometry, "%dx%d", s->width, s->height); + g_sprintf(depth, "%d", s->bpp); +--- a/sesman/verify_user_pam.c ++++ b/sesman/verify_user_pam.c +@@ -308,8 +308,8 @@ auth_userpass(const char *user, const ch + + /******************************************************************************/ + /* returns error */ +-int +-auth_start_session(long in_val, int in_display) ++static int ++auth_start_session_private(long in_val, int in_display) + { + struct t_auth_info *auth_info; + int error; +@@ -350,6 +350,26 @@ auth_start_session(long in_val, int in_d + } + + /******************************************************************************/ ++/** ++ * Main routine to start a session ++ * ++ * Calls the private routine and logs an additional error if the private ++ * routine fails ++ */ ++int ++auth_start_session(long in_val, int in_display) ++{ ++ int result = auth_start_session_private(in_val, in_display); ++ if (result != 0) ++ { ++ LOG(LOG_LEVEL_ERROR, ++ "Can't start PAM session. See PAM logging for more info"); ++ } ++ ++ return result; ++} ++ ++/******************************************************************************/ + /* returns error */ + int + auth_stop_session(long in_val) diff -Nru xrdp-0.9.21.1/debian/patches/CVE-2023-42822.patch xrdp-0.9.21.1/debian/patches/CVE-2023-42822.patch --- xrdp-0.9.21.1/debian/patches/CVE-2023-42822.patch 1970-01-01 00:00:00.000000000 +0000 +++ xrdp-0.9.21.1/debian/patches/CVE-2023-42822.patch 2025-05-25 09:46:34.000000000 +0000 @@ -0,0 +1,300 @@ +From 58c9c1f06aeb5c91386bca20fa1609d68bf37ae0 Mon Sep 17 00:00:00 2001 +From: matt335672 <30179339+matt335672@users.noreply.github.com> +Date: Mon, 25 Sep 2023 11:25:04 +0100 +Subject: [PATCH] CVE-2023-42822 + +- font_items in struct xrdp_font renamed to chars to catch all + accesses to it. This name is consistent with the type of + the array elements (struct xrdp_font_char). +- Additional fields added to struct xrdp_font to allow for range + checking and for a default character to be provided +- Additional checks and logic added to xrdp_font_create() +- New macro XRDP_FONT_GET_CHAR() added to perform checked access + to chars field in struct xrdp_font +--- + xrdp/xrdp.h | 9 ++++ + xrdp/xrdp_font.c | 113 +++++++++++++++++++++++++++++++++++++------- + xrdp/xrdp_painter.c | 10 ++-- + xrdp/xrdp_types.h | 8 +++- + 4 files changed, 115 insertions(+), 25 deletions(-) + +diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h +index 36d8f87a9a..be008aa227 100644 +--- a/xrdp/xrdp.h ++++ b/xrdp/xrdp.h +@@ -345,6 +345,15 @@ xrdp_font_delete(struct xrdp_font *self); + int + xrdp_font_item_compare(struct xrdp_font_char *font1, + struct xrdp_font_char *font2); ++/** ++ * Gets a checked xrdp_font_char from a font ++ * @param f Font ++ * @param c32 Unicode codepoint ++ */ ++#define XRDP_FONT_GET_CHAR(f, c32) \ ++ (((unsigned int)(c32) >= ' ') && ((unsigned int)(c32) < (f)->char_count) \ ++ ? ((f)->chars + (unsigned int)(c32)) \ ++ : (f)->default_char) + + /* funcs.c */ + int +diff --git a/xrdp/xrdp_font.c b/xrdp/xrdp_font.c +index c089db0075..2b34f36ca6 100644 +--- a/xrdp/xrdp_font.c ++++ b/xrdp/xrdp_font.c +@@ -65,6 +65,12 @@ static char w_char[] = + }; + #endif + ++// Unicode definitions ++#define UNICODE_WHITE_SQUARE 0x25a1 ++ ++// First character allocated in the 'struct xrdp_font.chars' array ++#define FIRST_CHAR ' ' ++ + /*****************************************************************************/ + struct xrdp_font * + xrdp_font_create(struct xrdp_wm *wm) +@@ -74,7 +80,7 @@ xrdp_font_create(struct xrdp_wm *wm) + int fd; + int b; + int i; +- int index; ++ unsigned int char_count; + int datasize; + int file_size; + struct xrdp_font_char *f; +@@ -100,17 +106,39 @@ xrdp_font_create(struct xrdp_wm *wm) + } + + self = (struct xrdp_font *)g_malloc(sizeof(struct xrdp_font), 1); ++ if (self == NULL) ++ { ++ LOG(LOG_LEVEL_ERROR, "xrdp_font_create: " ++ "Can't allocate memory for font"); ++ return self; ++ } + self->wm = wm; + make_stream(s); + init_stream(s, file_size + 1024); + fd = g_file_open(file_path); + +- if (fd != -1) ++ if (fd < 0) ++ { ++ LOG(LOG_LEVEL_ERROR, ++ "xrdp_font_create: Can't open %s - %s", file_path, ++ g_get_strerror()); ++ g_free(self); ++ self = NULL; ++ } ++ else + { + b = g_file_read(fd, s->data, file_size + 1024); + g_file_close(fd); + +- if (b > 0) ++ // Got at least a header? ++ if (b < (4 + 32 + 2 + 2 + 8)) ++ { ++ LOG(LOG_LEVEL_ERROR, ++ "xrdp_font_create: Font %s is truncated", file_path); ++ g_free(self); ++ self = NULL; ++ } ++ else + { + s->end = s->data + b; + in_uint8s(s, 4); +@@ -118,11 +146,27 @@ xrdp_font_create(struct xrdp_wm *wm) + in_uint16_le(s, self->size); + in_uint16_le(s, self->style); + in_uint8s(s, 8); +- index = 32; ++ char_count = FIRST_CHAR; + +- while (s_check_rem(s, 16)) ++ while (!s_check_end(s)) + { +- f = self->font_items + index; ++ if (!s_check_rem(s, 16)) ++ { ++ LOG(LOG_LEVEL_WARNING, ++ "xrdp_font_create: " ++ "Can't parse header for character U+%X", char_count); ++ break; ++ } ++ ++ if (char_count >= MAX_FONT_CHARS) ++ { ++ LOG(LOG_LEVEL_WARNING, ++ "xrdp_font_create: " ++ "Ignoring characters >= U+%x", MAX_FONT_CHARS); ++ break; ++ } ++ ++ f = self->chars + char_count; + in_sint16_le(s, i); + f->width = i; + in_sint16_le(s, i); +@@ -139,23 +183,56 @@ xrdp_font_create(struct xrdp_wm *wm) + if (datasize < 0 || datasize > 512) + { + /* shouldn't happen */ +- LOG(LOG_LEVEL_ERROR, "error in xrdp_font_create, datasize wrong " +- "width %d, height %d, datasize %d, index %d", +- f->width, f->height, datasize, index); ++ LOG(LOG_LEVEL_ERROR, ++ "xrdp_font_create: " ++ "datasize for U+%x wrong " ++ "width %d, height %d, datasize %d", ++ char_count, f->width, f->height, datasize); + break; + } + +- if (s_check_rem(s, datasize)) ++ if (!s_check_rem(s, datasize)) + { +- f->data = (char *)g_malloc(datasize, 0); +- in_uint8a(s, f->data, datasize); ++ LOG(LOG_LEVEL_ERROR, ++ "xrdp_font_create: " ++ "Not enough data for character U+%X", char_count); ++ break; + } +- else ++ ++ if ((f->data = (char *)g_malloc(datasize, 0)) == NULL) + { +- LOG(LOG_LEVEL_ERROR, "error in xrdp_font_create"); ++ LOG(LOG_LEVEL_ERROR, ++ "xrdp_font_create: " ++ "Allocation error for character U+%X", char_count); ++ break; + } ++ in_uint8a(s, f->data, datasize); ++ ++ ++char_count; ++ } + +- index++; ++ self->char_count = char_count; ++ if (char_count <= FIRST_CHAR) ++ { ++ /* We read no characters from the font */ ++ xrdp_font_delete(self); ++ self = NULL; ++ } ++ else ++ { ++ // Find a default glyph ++ if (char_count > UNICODE_WHITE_SQUARE) ++ { ++ self->default_char = &self->chars[UNICODE_WHITE_SQUARE]; ++ } ++ else if (char_count > '?') ++ { ++ self->default_char = &self->chars['?']; ++ } ++ else ++ { ++ self->default_char = &self->chars[FIRST_CHAR]; ++ } + } + } + } +@@ -178,16 +255,16 @@ xrdp_font_create(struct xrdp_wm *wm) + void + xrdp_font_delete(struct xrdp_font *self) + { +- int i; ++ unsigned int i; + + if (self == 0) + { + return; + } + +- for (i = 0; i < NUM_FONTS; i++) ++ for (i = FIRST_CHAR; i < self->char_count; i++) + { +- g_free(self->font_items[i].data); ++ g_free(self->chars[i].data); + } + + g_free(self); +diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c +index b02c9072b6..832186ff22 100644 +--- a/xrdp/xrdp_painter.c ++++ b/xrdp/xrdp_painter.c +@@ -455,7 +455,7 @@ xrdp_painter_text_width(struct xrdp_painter *self, const char *text) + + for (index = 0; index < len; index++) + { +- font_item = self->font->font_items + wstr[index]; ++ font_item = XRDP_FONT_GET_CHAR(self->font, wstr[index]); + rv = rv + font_item->incby; + } + +@@ -493,7 +493,7 @@ xrdp_painter_text_height(struct xrdp_painter *self, const char *text) + + for (index = 0; index < len; index++) + { +- font_item = self->font->font_items + wstr[index]; ++ font_item = XRDP_FONT_GET_CHAR(self->font, wstr[index]); + rv = MAX(rv, font_item->height); + } + +@@ -870,7 +870,7 @@ xrdp_painter_draw_text(struct xrdp_painter *self, + total_height = 0; + for (index = 0; index < len; index++) + { +- font_item = font->font_items + wstr[index]; ++ font_item = XRDP_FONT_GET_CHAR(font, wstr[index]); + k = font_item->incby; + total_width += k; + total_height = MAX(total_height, font_item->height); +@@ -904,7 +904,7 @@ xrdp_painter_draw_text(struct xrdp_painter *self, + draw_rect.bottom - draw_rect.top); + for (index = 0; index < len; index++) + { +- font_item = font->font_items + wstr[index]; ++ font_item = XRDP_FONT_GET_CHAR(font, wstr[index]); + g_memset(&pat, 0, sizeof(pat)); + pat.format = PT_FORMAT_c1; + pat.width = font_item->width; +@@ -946,7 +946,7 @@ xrdp_painter_draw_text(struct xrdp_painter *self, + + for (index = 0; index < len; index++) + { +- font_item = font->font_items + wstr[index]; ++ font_item = XRDP_FONT_GET_CHAR(font, wstr[index]); + i = xrdp_cache_add_char(self->wm->cache, font_item); + f = HIWORD(i); + c = LOWORD(i); +diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h +index 41b65702f0..b794890b08 100644 +--- a/xrdp/xrdp_types.h ++++ b/xrdp/xrdp_types.h +@@ -574,7 +574,7 @@ struct xrdp_bitmap + int crc16; + }; + +-#define NUM_FONTS 0x4e00 ++#define MAX_FONT_CHARS 0x4e00 + #define DEFAULT_FONT_NAME "sans-10.fv1" + + #define DEFAULT_ELEMENT_TOP 35 +@@ -594,7 +594,11 @@ struct xrdp_bitmap + struct xrdp_font + { + struct xrdp_wm *wm; +- struct xrdp_font_char font_items[NUM_FONTS]; ++ // Font characters, accessed by Unicode codepoint. The first 32 ++ // entries are unused. ++ struct xrdp_font_char chars[MAX_FONT_CHARS]; ++ unsigned int char_count; // # elements in above array ++ struct xrdp_font_char *default_char; // Pointer into above array + char name[32]; + int size; + int style; diff -Nru xrdp-0.9.21.1/debian/patches/CVE-2024-39917.patch xrdp-0.9.21.1/debian/patches/CVE-2024-39917.patch --- xrdp-0.9.21.1/debian/patches/CVE-2024-39917.patch 1970-01-01 00:00:00.000000000 +0000 +++ xrdp-0.9.21.1/debian/patches/CVE-2024-39917.patch 2025-05-16 06:52:50.000000000 +0000 @@ -0,0 +1,101 @@ +Description: CVE-2024-39917 +Author: Abhijith PA +Origin: (upstream|backport|vendor|other), (|commit:) +Last-Update: 2025-02-27 + +--- a/docs/man/xrdp.ini.5.in ++++ b/docs/man/xrdp.ini.5.in +@@ -119,10 +119,12 @@ Specifying interfaces requires said inte + + .TP + \fBrequire_credentials\fP=\fI[true|false]\fP +-If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP will scan the user name provided by the +-client for the ASCII field separator character (0x1F). It will then copy over what is after the +-separator as the password supplied by the user and treats it as autologon. If not specified, +-defaults to \fBfalse\fP. ++If set to \fB1\fP, \fBtrue\fP or \fByes\fP, \fBxrdp\fP requires clients ++to include username and password initial connection phase. In other ++words, xrdp doesn't allow clients to show login screen if set to true. ++It follows that an incorrect password will cause the login to immediately ++fail without displaying the login screen. If not specified, defaults ++to \fBfalse\fP. + + .TP + \domain_user_separator\fP=\separator\fP +--- a/libxrdp/xrdp_sec.c ++++ b/libxrdp/xrdp_sec.c +@@ -1001,6 +1001,25 @@ xrdp_sec_process_logon_info(struct xrdp_ + return 1; + } + ++ // If we require credentials, don't continue if they're not provided ++ if (self->rdp_layer->client_info.require_credentials) ++ { ++ if ((flags & RDP_LOGON_AUTO) == 0) ++ { ++ LOG(LOG_LEVEL_ERROR, "Server is configured to require that the " ++ "client enable auto logon with credentials, but the client did " ++ "not request auto logon."); ++ return 1; ++ } ++ if (len_user == 0 || len_password == 0) ++ { ++ LOG(LOG_LEVEL_ERROR, "Server is configured to require that the " ++ "client enable auto logon with credentials, but the client did " ++ "not supply both a username and password."); ++ return 1; ++ } ++ } ++ + if (flags & RDP_LOGON_AUTO) + { + if (unicode_utf16_in(s, len_password, self->rdp_layer->client_info.password, sizeof(self->rdp_layer->client_info.password) - 1) != 0) +@@ -1022,18 +1041,13 @@ xrdp_sec_process_logon_info(struct xrdp_ + } + else + { ++ // Skip the password + if (!s_check_rem_and_log(s, len_password + 2, "Parsing [MS-RDPBCGR] TS_INFO_PACKET Password")) + { + return 1; + } + in_uint8s(s, len_password + 2); +- if (self->rdp_layer->client_info.require_credentials) +- { +- LOG(LOG_LEVEL_ERROR, "Server is configured to require that the " +- "client enable auto logon with credentials, but the client did " +- "not request auto logon."); +- return 1; /* credentials on cmd line is mandatory */ +- } ++ + } + if (self->rdp_layer->client_info.domain_user_separator[0] != '\0' + && self->rdp_layer->client_info.domain[0] != '\0') +--- a/xrdp/xrdp.ini ++++ b/xrdp/xrdp.ini +@@ -87,7 +87,8 @@ max_bpp=32 + new_cursors=true + ; fastpath - can be 'input', 'output', 'both', 'none' + use_fastpath=both +-; when true, userid/password *must* be passed on cmd line ++;when true, userid/password *must* be passed on cmd line. If the password ++; is incorrect, the login will fail + #require_credentials=true + ; when true, the userid will be used to try to authenticate + #enable_token_login=true +--- a/xrdp/xrdp_mm.c ++++ b/xrdp/xrdp_mm.c +@@ -1884,6 +1884,13 @@ xrdp_mm_scp_process_msg(struct xrdp_mm * + { + /* Authentication failure */ + cleanup_sesman_connection(self); ++ if (self->wm->client_info->require_credentials) ++ { ++ /* Credentials had to be specified, but were invalid */ ++ g_set_wait_obj(self->wm->pro_layer->self_term_event); ++ LOG(LOG_LEVEL_ERROR, "require_credentials is set, " ++ "but the user could not be logged in"); ++ } + xrdp_wm_mod_connect_done(self->wm, 1); + } + else diff -Nru xrdp-0.9.21.1/debian/patches/series xrdp-0.9.21.1/debian/patches/series --- xrdp-0.9.21.1/debian/patches/series 2022-12-20 09:47:18.000000000 +0000 +++ xrdp-0.9.21.1/debian/patches/series 2025-05-25 09:46:34.000000000 +0000 @@ -7,3 +7,6 @@ var-run.diff document-certs.diff fix-environment.diff +CVE-2023-40184.patch +CVE-2023-42822.patch +CVE-2024-39917.patch