CVE-2026-18358 gnome-remote-desktop: gnome-remote-desktop system-mode RDP server missing connection throttling allows unauthenticated denial of service
A flaw was found in gnome-remote-desktop as shipped in Red Hat Enterprise Linux. When the daemon is running in system mode with RDP enabled, the incoming connection handler bypasses the connection throttler, allowing an unauthenticated remote attacker to open many parallel pre-authentication connections to the RDP listener. This can accumulate accepted sockets and pending routing-token operations until timeout, exhausting resources and preventing legitimate users from establishing RDP sessions. This issue does not affect the upstream version.
AI_ONLY_REPORT
package: gnome-remote-desktop-49.3-1.el10
------
Summary: Missing Connection Throttling in System-Mode RDP Server:
unauthenticated flooding of the system-mode RDP listener can accumulate
accepted sockets and asynchronous routing-token peek work until timeout,
degrading or denying legitimate RDP access.
Requirements to exploit: The `gnome-remote-desktop` system-mode daemon must
be running with RDP enabled and its RDP listener reachable from the
attacker. No authentication or user interaction is required; the attacker
only needs to open many parallel TCP connections and keep them open briefly
or send partial handshake data.
Component affected: `gnome-remote-desktop` RDP ingress handling in
`src/grd-rdp-server.c` and asynchronous routing-token peeking in
`src/grd-rdp-routing-token.c`.
Version affected: `gnome-remote-desktop-49.3-1.el10`, when run in
`--system` mode with RDP enabled and the RDP listener reachable by an
attacker.
Patch available: no released package fix established; proposed patch
included below
Version fixed: unknown
Upstream coordination: This report is the initial private notification.
CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - 7.5 (HIGH)
AV:N - The vulnerable path is reachable over the network through the RDP
listener when system mode is exposed.
AC:L - The attack is a straightforward connection flood against a
pre-auth code path; no special race or unusual precondition beyond service
exposure is required.
PR:N - The vulnerable behavior occurs before authentication.
UI:N - No user interaction is required.
S:U - The impact is confined to the `gnome-remote-desktop` service
boundary.
C:N - No confidentiality impact is demonstrated.
I:N - No integrity impact is demonstrated.
A:H - Repeated parallel connections can keep accepted sockets and async
peek work outstanding until timeout, materially degrading or denying
legitimate RDP service.
Impact: Important. This aligns with Red Hat's Important rating because it
allows unauthenticated remote users to cause denial of service against a
network-facing service. It is not Critical because the demonstrated impact
is availability loss rather than system compromise, and reachability
depends on the system-mode RDP service being enabled and exposed. The
listener backlog and two-second peek timeout reduce peak pressure but do
not eliminate sustained pre-auth flooding.
Embargo: no
Reason: The demonstrated impact is limited to service availability in a
configuration-dependent deployment, with no shown confidentiality,
integrity, or code-execution impact. Immediate operational mitigations are
available by disabling system-mode RDP or restricting network reachability.
Acknowledgement: Aisle Research
Vulnerability Details: In `grd_rdp_server_start()`,
`GRD_RUNTIME_MODE_SYSTEM` connects the `incoming` signal to
`on_incoming_as_system_headless()`, while non-system modes use
`on_incoming()`. The two handlers differ in a way that matters for pre-auth
resource control:
```c
static gboolean
on_incoming_as_system_headless (GSocketService *service,
GSocketConnection *connection)
{
GrdRdpServer *rdp_server = GRD_RDP_SERVER (service);
grd_routing_token_peek_async (rdp_server,
connection,
rdp_server->cancellable,
on_routing_token_peeked);
return TRUE;
}
static gboolean
on_incoming (GSocketService *service,
GSocketConnection *connection)
{
GrdRdpServer *rdp_server = GRD_RDP_SERVER (service);
grd_throttler_handle_connection (rdp_server->throttler,
connection);
return TRUE;
}
```
`grd_routing_token_peek_async()` retains the accepted socket in a
per-connection context, schedules the peek asynchronously, and only aborts
after `MAX_PEEK_TIME_MS`:
```c
void
grd_routing_token_peek_async (GrdRdpServer *rdp_server,
GSocketConnection *connection,
GCancellable *cancellable,
GAsyncReadyCallback on_finished_callback)
{
RoutingTokenContext *routing_token_context;
GTask *task;
routing_token_context = g_new0 (RoutingTokenContext, 1);
routing_token_context->rdp_server = rdp_server;
routing_token_context->connection = g_object_ref (connection);
routing_token_context->cancellable = g_cancellable_new ();
routing_token_context->server_cancellable = g_object_ref (cancellable);
task = g_task_new (NULL, NULL, on_finished_callback, NULL);
g_task_set_task_data (task, routing_token_context,
clear_routing_token_context);
g_task_run_in_thread (task, peek_routing_token_in_thread);
g_object_unref (task);
routing_token_context->abort_peek_source_id =
g_timeout_add (MAX_PEEK_TIME_MS,
abort_peek_routing_token,
routing_token_context);
}
```
Because the system-mode path bypasses `grd_throttler_handle_connection()`,
attacker-controlled parallel pre-auth connections can accumulate accepted
sockets and outstanding peek operations until completion or timeout. The
existing `RDP_SERVER_SOCKET_BACKLOG_COUNT = 5` and `MAX_PEEK_TIME_MS =
2000` limit each wave, but they do not prevent repeated flooding from
keeping the RDP service under resource pressure and denying legitimate
connections.
Steps to reproduce:
1. Start the daemon in system mode with RDP enabled.
2. From another host, open many parallel TCP connections to the RDP port
(default `3389`) and keep them open briefly, or send partial handshake
bytes and stop.
3. While the flood is in progress, observe a high count of connections to
port `3389`, repeated routing-token peek warnings or timeouts, and degraded
acceptance of legitimate RDP connections.
4. Stop the flood and observe recovery after the timeout window expires.
Mitigation: Until a fix is available, disable system-mode RDP where it is
not required or restrict the RDP listener to trusted management networks
using host or network firewall rules. The existing backlog and peek timeout
only reduce per-wave pressure, and `--max-parallel-connections` does not
address this path because system-mode ingress bypasses the throttler.
Proposed Fix: Route system-mode incoming sockets through the existing
throttler, then branch inside `allow_connection_cb()` so system mode still
performs routing-token peeking after throttler admission.
```diff
diff --git a/src/grd-rdp-server.c b/src/grd-rdp-server.c
@@
static gboolean
on_incoming_as_system_headless (GSocketService *service,
GSocketConnection *connection)
{
GrdRdpServer *rdp_server = GRD_RDP_SERVER (service);
-
grd_routing_token_peek_async (rdp_server,
connection,
rdp_server->cancellable,
on_routing_token_peeked);
-
+ grd_throttler_handle_connection (rdp_server->throttler, connection);
return TRUE;
}
@@
static void
allow_connection_cb (GrdThrottler *throttler,
GSocketConnection *connection,
gpointer user_data)
{
GrdRdpServer *rdp_server = GRD_RDP_SERVER (user_data);
+ GrdRuntimeMode runtime_mode =
+ grd_context_get_runtime_mode (rdp_server->context);
GrdSessionRdp *session_rdp;
+ if (runtime_mode == GRD_RUNTIME_MODE_SYSTEM)
+ {
+ grd_routing_token_peek_async (rdp_server,
+ connection,
+ rdp_server->cancellable,
+ on_routing_token_peeked);
+ return;
+ }
+
g_debug ("Creating new RDP session");
```
------
This report was generated using AI technology. Always review AI-generated
content prior to use
AI_ONLY_REPORT package: gnome-remote-desktop-49.3-1.el10 ------ Summary: Missing Connection Throttling in System-Mode RDP Server: unauthenticated flooding of the system-mode RDP listener can accumulate accepted sockets and asynchronous routing-token peek work until timeout, degrading or denying legitimate RDP access. Requirements to exploit: The `gnome-remote-desktop` system-mode daemon must be running with RDP enabled and its RDP listener reachable from the attacker. No authentication or user interaction is required; the attacker only needs to open many parallel TCP connections and keep them open briefly or send partial handshake data. Component affected: `gnome-remote-desktop` RDP ingress handling in `src/grd-rdp-server.c` and asynchronous routing-token peeking in `src/grd-rdp-routing-token.c`. Version affected: `gnome-remote-desktop-49.3-1.el10`, when run in `--system` mode with RDP enabled and the RDP listener reachable by an attacker. Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: This report is the initial private notification. CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - 7.5 (HIGH) AV:N - The vulnerable path is reachable over the network through the RDP listener when system mode is exposed. AC:L - The attack is a straightforward connection flood against a pre-auth code path; no special race or unusual precondition beyond service exposure is required. PR:N - The vulnerable behavior occurs before authentication. UI:N - No user interaction is required. S:U - The impact is confined to the `gnome-remote-desktop` service boundary. C:N - No confidentiality impact is demonstrated. I:N - No integrity impact is demonstrated. A:H - Repeated parallel connections can keep accepted sockets and async peek work outstanding until timeout, materially degrading or denying legitimate RDP service. Impact: Important. This aligns with Red Hat's Important rating because it allows unauthenticated remote users to cause denial of service against a network-facing service. It is not Critical because the demonstrated impact is availability loss rather than system compromise, and reachability depends on the system-mode RDP service being enabled and exposed. The listener backlog and two-second peek timeout reduce peak pressure but do not eliminate sustained pre-auth flooding. Embargo: no Reason: The demonstrated impact is limited to service availability in a configuration-dependent deployment, with no shown confidentiality, integrity, or code-execution impact. Immediate operational mitigations are available by disabling system-mode RDP or restricting network reachability. Acknowledgement: Aisle Research Vulnerability Details: In `grd_rdp_server_start()`, `GRD_RUNTIME_MODE_SYSTEM` connects the `incoming` signal to `on_incoming_as_system_headless()`, while non-system modes use `on_incoming()`. The two handlers differ in a way that matters for pre-auth resource control: ```c static gboolean on_incoming_as_system_headless (GSocketService *service, GSocketConnection *connection) { GrdRdpServer *rdp_server = GRD_RDP_SERVER (service); grd_routing_token_peek_async (rdp_server, connection, rdp_server->cancellable, on_routing_token_peeked); return TRUE; } static gboolean on_incoming (GSocketService *service, GSocketConnection *connection) { GrdRdpServer *rdp_server = GRD_RDP_SERVER (service); grd_throttler_handle_connection (rdp_server->throttler, connection); return TRUE; } ``` `grd_routing_token_peek_async()` retains the accepted socket in a per-connection context, schedules the peek asynchronously, and only aborts after `MAX_PEEK_TIME_MS`: ```c void grd_routing_token_peek_async (GrdRdpServer *rdp_server, GSocketConnection *connection, GCancellable *cancellable, GAsyncReadyCallback on_finished_callback) { RoutingTokenContext *routing_token_context; GTask *task; routing_token_context = g_new0 (RoutingTokenContext, 1); routing_token_context->rdp_server = rdp_server; routing_token_context->connection = g_object_ref (connection); routing_token_context->cancellable = g_cancellable_new (); routing_token_context->server_cancellable = g_object_ref (cancellable); task = g_task_new (NULL, NULL, on_finished_callback, NULL); g_task_set_task_data (task, routing_token_context, clear_routing_token_context); g_task_run_in_thread (task, peek_routing_token_in_thread); g_object_unref (task); routing_token_context->abort_peek_source_id = g_timeout_add (MAX_PEEK_TIME_MS, abort_peek_routing_token, routing_token_context); } ``` Because the system-mode path bypasses `grd_throttler_handle_connection()`, attacker-controlled parallel pre-auth connections can accumulate accepted sockets and outstanding peek operations until completion or timeout. The existing `RDP_SERVER_SOCKET_BACKLOG_COUNT = 5` and `MAX_PEEK_TIME_MS = 2000` limit each wave, but they do not prevent repeated flooding from keeping the RDP service under resource pressure and denying legitimate connections. Steps to reproduce: 1. Start the daemon in system mode with RDP enabled. 2. From another host, open many parallel TCP connections to the RDP port (default `3389`) and keep them open briefly, or send partial handshake bytes and stop. 3. While the flood is in progress, observe a high count of connections to port `3389`, repeated routing-token peek warnings or timeouts, and degraded acceptance of legitimate RDP connections. 4. Stop the flood and observe recovery after the timeout window expires. Mitigation: Until a fix is available, disable system-mode RDP where it is not required or restrict the RDP listener to trusted management networks using host or network firewall rules. The existing backlog and peek timeout only reduce per-wave pressure, and `--max-parallel-connections` does not address this path because system-mode ingress bypasses the throttler. Proposed Fix: Route system-mode incoming sockets through the existing throttler, then branch inside `allow_connection_cb()` so system mode still performs routing-token peeking after throttler admission. ```diff diff --git a/src/grd-rdp-server.c b/src/grd-rdp-server.c @@ static gboolean on_incoming_as_system_headless (GSocketService *service, GSocketConnection *connection) { GrdRdpServer *rdp_server = GRD_RDP_SERVER (service); - grd_routing_token_peek_async (rdp_server, connection, rdp_server->cancellable, on_routing_token_peeked); - + grd_throttler_handle_connection (rdp_server->throttler, connection); return TRUE; } @@ static void allow_connection_cb (GrdThrottler *throttler, GSocketConnection *connection, gpointer user_data) { GrdRdpServer *rdp_server = GRD_RDP_SERVER (user_data); + GrdRuntimeMode runtime_mode = + grd_context_get_runtime_mode (rdp_server->context); GrdSessionRdp *session_rdp; + if (runtime_mode == GRD_RUNTIME_MODE_SYSTEM) + { + grd_routing_token_peek_async (rdp_server, + connection, + rdp_server->cancellable, + on_routing_token_peeked); + return; + } + g_debug ("Creating new RDP session"); ``` ------ This report was generated using AI technology. Always review AI-generated content prior to use