Chromium Handle Duplication on Microsoft Windows
This article provides a technical overview of how the Chromium web
browser manages the duplication of operating system handles across
different processes on Microsoft Windows. Because Chromium relies on a
strict multi-process architecture for security and stability,
unprivileged child processes cannot directly access most system
resources. To bypass this limitation safely, Chromium uses a privileged
broker process, the Windows DuplicateHandle API, and its
Mojo Inter-Process Communication (IPC) system to seamlessly transfer
resource handles—such as files, shared memory, and synchronization
objects—across process boundaries without compromising the security
sandbox.
The Sandbox Constraint
Chromium separates its workload into multiple processes: a single privileged Browser process and multiple unprivileged child processes (such as Renderers, GPU, and Utility processes). On Windows, these child processes operate inside a restrictive security sandbox. They run with low integrity levels and restricted security tokens, meaning the Windows kernel blocks them from opening files, creating shared memory regions, or accessing hardware directly.
When a sandboxed Renderer process needs to read a file or share a
memory buffer with the GPU process, it cannot create the Windows
HANDLE itself. Instead, the resource must be created
elsewhere and transferred into the Renderer's process space.
The Windows
DuplicateHandle API
On Microsoft Windows, a HANDLE is not a global pointer;
it is an index into a process-specific handle table managed by the OS
kernel. Handle 0x100 in the Browser process means something
entirely different than Handle 0x100 in a Renderer
process.
To share an underlying kernel object (like a file or memory section)
between two processes, Windows provides the DuplicateHandle
system call. This function takes a handle from a source process, creates
a new entry in the target process's handle table pointing to the same
kernel object, and returns the new handle value.
To execute DuplicateHandle, the calling process must
possess handles to both the source and target processes with the
PROCESS_DUP_HANDLE access right.
The Browser Process as a Broker
For security reasons, sandboxed processes do not have
PROCESS_DUP_HANDLE permissions for other processes. If a
Renderer had this permission, a compromised Renderer could inject
handles into other processes or exhaust system resources.
Chromium solves this by designating the main Browser process as the
"Broker." When the Browser process spawns a child process, it retains a
privileged process handle to that child. Because the Browser process has
PROCESS_DUP_HANDLE rights to all its children, it acts as
the central authority for moving handles around:
- Browser to Child: The Browser creates a resource
handle, calls
DuplicateHandletargeting the child process, and sends the resulting numeric handle value to the child over an IPC message. - Child to Browser: The child sends the numeric value
of its local handle to the Browser via IPC. The Browser then calls
DuplicateHandle, using the child as the source and itself as the target. - Child to Child (e.g., Renderer to GPU): The source
child sends a request to the Browser broker. The Browser uses
DuplicateHandleto copy the handle directly from the source child's handle table into the destination child's handle table, then informs the destination child of the new handle value.
Mojo IPC Integration
Developers working on Chromium rarely call
DuplicateHandle manually. Instead, handle duplication is
abstracted away by Mojo, Chromium’s IPC system.
When a developer wants to send a Windows handle across processes,
they wrap the native Windows HANDLE into a C++ object
called mojo::PlatformHandle. When this object is attached
to a Mojo message and sent over a pipe, Mojo’s underlying transport
layer (ChannelWin) intercepts it:
- Mojo automatically strips the raw handle from the payload.
- If the sender is the Broker, Mojo immediately calls
DuplicateHandleinto the target process. - If the sender is a sandboxed process talking to another sandboxed
process, Mojo transparently routes the message through the Broker
process, which performs the
DuplicateHandleoperation before forwarding the message to the final destination. - Upon arrival in the target process, Mojo reconstructs the
mojo::PlatformHandlewith the newly duplicated handle value, making it immediately usable by the receiving code.
Lifecycle Management and Security
Managing handle lifetimes across processes is critical to prevent
resource leaks and security vulnerabilities. Chromium enforces strict
ownership rules using RAII (Resource Acquisition Is Initialization)
wrappers, specifically base::win::ScopedHandle.
When a handle is duplicated for IPC, the
DUPLICATE_CLOSE_SOURCE flag is frequently used if the
sending process no longer needs the resource. This tells the Windows
kernel to automatically close the handle in the source process as soon
as it is duplicated into the target, ensuring only one process owns the
handle at any time.
Furthermore, Chromium uses DuplicateHandle to enforce
the principle of least privilege. When the Browser creates a shared
memory region, it has full read-write access. Before duplicating that
handle into an untrusted Renderer process, the Browser can modify the
dwDesiredAccess parameter in DuplicateHandle
to strip write permissions. The Renderer receives a valid handle to the
exact same memory space, but the Windows kernel will strictly enforce it
as read-only.