CVE-2026-9988
Overview
Files Changed
modules/desktop_capture/linux/wayland/restore_token_manager.ccmodules/desktop_capture/linux/wayland/restore_token_manager.h
Patch
From b9f0b184cb5a487fcb4910efaf4f84483ddba284 Mon Sep 17 00:00:00 2001 From: Alexander Cooper <[email protected]> Date: Thu, 14 May 2026 13:26:42 -0700 Subject: [PATCH] Guard RestoreTokenManager add/reads with Mutex The RestoreTokenManager is a singleton who's adds and reads could be accessed by multiple threads simultaneously. To prevent any potential issues/collisions, ensure that such accesses happen behind a lock. Bug: chromium:513049286 Change-Id: I44c1c7977a6d02e1ac3fbe00e6ffc7bc22e41e46 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/472480 Reviewed-by: Mark Foltz <[email protected]> Auto-Submit: Alexander Cooper <[email protected]> Commit-Queue: Mark Foltz <[email protected]> Cr-Commit-Position: refs/heads/main@{#47711} --- diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.cc b/modules/desktop_capture/linux/wayland/restore_token_manager.cc index ff843c2..101a5af 100644 --- a/modules/desktop_capture/linux/wayland/restore_token_manager.cc +++ b/modules/desktop_capture/linux/wayland/restore_token_manager.cc @@ -13,6 +13,7 @@ #include <string> #include "modules/desktop_capture/desktop_capturer.h" +#include "rtc_base/synchronization/mutex.h" namespace webrtc { @@ -24,15 +25,18 @@ void RestoreTokenManager::AddToken(DesktopCapturer::SourceId id, const std::string& token) { + MutexLock lock(&mutex_); restore_tokens_.insert({id, token}); } std::string RestoreTokenManager::GetToken(DesktopCapturer::SourceId id) { + MutexLock lock(&mutex_); const std::string token = restore_tokens_[id]; return token; } DesktopCapturer::SourceId RestoreTokenManager::GetUnusedId() { + MutexLock lock(&mutex_); return ++last_source_id_; } diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.h b/modules/desktop_capture/linux/wayland/restore_token_manager.h index 06d3071..120a4b2 100644 --- a/modules/desktop_capture/linux/wayland/restore_token_manager.h +++ b/modules/desktop_capture/linux/wayland/restore_token_manager.h @@ -15,6 +15,8 @@ #include <unordered_map> #include "modules/desktop_capture/desktop_capturer.h" +#include "rtc_base/synchronization/mutex.h" +#include "rtc_base/thread_annotations.h" namespace webrtc { @@ -35,9 +37,11 @@ RestoreTokenManager() = default; ~RestoreTokenManager() = default; - DesktopCapturer::SourceId last_source_id_ = 0; + Mutex mutex_; + DesktopCapturer::SourceId last_source_id_ RTC_GUARDED_BY(mutex_) = 0; - std::unordered_map<DesktopCapturer::SourceId, std::string> restore_tokens_; + std::unordered_map<DesktopCapturer::SourceId, std::string> restore_tokens_ + RTC_GUARDED_BY(mutex_); }; } // namespace webrtc
Original Bug Report
Potential data race in RestoreTokenManager singleton leads to memory corruption in Browser process
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: The RestoreTokenManager singleton in WebRTC’s Wayland desktop capture module lacks any synchronization for its shared state. Concurrent mutation of an internal std::unordered_map from the Browser UI thread and dedicated capture threads can lead to heap corruption or use-after-free. This vulnerability resides in the unsandboxed browser process and is reachable from web content via screen capture requests.
Affected files:
third_party/webrtc/modules/desktop_capture/linux/wayland/restore_token_manager.ccthird_party/webrtc/modules/desktop_capture/linux/wayland/restore_token_manager.hthird_party/webrtc/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
Estimated timestamp from git blame: 2022-06-06
Description
A potential data race exists in the RestoreTokenManager class used by the PipeWire-based desktop capturer on Linux/Wayland. RestoreTokenManager is a process-wide singleton that manages restore tokens using a std::unordered_map and an integer counter, both of which are accessed without any synchronization primitives (such as mutexes or atomics).
// third_party/webrtc/modules/desktop_capture/linux/wayland/restore_token_manager.h
DesktopCapturer::SourceId last_source_id_ = 0;
std::unordered_map<DesktopCapturer::SourceId, std::string> restore_tokens_;
In Chromium, this singleton is accessed concurrently from different threads within the browser process:
- Browser UI Thread: On Linux, the UI thread pumps the global GLib main context. The
BaseCapturerPipeWireclass uses asynchronous GDBus signals to communicate with the XDG Desktop Portal. When a portal response is received (e.g., inOnScreenCastRequestResult), the callback is executed on the UI thread. This callback callsRestoreTokenManager::AddToken, which performs astd::unordered_map::insertoperation. - Desktop Capture Threads: Each capture session runs on a dedicated
desktopCaptureThread. These threads callRestoreTokenManager::GetToken(duringBaseCapturerPipeWire::Start) andRestoreTokenManager::GetUnusedId(duringBaseCapturerPipeWire::EnsureVisible).GetTokenuses theoperator[], which is a mutating operation in C++ (it inserts a default value if the key is not found).
Impact
Concurrent unsynchronized mutation of a std::unordered_map is undefined behavior. If one thread triggers a rehash of the map while another thread is accessing it, it can result in a heap use-after-free (UAF) or corruption of the map’s internal bucket structure. Since this occurs in the browser process, which is not sandboxed, it could potentially be leveraged for an escape from the renderer sandbox and arbitrary code execution with the user’s privileges.
Potential Steps to Reproduce
Note: These are suggested steps; our analysis is based on code review.
- On a Linux Wayland system, open a web page that initiates multiple desktop capture requests (e.g., multiple calls to
navigator.mediaDevices.getDisplayMedia()). - Rapidly accept the system-level capture prompts. This forces the browser to handle multiple asynchronous portal responses on the UI thread while the capture threads are simultaneously initializing or restarting capture sessions.
- Under a ThreadSanitizer (TSAN) build, a data race on
RestoreTokenManager::restore_tokens_should be detected between the UI thread and the background capture threads. - Under AddressSanitizer (ASAN), the race may manifest as a heap-use-after-free during map rehashing.
Suggested Fix
Protect all accesses to restore_tokens_ in RestoreTokenManager with a mutex (e.g., webrtc::Mutex). Additionally, last_source_id_ should be changed to a std::atomic<DesktopCapturer::SourceId> or also be protected by the mutex.
Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.