cpython: 1fc32bf069ff (original) (raw)
Mercurial > cpython
changeset 95042:1fc32bf069ff
Issue #22181: On Linux, os.urandom() now uses the new getrandom() syscall if available, syscall introduced in the Linux kernel 3.17. It is more reliable and more secure, because it avoids the need of a file descriptor and waits until the kernel has enough entropy. [#22181]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Wed, 18 Mar 2015 14:39:33 +0100 |
parents | 304f8011df9f |
children | f7c129f63922 |
files | Misc/NEWS Python/random.c |
diffstat | 2 files changed, 89 insertions(+), 6 deletions(-)[+] [-] Misc/NEWS 5 Python/random.c 90 |
line wrap: on
line diff
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,11 @@ Core and Builtins Library ------- +- Issue #22181: On Linux, os.urandom() now uses the new getrandom() syscall if
- available, syscall introduced in the Linux kernel 3.17. It is more reliable
- and more secure, because it avoids the need of a file descriptor and waits
- until the kernel has enough entropy. +
- Issue #2211: Updated the implementation of the http.cookies.Morsel class. Setting attributes key, value and coded_value directly now is deprecated. update() and setdefault() now transform and check keys. Comparing for
--- a/Python/random.c +++ b/Python/random.c @@ -1,11 +1,17 @@ #include "Python.h" #ifdef MS_WINDOWS -#include <windows.h> +# include <windows.h> #else -#include <fcntl.h> -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif +# include <fcntl.h> +# ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +# endif +# ifdef HAVE_SYS_SYSCALL_H +# include <sys/syscall.h> +# if defined(linux) && defined(SYS_getrandom) +# define HAVE_GETRANDOM +# endif +# endif #endif #ifdef Py_DEBUG @@ -94,13 +100,65 @@ py_getentropy(unsigned char buffer, Py_ return 0; } -#else +#else / !HAVE_GETENTROPY */ + +#ifdef HAVE_GETRANDOM +static int +py_getrandom(void *buffer, Py_ssize_t size, int raise) +{
- /* is getrandom() supported by the running kernel?
* need Linux kernel 3.17 or later */[](#l2.38)
- static int getrandom_works = 1;
- /* Use /dev/urandom, block if the kernel has no entropy */
- const int flags = 0;
- int n;
- while (0 < size) {
errno = 0;[](#l2.48)
/* the libc doesn't expose getrandom() yet, see:[](#l2.49)
* https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */[](#l2.50)
n = syscall(SYS_getrandom, buffer, size, flags);[](#l2.51)
if (n < 0) {[](#l2.52)
if (errno == ENOSYS) {[](#l2.53)
getrandom_works = 0;[](#l2.54)
return 0;[](#l2.55)
}[](#l2.56)
if (errno == EINTR) {[](#l2.58)
/* Note: EINTR should not occur with flags=0 */[](#l2.59)
if (PyErr_CheckSignals()) {[](#l2.60)
if (!raise)[](#l2.61)
Py_FatalError("getrandom() interrupted by a signal");[](#l2.62)
return -1;[](#l2.63)
}[](#l2.64)
/* retry getrandom() */[](#l2.65)
continue;[](#l2.66)
}[](#l2.67)
if (raise)[](#l2.69)
PyErr_SetFromErrno(PyExc_OSError);[](#l2.70)
else[](#l2.71)
Py_FatalError("getrandom() failed");[](#l2.72)
return -1;[](#l2.73)
}[](#l2.74)
+} +#endif + 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 @@ -115,6 +173,13 @@ dev_urandom_noraise(unsigned char *buffe if (fd < 0) Py_FatalError("Failed to open /dev/urandom"); +#ifdef HAVE_GETRANDOM
- if (py_getrandom(buffer, size, 0) == 1)
return;[](#l2.99)
- /* getrandom() is not supported by the running kernel, fall back
* on reading /dev/urandom */[](#l2.101)
+#endif + while (0 < size) { do { @@ -140,10 +205,23 @@ dev_urandom_python(char *buffer, Py_ssiz int fd; Py_ssize_t n; struct _Py_stat_struct st; +#ifdef HAVE_GETRANDOM
+#endif if (size <= 0) return 0; +#ifdef HAVE_GETRANDOM
- res = py_getrandom(buffer, size, 1);
- if (res < 0)
return -1;[](#l2.121)
- if (res == 1)
return 0;[](#l2.123)
- /* getrandom() is not supported by the running kernel, fall back
* on reading /dev/urandom */[](#l2.125)
+#endif + if (urandom_cache.fd >= 0) { /* Does the fd point to the same thing as before? (issue #21207) */ if (_Py_fstat(urandom_cache.fd, &st)