File 0009-rdp-server-Throttle-connections-using-GrdThrottler.patch of Package gnome-remote-desktop
From 557d6197a2ff368dbf5b5da91e4f65c4c427e819 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 10 Feb 2026 16:44:43 -0600
Subject: [PATCH 09/13] rdp-server: Throttle connections using GrdThrottler
This avoids system resource exhaustion by a single attacker.
Related: CVE-2025-5024
Part-of: <https://gitlab.gnome.org/GNOME/gnome-remote-desktop/-/merge_requests/321>
Backported by Mike Gorse <mgorse@suse.com>
---
src/grd-daemon-system.c | 4 ++
src/grd-rdp-server.c | 100 ++++++++++++++++++++++++++++++++--------
src/grd-session-rdp.c | 5 ++
3 files changed, 91 insertions(+), 18 deletions(-)
diff -urp gnome-remote-desktop-49.2.orig/src/grd-daemon-system.c gnome-remote-desktop-49.2/src/grd-daemon-system.c
--- gnome-remote-desktop-49.2.orig/src/grd-daemon-system.c 2026-02-10 17:57:24.786514313 -0600
+++ gnome-remote-desktop-49.2/src/grd-daemon-system.c 2026-02-10 17:58:00.383080115 -0600
@@ -35,6 +35,7 @@
#include "grd-rdp-server.h"
#include "grd-session-rdp.h"
#include "grd-settings.h"
+#include "grd-utils.h"
#define MAX_HANDOVER_WAIT_TIME_MS (30 * 1000)
@@ -148,6 +149,7 @@ on_handle_take_client (GrdDBusRemoteDesk
fd_list,
fd_variant);
+ grd_close_connection_and_notify (remote_client->socket_connection);
g_clear_object (&remote_client->socket_connection);
g_clear_handle_id (&remote_client->abort_handover_source_id, g_source_remove);
@@ -524,6 +526,8 @@ static void
grd_remote_client_free (GrdRemoteClient *remote_client)
{
g_clear_pointer (&remote_client->id, g_free);
+ if (remote_client->socket_connection)
+ grd_close_connection_and_notify (remote_client->socket_connection);
g_clear_object (&remote_client->socket_connection);
unregister_handover_iface (remote_client, remote_client->handover_src);
unregister_handover_iface (remote_client, remote_client->handover_dst);
diff -urp gnome-remote-desktop-49.2.orig/src/grd-rdp-server.c gnome-remote-desktop-49.2/src/grd-rdp-server.c
--- gnome-remote-desktop-49.2.orig/src/grd-rdp-server.c 2026-02-10 17:57:37.936440841 -0600
+++ gnome-remote-desktop-49.2/src/grd-rdp-server.c 2026-02-10 18:08:41.674218612 -0600
@@ -32,6 +32,7 @@
#include "grd-hwaccel-vulkan.h"
#include "grd-rdp-routing-token.h"
#include "grd-session-rdp.h"
+#include "grd-throttler.h"
#include "grd-utils.h"
#define RDP_SERVER_N_BINDING_ATTEMPTS 10
@@ -60,6 +61,8 @@ struct _GrdRdpServer
{
GSocketService parent;
+ GrdThrottler *throttler;
+
GList *sessions;
GList *stopped_sessions;
@@ -206,18 +209,17 @@ on_routing_token_peeked (GObject *s
}
}
-static gboolean
-on_incoming_as_system_headless (GSocketService *service,
- GSocketConnection *connection)
+static void
+allow_connection_peek_cb (GrdThrottler *throttler,
+ GSocketConnection *connection,
+ gpointer user_data)
{
- GrdRdpServer *rdp_server = GRD_RDP_SERVER (service);
+ GrdRdpServer *rdp_server = GRD_RDP_SERVER (user_data);
grd_routing_token_peek_async (rdp_server,
connection,
rdp_server->cancellable,
on_routing_token_peeked);
-
- return TRUE;
}
static gboolean
@@ -225,14 +227,24 @@ on_incoming (GSocketService *service,
GSocketConnection *connection)
{
GrdRdpServer *rdp_server = GRD_RDP_SERVER (service);
+
+ grd_throttler_handle_connection (rdp_server->throttler,
+ connection);
+ return TRUE;
+}
+
+static void
+accept_connection (GrdRdpServer *rdp_server,
+ GSocketConnection *connection)
+{
GrdSessionRdp *session_rdp;
- g_debug ("New incoming RDP connection");
+ g_debug ("Creating new RDP session");
if (!(session_rdp = grd_session_rdp_new (rdp_server, connection,
rdp_server->hwaccel_vulkan,
rdp_server->hwaccel_nvidia)))
- return TRUE;
+ return;
rdp_server->sessions = g_list_append (rdp_server->sessions, session_rdp);
@@ -243,15 +255,35 @@ on_incoming (GSocketService *service,
g_signal_connect (session_rdp, "post-connected",
G_CALLBACK (on_session_post_connect),
rdp_server);
+}
- return TRUE;
+static void
+allow_connection_accept_cb (GrdThrottler *throttler,
+ GSocketConnection *connection,
+ gpointer user_data)
+{
+ GrdRdpServer *rdp_server = GRD_RDP_SERVER (user_data);
+
+ accept_connection (rdp_server, connection);
}
void
grd_rdp_server_notify_incoming (GSocketService *service,
GSocketConnection *connection)
{
- on_incoming (service, connection);
+ GrdRdpServer *rdp_server = GRD_RDP_SERVER (service);
+ GrdRuntimeMode runtime_mode = grd_context_get_runtime_mode (rdp_server->context);
+
+ switch (runtime_mode)
+ {
+ case GRD_RUNTIME_MODE_HANDOVER:
+ accept_connection (rdp_server, connection);
+ break;
+ case GRD_RUNTIME_MODE_SYSTEM:
+ case GRD_RUNTIME_MODE_SCREEN_SHARE:
+ case GRD_RUNTIME_MODE_HEADLESS:
+ g_assert_not_reached ();
+ }
}
static gboolean
@@ -378,16 +410,13 @@ grd_rdp_server_start (GrdRdpServer *rdp
switch (runtime_mode)
{
- case GRD_RUNTIME_MODE_SCREEN_SHARE:
- case GRD_RUNTIME_MODE_HEADLESS:
- g_signal_connect (rdp_server, "incoming", G_CALLBACK (on_incoming), NULL);
- break;
case GRD_RUNTIME_MODE_SYSTEM:
- g_signal_connect (rdp_server, "incoming",
- G_CALLBACK (on_incoming_as_system_headless), NULL);
-
g_assert (!rdp_server->cancellable);
rdp_server->cancellable = g_cancellable_new ();
+ G_GNUC_FALLTHROUGH;
+ case GRD_RUNTIME_MODE_SCREEN_SHARE:
+ case GRD_RUNTIME_MODE_HEADLESS:
+ g_signal_connect (rdp_server, "incoming", G_CALLBACK (on_incoming), NULL);
break;
case GRD_RUNTIME_MODE_HANDOVER:
break;
@@ -420,6 +449,8 @@ grd_rdp_server_stop (GrdRdpServer *rdp_s
g_clear_handle_id (&rdp_server->cleanup_sessions_idle_id, g_source_remove);
grd_rdp_server_cleanup_stopped_sessions (rdp_server);
+ g_clear_object (&rdp_server->throttler);
+
if (rdp_server->cancellable)
{
g_cancellable_cancel (rdp_server->cancellable);
@@ -479,6 +510,7 @@ grd_rdp_server_dispose (GObject *object)
g_assert (!rdp_server->binding_timeout_source_id);
g_assert (!rdp_server->cleanup_sessions_idle_id);
g_assert (!rdp_server->stopped_sessions);
+ g_assert (!rdp_server->throttler);
g_assert (!rdp_server->hwaccel_nvidia);
g_assert (!rdp_server->hwaccel_vulkan);
@@ -489,12 +521,30 @@ grd_rdp_server_dispose (GObject *object)
static void
grd_rdp_server_constructed (GObject *object)
{
- G_OBJECT_CLASS (grd_rdp_server_parent_class)->constructed (object);
-}
+ GrdRdpServer *rdp_server = GRD_RDP_SERVER (object);
+ GrdRuntimeMode runtime_mode =
+ grd_context_get_runtime_mode (rdp_server->context);
+ GrdThrottlerAllowCallback allow_callback = NULL;
+
+ switch (runtime_mode)
+ {
+ case GRD_RUNTIME_MODE_SCREEN_SHARE:
+ case GRD_RUNTIME_MODE_HEADLESS:
+ allow_callback = allow_connection_accept_cb;
+ break;
+ case GRD_RUNTIME_MODE_SYSTEM:
+ allow_callback = allow_connection_peek_cb;
+ break;
+ case GRD_RUNTIME_MODE_HANDOVER:
+ break;
+ }
+
+ if (allow_callback)
+ {
+ rdp_server->throttler = grd_throttler_new (allow_callback,
+ rdp_server);
+ }
-static void
-grd_rdp_server_init (GrdRdpServer *rdp_server)
-{
rdp_server->pending_binding_attempts = RDP_SERVER_N_BINDING_ATTEMPTS;
winpr_InitializeSSL (WINPR_SSL_INIT_DEFAULT);
@@ -504,6 +554,13 @@ grd_rdp_server_init (GrdRdpServer *rdp_s
* Run the primitives benchmark here to save time, when initializing a session
*/
primitives_get ();
+
+ G_OBJECT_CLASS (grd_rdp_server_parent_class)->constructed (object);
+}
+
+static void
+grd_rdp_server_init (GrdRdpServer *rdp_server)
+{
}
static void
diff -urp gnome-remote-desktop-49.2.orig/src/grd-session-rdp.c gnome-remote-desktop-49.2/src/grd-session-rdp.c
--- gnome-remote-desktop-49.2.orig/src/grd-session-rdp.c 2026-02-10 17:57:24.812514709 -0600
+++ gnome-remote-desktop-49.2/src/grd-session-rdp.c 2026-02-10 17:58:00.385139366 -0600
@@ -48,6 +48,7 @@
#include "grd-rdp-server.h"
#include "grd-rdp-session-metrics.h"
#include "grd-settings.h"
+#include "grd-utils.h"
#define MAX_MONITOR_COUNT_HEADLESS 16
#define MAX_MONITOR_COUNT_SCREEN_SHARE 1
@@ -1643,6 +1644,7 @@ grd_session_rdp_stop (GrdSession *sessio
g_clear_object (&session_rdp->renderer);
peer->Close (peer);
+ grd_close_connection_and_notify (session_rdp->connection);
g_clear_object (&session_rdp->connection);
g_clear_object (&rdp_peer_context->network_autodetection);
@@ -1833,6 +1835,9 @@ grd_session_rdp_dispose (GObject *object
g_clear_object (&session_rdp->layout_manager);
clear_rdp_peer (session_rdp);
+
+ if (session_rdp->connection)
+ grd_close_connection_and_notify (session_rdp->connection);
g_clear_object (&session_rdp->connection);
g_clear_object (&session_rdp->renderer);