[Python-checkins] cpython (2.7): Issue #23458: On POSIX, the file descriptor kept open by os.urandom() is now

victor.stinner python-checkins at python.org
Tue Feb 24 14:32:46 CET 2015


https://hg.python.org/cpython/rev/88a99ea8a4cf
changeset:   94736:88a99ea8a4cf
branch:      2.7
parent:      94730:2b8c5ed7b38b
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Tue Feb 24 14:30:43 2015 +0100
summary:
  Issue #23458: On POSIX, the file descriptor kept open by os.urandom() is now
set to non inheritable

files:
  Lib/test/subprocessdata/fd_status.py |  32 ++++++++++++++++
  Lib/test/test_os.py                  |  28 ++++++++++++++
  Misc/NEWS                            |   3 +
  Python/random.c                      |   9 ++++
  4 files changed, 72 insertions(+), 0 deletions(-)


diff --git a/Lib/test/subprocessdata/fd_status.py b/Lib/test/subprocessdata/fd_status.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/subprocessdata/fd_status.py
@@ -0,0 +1,32 @@
+"""When called as a script, print a comma-separated list of the open
+file descriptors on stdout.
+
+Usage:
+fd_stats.py: check all file descriptors
+fd_status.py fd1 fd2 ...: check only specified file descriptors
+"""
+
+import errno
+import os
+import stat
+import sys
+
+if __name__ == "__main__":
+    fds = []
+    if len(sys.argv) == 1:
+        try:
+            _MAXFD = os.sysconf("SC_OPEN_MAX")
+        except:
+            _MAXFD = 256
+        test_fds = range(0, _MAXFD)
+    else:
+        test_fds = map(int, sys.argv[1:])
+    for fd in test_fds:
+        try:
+            st = os.fstat(fd)
+        except OSError as e:
+            if e.errno == errno.EBADF:
+                continue
+            raise
+        fds.append(fd)
+    print(','.join(map(str, fds)))
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -10,6 +10,7 @@
 import signal
 import subprocess
 import sysconfig
+import textwrap
 import time
 try:
     import resource
@@ -568,6 +569,33 @@
         data2 = self.get_urandom_subprocess(16)
         self.assertNotEqual(data1, data2)
 
+    def test_urandom_fd_non_inheritable(self):
+        # Issue #23458: os.urandom() keeps a file descriptor open, but it
+        # must be non inheritable
+        fd_status = test_support.findfile("fd_status.py", subdir="subprocessdata")
+
+        # Need a two subprocesses because the Python test suite opens other
+        # inheritable file descriptors, whereas the test is specific to
+        # os.urandom() file descriptor
+        code = textwrap.dedent("""
+            import os
+            import subprocess
+            import sys
+
+            # Ensure that the /dev/urandom file descriptor is open
+            os.urandom(1)
+
+            exitcode = subprocess.call([sys.executable, %r],
+                                       close_fds=False)
+            sys.exit(exitcode)
+        """ % fd_status)
+
+        proc = subprocess.Popen([sys.executable, "-c", code],
+                                stdout=subprocess.PIPE, close_fds=True)
+        output, error = proc.communicate()
+        open_fds = set(map(int, output.rstrip().split(',')))
+        self.assertEqual(open_fds - set(range(3)), set())
+
 
 HAVE_GETENTROPY = (sysconfig.get_config_var('HAVE_GETENTROPY') == 1)
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -18,6 +18,9 @@
 Library
 -------
 
+- Issue #23458: On POSIX, the file descriptor kept open by os.urandom() is now
+  set to non inheritable
+
 - Issue #22113: struct.pack_into() now supports new buffer protocol (in
   particular accepts writable memoryview).
 
diff --git a/Python/random.c b/Python/random.c
--- a/Python/random.c
+++ b/Python/random.c
@@ -188,6 +188,7 @@
     int fd;
     Py_ssize_t n;
     struct stat st;
+    int attr;
 
     if (size <= 0)
         return 0;
@@ -219,6 +220,14 @@
                 PyErr_SetFromErrno(PyExc_OSError);
             return -1;
         }
+
+        /* try to make the file descriptor non-inheritable, ignore errors */
+        attr = fcntl(fd, F_GETFD);
+        if (attr >= 0) {
+            attr |= FD_CLOEXEC;
+            (void)fcntl(fd, F_SETFD, attr);
+        }
+
         if (urandom_cache.fd >= 0) {
             /* urandom_fd was initialized by another thread while we were
                not holding the GIL, keep it. */

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list