Medium watch ✔︎ verified CVSS 5.5 chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
5.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Chromoting
DescriptionInappropriate implementation in Chromoting
ComponentChromoting
Sub-componentCrd host
Bug ClassLogic Error
Action tierwatch — dos-class only — no demonstrated corruption path — factors set by independent review by AI
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Independent review by AIConfirmed
Reviewer notes: none material-breaking. Citations verified: WorkingDirectoryIndependentServerNameFromUTF8 20-37 via base::GetTempDir (27); five accessors route through it; diff relocates to /var/lib (GetVarLibDir) and $XDG_RUNTIME_DIR. Minor: GetAgentProcessBrokerServerName (128-135) is under #if IS_MAC (line 124), so it is not actually a Linux /tmp path.
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker499154022
Fix commit1e376a204337 (chromium/src) +29/-95
CWECWE-284
CVSS vectorCVSS:3.1/AV:A/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L
CISA KEVNot listed
CreditedGoogle
Reported2026-04-03 (per vendor advisory)
Fix landed2026-04-03 (public git)
Disclosed2026-05-12
Patch gap39 days — fix public in source before the advisory

Background

CRD / Chromoting host
Chrome Remote Desktop’s host, which on Linux runs as a multi-process host (daemon as root) or a single-process host (as the login user).
Named Mojo server socket
a Unix domain socket at a well-known path that a CRD process listens on for IPC.
`WorkingDirectoryIndependentServerNameFromUTF8`
the pre-fix helper that turned a socket name into an absolute path under the temp directory.
CWE-377
insecure use of a shared temporary directory, where an unprivileged actor can pre-create or squat a predictable path.

Root Cause Analysis

Pre-fix, every CRD named-socket path on Linux was built by WorkingDirectoryIndependentServerNameFromUTF8 (components/named_mojo_ipc_server/named_mojo_ipc_util.cc:20-37), which called base::GetTempDir(&temp_dir_path) (line 27) and appended the socket name, placing sockets in /tmp with predictable names. All five accessors — GetChromotingHostServicesServerName (remoting/host/ipc_constants.cc:100-107), GetLegacyChromotingHostServicesServerName (lines 110-121), GetAgentProcessBrokerServerName (lines 128-135), GetLoginSessionReporterServerName (lines 143-150), and GetLoginSessionServerName (lines 154-160) — routed through that helper, and the legacy single-process name merely added the username to the /tmp path (lines 112-119). The invariant is “a server socket path must live in a directory writable only by a trusted principal so another local user cannot pre-create or squat it”; /tmp is world-writable, breaking it.

The fix deletes WorkingDirectoryIndependentServerNameFromUTF8 and its named_mojo_ipc_util.{cc,h} files (and their BUILD.gn entries) and introduces a new GetServerName helper in ipc_constants.cc that on Linux returns GetVarLibDir().Append(name) — i.e. /var/lib/chrome-remote-desktop/, writable only by root — for the daemon-started sockets, while GetLegacyChromotingHostServicesServerName is rewritten to place its socket under $XDG_RUNTIME_DIR via base::nix::GetXDGDirectory, writable only by the current user. This TIGHTENS the socket location from a shared, world-writable directory to per-principal directories.

Key insight
CRD created its named Mojo sockets at predictable /tmp paths (CWE-377), which another local user could squat; the fix relocates daemon sockets to root-only /var/lib/chrome-remote-desktop/ and single-process-host sockets to the user-only $XDG_RUNTIME_DIR.

Attack Path

  1. Predict the socket path A local attacker knows the fixed /tmp/chromoting.* socket name used pre-fix (named_mojo_ipc_util.cc:27-29). (inferred)
  2. Pre-create the path Before the CRD host launches, the attacker creates a file or socket at that /tmp path as a different user. (inferred)
  3. Disrupt or interpose For the single-process host, which does not run as root, the squatted path prevents or interferes with the host binding its own socket. (inferred)

Impact Assessment

A local, unprivileged user could pre-create the predictable /tmp socket paths that the CRD host expected, which the reporter frames as a denial of service most impactful to the single-process (non-root) host. The advisory classifies this as an inappropriate implementation in Chromoting, medium severity, not exploited in the wild. The scope is a local Linux attacker; no remote or cross-origin vector is shown in this material.

Changed Functions

FunctionChangeNotes
WorkingDirectoryIndependentServerNameFromUTF8
components/named_mojo_ipc_server/named_mojo_ipc_util.cc
modified
GetChromotingHostServicesServerName
remoting/host/ipc_constants.cc
modified
GetLegacyChromotingHostServicesServerName
remoting/host/ipc_constants.cc
modified
server_name
remoting/host/ipc_constants.cc
modified

