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);
openSUSE Build Service is sponsored by