This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author vstinner
Recipients benjamin.peterson, martin.panter, serhiy.storchaka, vstinner
Date 2016-04-15.12:58:51
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1460725141.7.0.638632202912.issue26769@psf.upfronthosting.co.za>
In-reply-to
Content
By default, subprocess.Popen doesn't close file descriptors (close_fds=False by default) and so a child process inherit all file descriptors open by the parent process. See the PEP 446 for the long rationale.

I propose to partially backport the PEP 446: only make *private* file descriptors non-inheritable. The private file descriptor of os.urandom() is already marked as non-inheritable.

To be clear: my patch doesn't affect applications using fork(). Only child processes created with fork+exec (ex: using subprocess) are impacted. Since modified file descriptors are private (not accessible from the Python scope), I don't think that the change can cause any backward compatibility issue.

I'm not 100% sure that it's worth to take the risk of introducing bugs (backward incompatible change?), since it looks like very few users complained of leaked file descriptors. I'm not sure that the modified functions contain sensitive file descriptors.

--

I chose to add Python/fileutils.c (and Include/fileutils.h) to add the new functions:

   /* Try to make the file descriptor non-inheritable. Ignore errors. */
   PyAPI_FUNC(void) _Py_try_set_non_inheritable(int fd);

   /* Wrapper to fopen() which tries to make the file non-inheritable on success.
      Ignore errors on trying to set the file descriptor non-inheritable. */
   PyAPI_FUNC(FILE*) _Py_fopen(const char *path, const char *mode);

I had to modify PCbuild/pythoncore.vcxproj and Makefile.pre.in to add fileutils.c/h. I chose to mimick Python 3 Python/fileutils.c. Tell me if you prefer to put the new functions in an existing file (I don't see where such function should be put).

File descriptors made non inheritable:

* linuxaudiodev.open()
* mmap.mmap(fd, 0): this function duplicates the file descriptor, the duplicated file descriptor is set to non-inheritable
* mmap.mmap(-1, ...): on platforms without MAP_ANONYMOUS, the function opens /dev/zero, its file descriptor is set to non-inheritable
* ossaudiodev.open()
* ossaudiodev.openmixer()
* select.epoll()
* select.kqueue()
* sunaudiodev.open()

Other functions using fopen() have been modified to use _Py_fopen(): the file is closed a few lines below and not returned to the Python scope.

The patch also reuses _Py_try_set_non_inheritable(fd) in Modules/posixmodule.c and Python/random.c.

Not modified:

* _hotshot: the file descriptor can get retrieved with _hotshot.ProfilerType.fileno().
* find_module() of Python/import.c: imp.find_module() uses the FILE* to create a Python file object which is returned

Note: I don't think that os.openpty() should be modified to limit the risk of breaking the backward compatibility.

This issue is a much more generic issue than the change #10897.
History
Date User Action Args
2016-04-15 12:59:01vstinnersetrecipients: + vstinner, benjamin.peterson, martin.panter, serhiy.storchaka
2016-04-15 12:59:01vstinnersetmessageid: <1460725141.7.0.638632202912.issue26769@psf.upfronthosting.co.za>
2016-04-15 12:59:01vstinnerlinkissue26769 messages
2016-04-15 12:58:55vstinnercreate