Files Changed

  • components/named_mojo_ipc_server/BUILD.gn
  • components/named_mojo_ipc_server/named_mojo_ipc_util.cc
  • components/named_mojo_ipc_server/named_mojo_ipc_util.h
  • remoting/host/ipc_constants.cc

Audit Directions

  • Predictable `/tmp` endpoints
    Flag any IPC socket, lock, or state file created at a fixed path under base::GetTempDir()//tmp; prefer per-user ($XDG_RUNTIME_DIR) or privileged (/var/lib) directories.
  • Path writability by principal
    For each privileged daemon vs. per-user process, verify its endpoint directory is writable only by that principal.
  • Pre-launch squatting
    Audit startup paths where a socket/file is bound to a known name without verifying ownership or using an exclusive-create in a trusted directory.
From 1e376a204337be41d2acaec2aba69ff59a0330e4 Mon Sep 17 00:00:00 2001
From: Yuwei Huang <yuweih@chromium.org>
Date: Fri, 03 Apr 2026 16:59:04 -0700
Subject: [PATCH] [crd host] Fix named mojo server socket paths

CRD puts named mojo server sockets in /tmp, which is susceptible to
CWE-377. This CL fixes this by:

1. Putting daemon started server sockets in
   /var/lib/chrome-remote-desktop/
2. Putting other server sockets in $XDG_RUNTIME_DIR/

Also delete WorkingDirectoryIndependentServerNameFromUTF8 since nothing
uses it.

Verified with multi-process host and single-process host that WebAuthn
forwarding still WAI.

Bug: 499154022
Change-Id: Ife333f5f6b355fc450626e13e5821e6704b47afe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7729845
Reviewed-by: Joe Downing <joedow@chromium.org>
Commit-Queue: Yuwei Huang <yuweih@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1610031}
---

diff --git a/components/named_mojo_ipc_server/BUILD.gn b/components/named_mojo_ipc_server/BUILD.gn
index b4231731..f186e557 100644
--- a/components/named_mojo_ipc_server/BUILD.gn
+++ b/components/named_mojo_ipc_server/BUILD.gn
@@ -21,8 +21,6 @@
     "named_mojo_ipc_server.h",
     "named_mojo_ipc_server_client_util.cc",
     "named_mojo_ipc_server_client_util.h",
-    "named_mojo_ipc_util.cc",
-    "named_mojo_ipc_util.h",
     "named_mojo_message_pipe_server.cc",
     "named_mojo_message_pipe_server.h",
     "named_mojo_server_endpoint_connector.cc",
diff --git a/components/named_mojo_ipc_server/named_mojo_ipc_util.cc b/components/named_mojo_ipc_server/named_mojo_ipc_util.cc
deleted file mode 100644
index 8fbbde16..0000000
--- a/components/named_mojo_ipc_server/named_mojo_ipc_util.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/named_mojo_ipc_server/named_mojo_ipc_util.h"
-
-#include <string>
-#include <string_view>
-
-#include "build/build_config.h"
-
-#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#endif
-
-namespace named_mojo_ipc_server {
-
-mojo::NamedPlatformChannel::ServerName
-WorkingDirectoryIndependentServerNameFromUTF8(std::string_view name) {
-#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
-  // The channel name on non-mac POSIX (basically Linux) is the path to a unix
-  // domain socket, so it needs to be an absolute path to allow the IPC binary
-  // to be executed from any working directory.
-  base::FilePath temp_dir_path;
-  if (base::GetTempDir(&temp_dir_path)) {
-    return mojo::NamedPlatformChannel::ServerNameFromUTF8(
-        temp_dir_path.Append(name).value());
-  }
-  LOG(ERROR) << "Failed to retrieve temporary directory.";
-  // Fallback to just using |name|.
-#endif
-
-  // ServerName on other platforms (i.e. Windows and Mac) is globally unique.
-  return mojo::NamedPlatformChannel::ServerNameFromUTF8(name);
-}
-
-}  // namespace named_mojo_ipc_server
diff --git a/components/named_mojo_ipc_server/named_mojo_ipc_util.h b/components/named_mojo_ipc_server/named_mojo_ipc_util.h
deleted file mode 100644
index b7565c0..0000000
--- a/components/named_mojo_ipc_server/named_mojo_ipc_util.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_NAMED_MOJO_IPC_SERVER_NAMED_MOJO_IPC_UTIL_H_
-#define COMPONENTS_NAMED_MOJO_IPC_SERVER_NAMED_MOJO_IPC_UTIL_H_
-
-#include <string_view>
-
-#include "mojo/public/cpp/platform/named_platform_channel.h"
-
-namespace named_mojo_ipc_server {
-
-// Creates a server name that is independent to the working directory, i.e.
-// it resolves to the same channel no matter which working directory you are
-// running the binary from.
-mojo::NamedPlatformChannel::ServerName
-WorkingDirectoryIndependentServerNameFromUTF8(std::string_view name);
-
-}  // namespace named_mojo_ipc_server
-
-#endif  // COMPONENTS_NAMED_MOJO_IPC_SERVER_NAMED_MOJO_IPC_UTIL_H_
diff --git a/remoting/host/ipc_constants.cc b/remoting/host/ipc_constants.cc
index 1cd545d1..f74586d7 100644
--- a/remoting/host/ipc_constants.cc
+++ b/remoting/host/ipc_constants.cc
@@ -4,15 +4,20 @@
 
 #include "remoting/host/ipc_constants.h"
 
