Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8210549

Runtime.exec: in closeDescriptors(), use FD_CLOEXEC instead of close()

    XMLWordPrintable

    Details

    • Type: Enhancement
    • Status: Open
    • Priority: P4
    • Resolution: Unresolved
    • Affects Version/s: 12
    • Fix Version/s: tbd
    • Component/s: core-libs
    • Labels:
      None
    • Subcomponent:
    • Understanding:
      Fix Understood

      Description

      After fork()/vfork() and before exec(), the child process needs to close all inherited file descriptors apart from the stdin/out/err pipe ends.

      We do this by iterating thru all file descriptors in /proc/<pid>/fd or whatever the equivalent is on that platform. This is done using opendir(), readdir().

      We then close all these file descriptors using close().

      The problem with that technique is that we may accidentally close the file descriptor opendir() is using internally to read the directory content of /proc/<pid>/fd, thereby sawing off the branch we are sitting on. The coding does some magic to attempt to prevent this:

      <quote>
      86 /* We're trying to close all file descriptors, but opendir() might
      87 * itself be implemented using a file descriptor, and we certainly
      88 * don't want to close that while it's in use. We assume that if
      89 * opendir() is implemented using a file descriptor, then it uses
      90 * the lowest numbered file descriptor, just like open(). So we
      91 * close a couple explicitly. */
      92
      93 close(from_fd); /* for possible use by opendir() */
      94 close(from_fd + 1); /* another one for good luck */

      ...
      108 while ((dirp = readdir64(dp)) != NULL) {
      109 int fd;
      110 if (isAsciiDigit(dirp->d_name[0]) &&
      111 (fd = strtol(dirp->d_name, NULL, 10)) >= from_fd + 2)
      112 close(fd);
      113 }

      </quote>

      This workaround can be removed if, instead of outright closing the file descriptor in the loop, we were to set the file descriptor to FD_CLOEXEC. The file descriptor underlying the opendir()/readdir() call would continue to function. Closing all descriptors would be defered to the actual exec() call some milliseconds later.

      For further information, please see discussion: http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-September/055173.html

      ---

      A second issue which was brought up is that there is no sufficient error handling in the readdir() loop: readdir() may fail, which would leave the rest of the file descriptors unclosed in the child process, leading to potential difficult file io errors further down the road. There was no error handling for this kind of error.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              stuefe Thomas Stuefe
              Reporter:
              stuefe Thomas Stuefe
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated: