cpython: d3e8db93dc18 (original) (raw)
Mercurial > cpython
changeset 90460:d3e8db93dc18
Issue #21207: Detect when the os.urandom cached fd has been closed or replaced, and open it anew. [#21207]
Antoine Pitrou solipsis@pitrou.net | |
---|---|
date | Sat, 26 Apr 2014 14:35:19 +0200 |
parents | 9fc4a1ebe652(current diff)a66524ce9551(diff) |
children | 9ab6d13553ef |
files | Misc/NEWS |
diffstat | 3 files changed, 85 insertions(+), 10 deletions(-)[+] [-] Lib/test/test_os.py 43 Misc/NEWS 3 Python/random.c 49 |
line wrap: on
line diff
--- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -1070,6 +1070,49 @@ class URandomTests(unittest.TestCase): """ assert_python_ok('-c', code)
- def test_urandom_fd_closed(self):
# Issue #21207: urandom() should reopen its fd to /dev/urandom if[](#l1.8)
# closed.[](#l1.9)
code = """if 1:[](#l1.10)
import os[](#l1.11)
import sys[](#l1.12)
os.urandom(4)[](#l1.13)
os.closerange(3, 256)[](#l1.14)
sys.stdout.buffer.write(os.urandom(4))[](#l1.15)
"""[](#l1.16)
rc, out, err = assert_python_ok('-Sc', code)[](#l1.17)
- def test_urandom_fd_reopened(self):
# Issue #21207: urandom() should detect its fd to /dev/urandom[](#l1.20)
# changed to something else, and reopen it.[](#l1.21)
with open(support.TESTFN, 'wb') as f:[](#l1.22)
f.write(b"x" * 256)[](#l1.23)
self.addCleanup(os.unlink, support.TESTFN)[](#l1.24)
code = """if 1:[](#l1.25)
import os[](#l1.26)
import sys[](#l1.27)
os.urandom(4)[](#l1.28)
for fd in range(3, 256):[](#l1.29)
try:[](#l1.30)
os.close(fd)[](#l1.31)
except OSError:[](#l1.32)
pass[](#l1.33)
else:[](#l1.34)
# Found the urandom fd (XXX hopefully)[](#l1.35)
break[](#l1.36)
os.closerange(3, 256)[](#l1.37)
with open({TESTFN!r}, 'rb') as f:[](#l1.38)
os.dup2(f.fileno(), fd)[](#l1.39)
sys.stdout.buffer.write(os.urandom(4))[](#l1.40)
sys.stdout.buffer.write(os.urandom(4))[](#l1.41)
""".format(TESTFN=support.TESTFN)[](#l1.42)
rc, out, err = assert_python_ok('-Sc', code)[](#l1.43)
self.assertEqual(len(out), 8)[](#l1.44)
self.assertNotEqual(out[0:4], out[4:8])[](#l1.45)
rc, out2, err2 = assert_python_ok('-Sc', code)[](#l1.46)
self.assertEqual(len(out2), 8)[](#l1.47)
self.assertNotEqual(out2, out)[](#l1.48)
+ @contextlib.contextmanager def _execvpe_mockup(defpath=None):
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -57,6 +57,9 @@ Core and Builtins Library ------- +- Issue #21207: Detect when the os.urandom cached fd has been closed or
- Issue #21291: subprocess's Popen.wait() is now thread safe so that multiple threads may be calling wait() or poll() on a Popen instance at the same time without losing the Popen.returncode value.
--- a/Python/random.c +++ b/Python/random.c @@ -3,6 +3,9 @@ #include <windows.h> #else #include <fcntl.h> +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif #endif #ifdef Py_DEBUG @@ -69,7 +72,11 @@ win32_urandom(unsigned char *buffer, Py_ #ifndef MS_WINDOWS -static int urandom_fd = -1; +static struct {
+} urandom_cache = { -1 }; /* Read size bytes from /dev/urandom into buffer. Call Py_FatalError() on error. */ @@ -109,12 +116,24 @@ dev_urandom_python(char *buffer, Py_ssiz { int fd; Py_ssize_t n;
- if (urandom_cache.fd >= 0) {
/* Does the fd point to the same thing as before? (issue #21207) */[](#l3.38)
if (fstat(urandom_cache.fd, &st)[](#l3.39)
|| st.st_dev != urandom_cache.st_dev[](#l3.40)
|| st.st_ino != urandom_cache.st_ino) {[](#l3.41)
/* Something changed: forget the cached fd (but don't close it,[](#l3.42)
since it probably points to something important for some[](#l3.43)
third-party code). */[](#l3.44)
urandom_cache.fd = -1;[](#l3.45)
}[](#l3.46)
- }
- if (urandom_cache.fd >= 0)
else { Py_BEGIN_ALLOW_THREADS fd = _Py_open("/dev/urandom", O_RDONLY);fd = urandom_cache.fd;[](#l3.49)
@@ -129,14 +148,24 @@ dev_urandom_python(char *buffer, Py_ssiz PyErr_SetFromErrno(PyExc_OSError); return -1; }
if (urandom_fd >= 0) {[](#l3.57)
if (urandom_cache.fd >= 0) {[](#l3.58) /* urandom_fd was initialized by another thread while we were[](#l3.59) not holding the GIL, keep it. */[](#l3.60) close(fd);[](#l3.61)
fd = urandom_fd;[](#l3.62)
fd = urandom_cache.fd;[](#l3.63) }[](#l3.64)
else[](#l3.65)
urandom_fd = fd;[](#l3.66)
else {[](#l3.67)
if (fstat(fd, &st)) {[](#l3.68)
PyErr_SetFromErrno(PyExc_OSError);[](#l3.69)
close(fd);[](#l3.70)
return -1;[](#l3.71)
}[](#l3.72)
else {[](#l3.73)
urandom_cache.fd = fd;[](#l3.74)
urandom_cache.st_dev = st.st_dev;[](#l3.75)
urandom_cache.st_ino = st.st_ino;[](#l3.76)
}[](#l3.77)
} Py_BEGIN_ALLOW_THREADS @@ -168,9 +197,9 @@ dev_urandom_python(char *buffer, Py_ssiz static void dev_urandom_close(void) {}[](#l3.78)