+#include "base/environment.h"
 #include "base/logging.h"
 #include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "components/named_mojo_ipc_server/named_mojo_ipc_util.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
 #include "remoting/base/username.h"
 
+#if BUILDFLAG(IS_LINUX)
+#include "base/nix/xdg_util.h"
+#include "remoting/base/file_path_util_linux.h"
+#endif
+
 namespace remoting {
 
 namespace {
@@ -23,21 +28,9 @@
 // might also be running.
 constexpr char kChromotingHostServicesIpcName[] =
     "chromoting.host_services_debug_mojo_ipc";
-
-#if BUILDFLAG(IS_LINUX)
-constexpr char kLegacyChromotingHostServicesIpcNamePattern[] =
-    "chromoting.%s.host_services_debug_mojo_ipc";
-#endif
-
 #else  // defined(NDEBUG)
 constexpr char kChromotingHostServicesIpcName[] =
     "chromoting.host_services_mojo_ipc";
-
-#if BUILDFLAG(IS_LINUX)
-constexpr char kLegacyChromotingHostServicesIpcNamePattern[] =
-    "chromoting.%s.host_services_mojo_ipc";
-#endif
-
 #endif
 
 #if BUILDFLAG(IS_MAC)
@@ -69,6 +62,14 @@
 
 #endif
 
+mojo::NamedPlatformChannel::ServerName GetServerName(std::string_view name) {
+#if BUILDFLAG(IS_LINUX)
+  return GetVarLibDir().Append(name).value();
+#else
+  return mojo::NamedPlatformChannel::ServerNameFromUTF8(name);
+#endif
+}
+
 }  // namespace
 
 const base::FilePath::CharType kHostBinaryName[] =
@@ -100,23 +101,25 @@
 const mojo::NamedPlatformChannel::ServerName&
 GetChromotingHostServicesServerName() {
   static const base::NoDestructor<mojo::NamedPlatformChannel::ServerName>
-      server_name(
-          named_mojo_ipc_server::WorkingDirectoryIndependentServerNameFromUTF8(
-              kChromotingHostServicesIpcName));
+      server_name(GetServerName(kChromotingHostServicesIpcName));
   return *server_name;
 }
 
 #if BUILDFLAG(IS_LINUX)
 const mojo::NamedPlatformChannel::ServerName&
 GetLegacyChromotingHostServicesServerName() {
-  // The legacy Linux single-process host is run as the login user, so we put
-  // the username in the path in case there are multiple host services running
-  // on the same machine.
   static const base::NoDestructor<mojo::NamedPlatformChannel::ServerName>
-      server_name(
-          named_mojo_ipc_server::WorkingDirectoryIndependentServerNameFromUTF8(
-              base::StringPrintf(kLegacyChromotingHostServicesIpcNamePattern,
-                                 GetUsername().c_str())));
+      server_name([]() {
+        // The legacy Linux single-process host is run as the login user, so we
+        // put it in the user's XDG_RUNTIME_DIR instead.
Loading diff…

Original Bug Report

reported by yu...@google.com

[CWE-377][linux] Don't create named mojo sockets in /tmp

In Linux, we create named mojo sockets in /tmp with well defined names, e.g. /tmp/chromoting.host_services_debug_mojo_ipc. We should stop doing this, since an adversary process could perform a denial of service attack by creating these files under a different user before the CRD host is launched. This isn’t too bad for the multi-process host, since these sockets will be replaced by the daemon process, which runs as root, but it will be a problem for the single-process host.

To solve this, we can change the paths for the multi-process host to /var/lib/chrome-remote-desktop/... and change the paths for the single-process host to $XDG_RUNTIME_DIR/.... The former is only writable by root while the latter is only writable by the current user, avoiding the problem.

View on issue tracker