Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new inherit_handles flag to CommandExt trait #115501

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

michaelvanstraten
Copy link
Contributor

@michaelvanstraten michaelvanstraten commented Sep 3, 2023

This PR adds a new flag to the CommandExt trait to set whether to inherit the handles of the calling process ([ref][1]).

This is necessary when, for example, spawning a process with a pseudoconsole attached.

r? @ChrisDenton

ACP: rust-lang/libs-team#264
[1]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw

@rustbot rustbot added O-windows Operating system: Windows S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Sep 3, 2023
@rust-log-analyzer
Copy link
Collaborator

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
GITHUB_ACTION=__run_7
GITHUB_ACTIONS=true
GITHUB_ACTION_REF=
GITHUB_ACTION_REPOSITORY=
GITHUB_ACTOR=michaelvanstraten
GITHUB_API_URL=https://api.github.com
GITHUB_BASE_REF=master
GITHUB_ENV=/home/runner/work/_temp/_runner_file_commands/set_env_95a84762-0ce6-46fd-8ec8-7fec7a2a6980
GITHUB_EVENT_NAME=pull_request
GITHUB_EVENT_NAME=pull_request
GITHUB_EVENT_PATH=/home/runner/work/_temp/_github_workflow/event.json
GITHUB_GRAPHQL_URL=https://api.github.com/graphql
GITHUB_HEAD_REF=set_inherit_handles
GITHUB_JOB=pr
GITHUB_PATH=/home/runner/work/_temp/_runner_file_commands/add_path_95a84762-0ce6-46fd-8ec8-7fec7a2a6980
GITHUB_REF=refs/pull/115501/merge
GITHUB_REF_NAME=115501/merge
GITHUB_REF_PROTECTED=false
---
GITHUB_SERVER_URL=https://github.com
GITHUB_SHA=fc029cc3fa60716113328636886057582cfea2bf
GITHUB_STATE=/home/runner/work/_temp/_runner_file_commands/save_state_95a84762-0ce6-46fd-8ec8-7fec7a2a6980
GITHUB_STEP_SUMMARY=/home/runner/work/_temp/_runner_file_commands/step_summary_95a84762-0ce6-46fd-8ec8-7fec7a2a6980
GITHUB_TRIGGERING_ACTOR=michaelvanstraten
GITHUB_WORKFLOW_REF=rust-lang/rust/.github/workflows/ci.yml@refs/pull/115501/merge
GITHUB_WORKFLOW_SHA=fc029cc3fa60716113328636886057582cfea2bf
GITHUB_WORKSPACE=/home/runner/work/rust/rust
GOROOT_1_18_X64=/opt/hostedtoolcache/go/1.18.10/x64
---
    Checking object v0.32.0
    Checking hashbrown v0.14.0
    Checking miniz_oxide v0.7.1
    Checking addr2line v0.21.0
error[E0545]: `issue` must be a non-zero numeric string or "none"
   --> library/std/src/os/windows/process.rs:264:72
    |
264 |     #[unstable(feature = "windows_process_extensions_inherit_handles", issue = "")]
    |                                                                                |
    |                                                                                cannot parse integer from empty string

error: method has missing stability attribute
error: method has missing stability attribute
   --> library/std/src/os/windows/process.rs:265:5
    |
265 |     fn inherit_handles(&mut self, inherit_handles: bool) -> &mut process::Command;

For more information about this error, try `rustc --explain E0545`.
error: could not compile `std` (lib) due to 2 previous errors
Build completed unsuccessfully in 0:00:12

@michaelvanstraten
Copy link
Contributor Author

Should this have a stabilization issue attached to it?

@the8472
Copy link
Member

the8472 commented Sep 3, 2023

First you should create an API change proposal to see if libs-api wants it.

@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Sep 3, 2023

I recently changed the exact same interface and didn't need an ACP, is this really required here?

@the8472
Copy link
Member

the8472 commented Sep 3, 2023

No, not required

Note that an ACP is not strictly required: you can just go ahead and submit a pull request with an implementation of your proposed API, with the risk of wasted effort if the library team ends up rejecting this feature. However do note that this risk is always present even if an ACP is accepted, as the library team can end up rejecting a feature in the later parts of the stabilization process.

@the8472
Copy link
Member

the8472 commented Sep 3, 2023

Anyway, does windows have an equivalent to posix_spawn_file_actions_adddup2? I.e. a way to provide a list of descriptors that should be explicitly passed to the child process rather than relying on inheritance flags on handles?

Inheritance is questionable in multi-threaded programs because different command-spawning actions may want to pass different files to the child.

Also, how does one communicate to a child that a specific handle is available? On unix we've run into issues defining IO safety when passing ownership through the environment. Are there better ways to send handles to another process?

This is necessary when, for example, spawning a process with a pseudoconsole attached.

Alternatively, can we limit this to passing a set of well-defined handles?

@ChrisDenton
Copy link
Member

ChrisDenton commented Sep 3, 2023

This is necessary when, for example, spawning a process with a pseudoconsole attached.

It is not necessary when creating a pseudoconsole to disable handle inheritance. Doing so does however allow us to skip the mutex we currently use.

