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

Child process inherits all open file descriptors on linux #13

Closed
lfbayer opened this issue Dec 15, 2014 · 4 comments
Closed

Child process inherits all open file descriptors on linux #13

lfbayer opened this issue Dec 15, 2014 · 4 comments
Labels

Comments

@lfbayer
Copy link
Collaborator

lfbayer commented Dec 15, 2014

Because CLOEXEC isn't set on all the file descriptors, the child process inherits them all. Unfortunately it looks like there is no easy way to avoid this when using posix_spawnp. I haven't been able to find what the correct solution would be.

Here is an interesting thread about this issue. It sounds a bit messy, but one proposed solution seems to be to dup all file descriptors (even those that aren't open) to stdout and close them (except for stdin/stdout/stderr).

http://comp.unix.programmer.narkive.com/ZlyvRUIY/handling-the-posix-spawn-file-descriptor-hell#post57

@dano
Copy link

dano commented Feb 23, 2017

I just ran into this as well. It's causing issues because the parent process tries to restart an embedded HTTP server, but the restart fails because the child ends up taking control of the port the server was running on.

@brettwooldridge
Copy link
Owner

brettwooldridge commented Feb 23, 2017

@dano As @lfbayer noted, this is quite tricky. Because NuProcess does not use any native code (we use JNA), we don't have any control over the forked process.

The process implementation in Java uses JNI to first fork the JVM process, then the child JVM process performs a close of all file descriptors except for the pipes to the parent, and then executes the user-specified process, which replaces the child process in-situ (never to return) but inherits the file descriptors (now only the pipes to the parent).

There are two solutions:

  1. NuProcess could implement a JNI stub similar to that of the JVM. This is only needed in the case of Linux, as the MacOS and Windows branches do not have this issue. MacOS supports POSIX_SPAWN_CLOEXEC_DEFAULT, so all file handles are closed by default. On Windows we use CreateProcess and explicitly express that the child process should not inherit file handles.
  2. I haven't fully investigated this, but we could possibly invoke UnixProcess.forkAndExex() via reflection, which would leverage all of the fork/file-handle magic the JVM performs, and then on the returned file-handles make our fcntl calls to set them non-blocking.

The first is a huge pain, and a look at the comments in UNIXProcess_md.c should give you an idea of the complexity.

The second actually seems doable, though calling the private forkAndExec() via reflection would likely fail if a security domain is enabled, and possibly fail in Java 9 due to module isolation. It may be possible to call the JVM's own Java_java_lang_UNIXProcess_forkAndExec native function directly through the JNA library -- thereby avoiding all of the security issues -- and seems like the most promising of all the possibilities.

Pull requests on this later approach welcome.

@huntc
Copy link

huntc commented Sep 6, 2017

Our pet project ended up closing the file descriptors in the spawned process as recommended (Unix platform independent):

if [ -d /proc/$$/fd/ ]; then
  for descriptor_path in /proc/$$/fd/*; do
      descriptor="$(basename "$descriptor_path")"
      # Don't close stdin/stderr/stdout (-gt 2)
      if [ $descriptor -gt 2 ]; then
        exec {descriptor}<&-
      fi
  done
fi

@brettwooldridge
Copy link
Owner

Fixed in v1.2.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants