rust-lang / rust-lang/rust

`std::process::Command` shouldn't inherit handles on Windows by default

Open
#161,158 5 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-maybe-future-edition A-process C-bug E-needs-design O-windows T-libs
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I'm writing a Windows IPC library and I want to pass a handle to a child process, which I start manually with CreateProcess. Maybe it's a pipe, maybe it's a file, maybe it's a broker process handle. Passing a handle to a child process requires raising the "inheritable" flag for that handle, at least temporarily.

Currently, std::process::Command is implemented in such a way that all inheritable handles get inherited by the child process, without a whitelist. This means that if I start my child process in race with someone else calling Command::spawn, the handle will get inherited by both processes, not only mine. This can cause issues, such as:

  • When dropping privileges, accidentally inherited handles can grant untrusted code access to protected resources.
  • Resources are only freed when the last handle to them dies, so this can leak memory.
  • Keeping a file handle alive can make that file undeletable, causing issues both to the user and the program itself.

std::process::Command uses a mutex to ensure its own temporary handles don't get inherited by other simulataneous calls to std::process::Command, but the mutex is not exposed publicly. There are unstable features for controlling some aspects of std::process::Command, but it's unreasonable to expect that it can satisfy all uses of CreateProcess. Regardless, neither of these two APIs would help (well-behaved) libraries over FFI. std is being a bad citizen.

As a workaround, on nightly you can currently use inherit_handles to disable handle inheritance. But that needs to be done for every single use of Command in the entire program, including in library crates, which is impractical.

I would expect this to be resolved in the same fashion that GHC did in 2008, JDK in 2013, and Python in 2017: std::process::Command should be patched to white-list inheritance to handles it passes deliberately, i.e. stdio handles.

This can be implemented with the PROC_THREAD_ATTRIBUTE_HANDLE_LIST attribute passed to CreateProcess, available since Windows Vista. It would be a breaking change, since it would stop inheriting handles people might have exposed deliberately; however, at least such code can be ported to inherit_handles on nightly or to direct CreateProcess calls, and is already necessarily platform-dependent. It's also likely that such code is already broken in some multi-threaded scenarios.

This problem has been covered earlier in #38227, but it's marked as a feature request, while I think this is a bug or at least a misdesign. This also influences https://github.com/rust-lang/libs-team/issues/264 (by which point #38227 has seemingly been forgotten): that ACP asks for an API to disable inheritance, while I find that the issue is that it's enabled by default, and so the API should be redesigned to focus on enabling inheritance.

@rustbot label +O-windows +A-process +T-libs

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the Windows implementation of std::process::Command through its CreateProcess setup and review how PROC_THREAD_ATTRIBUTE_HANDLE_LIST can be supplied. Confirm the intended whitelist, including deliberately passed stdio handles, and validate that unrelated inheritable handles are excluded without breaking documented behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.