Anyway, does windows have an equivalent to posix_spawn_file_actions_adddup2? I.e. a way to provide a list of descriptors that should be explicitly passed to the child process rather than relying on inheritance flags on handles?

Yes. You need to set inherit_handles to true and then set the PROC_THREAD_ATTRIBUTE_HANDLE_LIST attribute. Rust should have been doing this from the start, imho, but not sure if we can change it now.

I recently changed the exact same interface and didn't need an ACP, is this really required here?

The reason the previous API change didn't require an ACP was because the change was already accepted under an older system (and I asked privately if this was still OK). A new API would need an ACP.

@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Sep 3, 2023

It is not necessary when creating a pseudoconsole to disable handle inheritance. Doing so does however allow us to skip the mutex we currently use.

Do you know why all of them set bInheritHandles to false? I have look at a dozenth reference implementation so far and all do so.

@michaelvanstraten
Copy link
Contributor Author

Okay I just tested it, indeed not necessary to set bInheritHandles.

Would this still be a useful extension to the CommandExt trait?

@ChrisDenton
Copy link
Member

ChrisDenton commented Sep 3, 2023

Do you know why all of them set bInheritHandles to false? I have look at a dozenth reference implementation so far and all do so.

The most likely the simplest explanation is "because the example code does". But there are good reasons to disable handle inheritance when it's not needed: inheriting unnecessary handles is pointless and also prevents kernel objects from being cleaned up. In the worst case it may also allow the child process to mess with the handles it inherits, though it would have to find them first.

Would this still be a useful extension to the CommandExt trait?

I think it would for the above reasons.

@michaelvanstraten
Copy link
Contributor Author

I don't know if windows has the concept of confidential handles but preventing the child from acquiring those handles could improve security of spawning commands.

@michaelvanstraten
Copy link
Contributor Author

Okay, just found the following list in the windows documentation:

Processes can inherit or duplicate handles to the following types of objects:

  • Access Token
  • Communications device
  • Console input
  • Console screen buffer
  • Desktop
  • Directory
  • Event
  • File
  • File mapping
  • Job
  • Mailslot
  • Mutex
  • Pipe
  • Process
  • Registry key
  • Semaphore
  • Socket
  • Thread
  • Timer

@michaelvanstraten
Copy link
Contributor Author

rust-lang/libs-team#264

@michaelvanstraten
Copy link
Contributor Author

@ChrisDenton should I message somebody about this in rust internals?

@ChrisDenton
Copy link
Member

You don't need to do anything other than be patient 🙂. ACPs are discussed in a weekly meeting (time permitting).

@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Sep 5, 2023

ACPs are discussed in a weekly meeting (time permitting).

Sorry, didn't know that.

@Dylan-DPC Dylan-DPC added S-waiting-on-ACP Status: PR has an ACP and is waiting for the ACP to complete. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 6, 2023
@bors
Copy link
Contributor

bors commented Jan 13, 2024

☔ The latest upstream changes (presumably #117285) made this pull request unmergeable. Please resolve the merge conflicts.

@bors bors added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jan 13, 2024
@Dylan-DPC Dylan-DPC removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Feb 14, 2024
@pixmaip
Copy link

pixmaip commented Sep 25, 2024

Hi everyone,
I am unearthing this discussion as this proposed API can be mandatory in some cases.

While handle inheritance can be selectively configured using the PROC_THREAD_ATTRIBUTE_HANDLE_LIST attribute, in the case of protected processes, the bInheritHandles parameter still needs to be set to FALSE in all cases, otherwise the CreateProcess call will fail.

This effectively means that Rust programs running as PPL currently cannot spawn non-protected processes using the standard library, as the spawn will always fail, as deccribed in the Microsoft documentation of CreateProcess:

Protected Process Light (PPL) processes: The generic handle inheritance is blocked when a PPL process creates a non-PPL process since PROCESS_DUP_HANDLE is not allowed from a non-PPL process to a PPL process. See Process Security and Access Rights

@michaelvanstraten
Copy link
Contributor Author

I have an exam on Monday but after that I should be able to work on this.

@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Oct 1, 2024

@pixmaip would the following suggestion aid your need?
rust-lang/libs-team#264 (comment)

@pixmaip
Copy link

pixmaip commented Oct 1, 2024

No, the suggestion you mentioned might be good for most usecases, but when running processes as PPL, passing a list of handles to inherit cannot be done.
For the CreateProcess API to succeed, you need to have bInheritHandles set to FALSE.

This is because PPL processes are inherently prevented by the system from leaking handles to non-protected processes, so Windows does not allow it.

Note that setting bInheritHandles to FALSE will automatically prevent standard handles to work properly, meaning that stdin will not be passed through to the child process, and stdout/err will not output any data. The only possible "interaction" with the child process is through its exit status.

@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Oct 1, 2024

Okay, then this should mergable independently of #123604. Please also raise your issue with the proposed solution over at rust-lang/libs-team#264 so it can be re-discussed by the lib team or maybe @ChrisDenton you can note it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
O-windows Operating system: Windows S-waiting-on-ACP Status: PR has an ACP and is waiting for the ACP to complete. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants