Skip to content

I/O safety of dup2 with an imminent exec #497

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

Open
sunfishcode opened this issue Jan 4, 2023 · 5 comments
Open

I/O safety of dup2 with an imminent exec #497

sunfishcode opened this issue Jan 4, 2023 · 5 comments
Labels
question Further information is requested

Comments

@sunfishcode
Copy link
Member

One of the main use cases for dup2 is to pass fds to an exec at arbitrarily chosen positions. I/O safety considers that to be forgery. But it's an important use case, and if you somehow know there will be no further I/O on any other fd, including on other threads, you can make it work reliably in practice. Is there a way we can accommodate this in I/O safety?

A related question: is it possible to call fork in Rust at all? POSIX says the child can only call async-signal-safe functions, but Rust doesn't currently guarantee that anything is async-signal-safe.

One option would be to say that these situations are too unwieldy, and that instead of trying to define soundness requirements for fork and exec, we should instead define "spawn" and "replace the current process" primitives which can be passed a list of fds to pass to exec, so that we can do all the dup2's etc in specially blessed code.

@notgull
Copy link
Contributor

notgull commented Jan 4, 2023

I think we can expose fork(), but unsafe and with the following notes:

  • You can't call anything from the standard library, even libcore, since there's no guarantees of whether or not it's signal safe.
  • In fact, you should really only call libc or rustix functions that explicitly say that they're channel safe.
  • Don't do anything that would allocate or deallocate memory.
  • Make sure you don't trip over the other processes' memory space or open file descriptors.

@sunfishcode
Copy link
Member Author

The Rust compiler and Rustix both regularly call things in libcore.

@sunfishcode
Copy link
Member Author

Note about dup2: POSIX says that implemtations can have extra fds open that user code doesn't know about, so user code can't just dup2 to arbitrary integer values even when there's an imminent exec:

https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html#

@LingMan
Copy link
Contributor

LingMan commented Mar 2, 2023

A related question: is it possible to call fork in Rust at all? POSIX says the child can only call async-signal-safe functions, but Rust doesn't currently guarantee that anything is async-signal-safe.

There's pre_exec on the std::os::unix::process::CommandExt trait.

@sunfishcode
Copy link
Member Author

There's pre_exec on the std::os::unix::process::CommandExt trait.

Wow, that's a scary function. I don't think it's possible to use it safely unless you know how every line of code you run inside that, transitively, is implemented, including all the standard library functions, and any compiler builtins that get called implicitly.

@sunfishcode sunfishcode added the question Further information is requested label Jul 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants