Commit e0a0bd6e authored by Victor Stinner's avatar Victor Stinner

Issue #23458: On POSIX, the file descriptor kept open by os.urandom() is now

set to non inheritable
parent 0e4da40e
"""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)))
...@@ -10,6 +10,7 @@ import sys ...@@ -10,6 +10,7 @@ import sys
import signal import signal
import subprocess import subprocess
import sysconfig import sysconfig
import textwrap
import time import time
try: try:
import resource import resource
...@@ -568,6 +569,33 @@ class URandomTests (unittest.TestCase): ...@@ -568,6 +569,33 @@ class URandomTests (unittest.TestCase):
data2 = self.get_urandom_subprocess(16) data2 = self.get_urandom_subprocess(16)
self.assertNotEqual(data1, data2) 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) HAVE_GETENTROPY = (sysconfig.get_config_var('HAVE_GETENTROPY') == 1)
......
...@@ -18,6 +18,9 @@ Core and Builtins ...@@ -18,6 +18,9 @@ Core and Builtins
Library 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 - Issue #22113: struct.pack_into() now supports new buffer protocol (in
particular accepts writable memoryview). particular accepts writable memoryview).
......
...@@ -188,6 +188,7 @@ dev_urandom_python(char *buffer, Py_ssize_t size) ...@@ -188,6 +188,7 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
int fd; int fd;
Py_ssize_t n; Py_ssize_t n;
struct stat st; struct stat st;
int attr;
if (size <= 0) if (size <= 0)
return 0; return 0;
...@@ -219,6 +220,14 @@ dev_urandom_python(char *buffer, Py_ssize_t size) ...@@ -219,6 +220,14 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
return -1; 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) { if (urandom_cache.fd >= 0) {
/* urandom_fd was initialized by another thread while we were /* urandom_fd was initialized by another thread while we were
not holding the GIL, keep it. */ not holding the GIL, keep it. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment