diff options
author | Benjamin Peterson <benjamin@python.org> | 2014-08-28 16:30:00 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2014-08-28 16:30:00 (GMT) |
commit | 57057a6624e1b12beb61eb2f817f9de95bb7d47a (patch) | |
tree | 2029c7946952e9f0eace8f7d730f5d265d0c1bf9 /Python | |
parent | 0062d1e7f42b3036aa02701c723ff63d1d3d6028 (diff) | |
download | cpython-57057a6624e1b12beb61eb2f817f9de95bb7d47a.zip cpython-57057a6624e1b12beb61eb2f817f9de95bb7d47a.tar.gz cpython-57057a6624e1b12beb61eb2f817f9de95bb7d47a.tar.bz2 |
PEP 466: backport persistent urandom fd (closes #21305)
Patch from Alex Gaynor.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pythonrun.c | 1 | ||||
-rw-r--r-- | Python/random.c | 94 |
2 files changed, 79 insertions, 16 deletions
diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 748a63b..05bb62b 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -536,6 +536,7 @@ Py_Finalize(void) PyInt_Fini(); PyFloat_Fini(); PyDict_Fini(); + _PyRandom_Fini(); #ifdef Py_USING_UNICODE /* Cleanup Unicode implementation */ diff --git a/Python/random.c b/Python/random.c index d615923..0776bfc 100644 --- a/Python/random.c +++ b/Python/random.c @@ -118,10 +118,16 @@ vms_urandom(unsigned char *buffer, Py_ssize_t size, int raise) #if !defined(MS_WINDOWS) && !defined(__VMS) +static struct { + int fd; + dev_t st_dev; + ino_t st_ino; +} urandom_cache = { -1 }; + /* Read size bytes from /dev/urandom into buffer. Call Py_FatalError() on error. */ static void -dev_urandom_noraise(char *buffer, Py_ssize_t size) +dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size) { int fd; Py_ssize_t n; @@ -156,22 +162,56 @@ dev_urandom_python(char *buffer, Py_ssize_t size) { int fd; Py_ssize_t n; + struct stat st; if (size <= 0) return 0; - Py_BEGIN_ALLOW_THREADS - fd = open("/dev/urandom", O_RDONLY); - Py_END_ALLOW_THREADS - if (fd < 0) - { - if (errno == ENOENT || errno == ENXIO || - errno == ENODEV || errno == EACCES) - PyErr_SetString(PyExc_NotImplementedError, - "/dev/urandom (or equivalent) not found"); - else - PyErr_SetFromErrno(PyExc_OSError); - return -1; + if (urandom_cache.fd >= 0) { + /* Does the fd point to the same thing as before? (issue #21207) */ + if (fstat(urandom_cache.fd, &st) + || st.st_dev != urandom_cache.st_dev + || st.st_ino != urandom_cache.st_ino) { + /* Something changed: forget the cached fd (but don't close it, + since it probably points to something important for some + third-party code). */ + urandom_cache.fd = -1; + } + } + if (urandom_cache.fd >= 0) + fd = urandom_cache.fd; + else { + Py_BEGIN_ALLOW_THREADS + fd = open("/dev/urandom", O_RDONLY); + Py_END_ALLOW_THREADS + if (fd < 0) + { + if (errno == ENOENT || errno == ENXIO || + errno == ENODEV || errno == EACCES) + PyErr_SetString(PyExc_NotImplementedError, + "/dev/urandom (or equivalent) not found"); + else + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + if (urandom_cache.fd >= 0) { + /* urandom_fd was initialized by another thread while we were + not holding the GIL, keep it. */ + close(fd); + fd = urandom_cache.fd; + } + else { + if (fstat(fd, &st)) { + PyErr_SetFromErrno(PyExc_OSError); + close(fd); + return -1; + } + else { + urandom_cache.fd = fd; + urandom_cache.st_dev = st.st_dev; + urandom_cache.st_ino = st.st_ino; + } + } } Py_BEGIN_ALLOW_THREADS @@ -195,12 +235,21 @@ dev_urandom_python(char *buffer, Py_ssize_t size) PyErr_Format(PyExc_RuntimeError, "Failed to read %zi bytes from /dev/urandom", size); - close(fd); return -1; } - close(fd); return 0; } + +static void +dev_urandom_close(void) +{ + if (urandom_cache.fd >= 0) { + close(urandom_cache.fd); + urandom_cache.fd = -1; + } +} + + #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */ /* Fill buffer with pseudo-random bytes generated by a linear congruent @@ -305,8 +354,21 @@ _PyRandom_Init(void) # ifdef __VMS vms_urandom((unsigned char *)secret, secret_size, 0); # else - dev_urandom_noraise((char*)secret, secret_size); + dev_urandom_noraise((unsigned char*)secret, secret_size); # endif #endif } } + +void +_PyRandom_Fini(void) +{ +#ifdef MS_WINDOWS + if (hCryptProv) { + CryptReleaseContext(hCryptProv, 0); + hCryptProv = 0; + } +#else + dev_urandom_close(); +#endif +} |