summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/python/python3
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2017-01-22 11:17:26 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-01-23 12:05:21 +0000
commita0336965aa2e2215a274ff7d2ebae8c40443b1c5 (patch)
tree3972ef50c9ced030e13fd09a1656e4902f278482 /meta/recipes-devtools/python/python3
parent6cea270c544ceb14cbd44f4e5f4e51c3a3dcb143 (diff)
downloadpoky-a0336965aa2e2215a274ff7d2ebae8c40443b1c5.tar.gz
python3: Add upstream random.c fixes for recent glibc
python3 fails to work with recent glibc versions on older hosts, giving errors like: Fatal Python error: getentropy() failed Aborted This breaks buildtools-tarball and hence eSDK. This patch backports the changes to random.c from upstream that address the problem. (From OE-Core rev: 126b2c47b1806b53fbd9a4706bc48bc7c4efd3be) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-devtools/python/python3')
-rw-r--r--meta/recipes-devtools/python/python3/upstream-random-fixes.patch721
1 files changed, 721 insertions, 0 deletions
diff --git a/meta/recipes-devtools/python/python3/upstream-random-fixes.patch b/meta/recipes-devtools/python/python3/upstream-random-fixes.patch
new file mode 100644
index 0000000000..0d9152ccd7
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/upstream-random-fixes.patch
@@ -0,0 +1,721 @@
1This patch updates random.c to match upstream python's code at revision
28125d9a8152b. This addresses various issues around problems with glibc 2.24
3and 2.25 such that python would fail to start with:
4
5[rpurdie@centos7 ~]$ /tmp/t2/sysroots/x86_64-pokysdk-linux/usr/bin/python3
6Fatal Python error: getentropy() failed
7Aborted
8
9(taken from our buildtools-tarball also breaks eSDK)
10
11Upstream-Status: Backport
12
13# HG changeset patch
14# User Victor Stinner <victor.stinner@gmail.com>
15# Date 1483957133 -3600
16# Node ID 8125d9a8152b79e712cb09c7094b9129b9bcea86
17# Parent 337461574c90281630751b6095c4e1baf380cf7d
18Issue #29157: Prefer getrandom() over getentropy()
19
20Copy and then adapt Python/random.c from default branch. Difference between 3.5
21and default branches:
22
23* Python 3.5 only uses getrandom() in non-blocking mode: flags=GRND_NONBLOCK
24* If getrandom() fails with EAGAIN: py_getrandom() immediately fails and
25 remembers that getrandom() doesn't work.
26* Python 3.5 has no _PyOS_URandomNonblock() function: _PyOS_URandom()
27 works in non-blocking mode on Python 3.5
28
29RP 2017/1/22
30
31Index: Python-3.5.2/Python/random.c
32===================================================================
33--- Python-3.5.2.orig/Python/random.c
34+++ Python-3.5.2/Python/random.c
35@@ -1,6 +1,9 @@
36 #include "Python.h"
37 #ifdef MS_WINDOWS
38 # include <windows.h>
39+/* All sample MSDN wincrypt programs include the header below. It is at least
40+ * required with Min GW. */
41+# include <wincrypt.h>
42 #else
43 # include <fcntl.h>
44 # ifdef HAVE_SYS_STAT_H
45@@ -36,10 +39,9 @@ win32_urandom_init(int raise)
46 return 0;
47
48 error:
49- if (raise)
50+ if (raise) {
51 PyErr_SetFromWindowsErr(0);
52- else
53- Py_FatalError("Failed to initialize Windows random API (CryptoGen)");
54+ }
55 return -1;
56 }
57
58@@ -52,8 +54,9 @@ win32_urandom(unsigned char *buffer, Py_
59
60 if (hCryptProv == 0)
61 {
62- if (win32_urandom_init(raise) == -1)
63+ if (win32_urandom_init(raise) == -1) {
64 return -1;
65+ }
66 }
67
68 while (size > 0)
69@@ -62,11 +65,9 @@ win32_urandom(unsigned char *buffer, Py_
70 if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer))
71 {
72 /* CryptGenRandom() failed */
73- if (raise)
74+ if (raise) {
75 PyErr_SetFromWindowsErr(0);
76- else
77- Py_FatalError("Failed to initialized the randomized hash "
78- "secret using CryptoGen)");
79+ }
80 return -1;
81 }
82 buffer += chunk;
83@@ -75,55 +76,29 @@ win32_urandom(unsigned char *buffer, Py_
84 return 0;
85 }
86
87-/* Issue #25003: Don't use getentropy() on Solaris (available since
88- * Solaris 11.3), it is blocking whereas os.urandom() should not block. */
89-#elif defined(HAVE_GETENTROPY) && !defined(sun)
90-#define PY_GETENTROPY 1
91-
92-/* Fill buffer with size pseudo-random bytes generated by getentropy().
93- Return 0 on success, or raise an exception and return -1 on error.
94-
95- If fatal is nonzero, call Py_FatalError() instead of raising an exception
96- on error. */
97-static int
98-py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
99-{
100- while (size > 0) {
101- Py_ssize_t len = Py_MIN(size, 256);
102- int res;
103-
104- if (!fatal) {
105- Py_BEGIN_ALLOW_THREADS
106- res = getentropy(buffer, len);
107- Py_END_ALLOW_THREADS
108-
109- if (res < 0) {
110- PyErr_SetFromErrno(PyExc_OSError);
111- return -1;
112- }
113- }
114- else {
115- res = getentropy(buffer, len);
116- if (res < 0)
117- Py_FatalError("getentropy() failed");
118- }
119-
120- buffer += len;
121- size -= len;
122- }
123- return 0;
124-}
125-
126-#else
127+#else /* !MS_WINDOWS */
128
129 #if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
130 #define PY_GETRANDOM 1
131
132+/* Call getrandom() to get random bytes:
133+
134+ - Return 1 on success
135+ - Return 0 if getrandom() is not available (failed with ENOSYS or EPERM),
136+ or if getrandom(GRND_NONBLOCK) failed with EAGAIN (system urandom not
137+ initialized yet).
138+ - Raise an exception (if raise is non-zero) and return -1 on error:
139+ if getrandom() failed with EINTR, raise is non-zero and the Python signal
140+ handler raised an exception, or if getrandom() failed with a different
141+ error.
142+
143+ getrandom() is retried if it failed with EINTR: interrupted by a signal. */
144 static int
145 py_getrandom(void *buffer, Py_ssize_t size, int raise)
146 {
147- /* Is getrandom() supported by the running kernel?
148- * Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
149+ /* Is getrandom() supported by the running kernel? Set to 0 if getrandom()
150+ failed with ENOSYS or EPERM. Need Linux kernel 3.17 or newer, or Solaris
151+ 11.3 or newer */
152 static int getrandom_works = 1;
153
154 /* getrandom() on Linux will block if called before the kernel has
155@@ -132,84 +107,165 @@ py_getrandom(void *buffer, Py_ssize_t si
156 * see https://bugs.python.org/issue26839. To avoid this, use the
157 * GRND_NONBLOCK flag. */
158 const int flags = GRND_NONBLOCK;
159- int n;
160+ char *dest;
161+ long n;
162
163- if (!getrandom_works)
164+ if (!getrandom_works) {
165 return 0;
166+ }
167
168+ dest = buffer;
169 while (0 < size) {
170 #ifdef sun
171 /* Issue #26735: On Solaris, getrandom() is limited to returning up
172- to 1024 bytes */
173+ to 1024 bytes. Call it multiple times if more bytes are
174+ requested. */
175 n = Py_MIN(size, 1024);
176 #else
177- n = size;
178+ n = Py_MIN(size, LONG_MAX);
179 #endif
180
181 errno = 0;
182 #ifdef HAVE_GETRANDOM
183 if (raise) {
184 Py_BEGIN_ALLOW_THREADS
185- n = getrandom(buffer, n, flags);
186+ n = getrandom(dest, n, flags);
187 Py_END_ALLOW_THREADS
188 }
189 else {
190- n = getrandom(buffer, n, flags);
191+ n = getrandom(dest, n, flags);
192 }
193 #else
194 /* On Linux, use the syscall() function because the GNU libc doesn't
195- * expose the Linux getrandom() syscall yet. See:
196- * https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
197+ expose the Linux getrandom() syscall yet. See:
198+ https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
199 if (raise) {
200 Py_BEGIN_ALLOW_THREADS
201- n = syscall(SYS_getrandom, buffer, n, flags);
202+ n = syscall(SYS_getrandom, dest, n, flags);
203 Py_END_ALLOW_THREADS
204 }
205 else {
206- n = syscall(SYS_getrandom, buffer, n, flags);
207+ n = syscall(SYS_getrandom, dest, n, flags);
208 }
209 #endif
210
211 if (n < 0) {
212- if (errno == ENOSYS) {
213+ /* ENOSYS: the syscall is not supported by the kernel.
214+ EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
215+ or something else. */
216+ if (errno == ENOSYS || errno == EPERM) {
217 getrandom_works = 0;
218 return 0;
219 }
220+
221 if (errno == EAGAIN) {
222- /* If we failed with EAGAIN, the entropy pool was
223- * uninitialized. In this case, we return failure to fall
224- * back to reading from /dev/urandom.
225- *
226- * Note: In this case the data read will not be random so
227- * should not be used for cryptographic purposes. Retaining
228- * the existing semantics for practical purposes. */
229+ /* getrandom(GRND_NONBLOCK) fails with EAGAIN if the system
230+ urandom is not initialiazed yet. In this case, fall back on
231+ reading from /dev/urandom.
232+
233+ Note: In this case the data read will not be random so
234+ should not be used for cryptographic purposes. Retaining
235+ the existing semantics for practical purposes. */
236 getrandom_works = 0;
237 return 0;
238 }
239
240 if (errno == EINTR) {
241- if (PyErr_CheckSignals()) {
242- if (!raise)
243- Py_FatalError("getrandom() interrupted by a signal");
244- return -1;
245+ if (raise) {
246+ if (PyErr_CheckSignals()) {
247+ return -1;
248+ }
249 }
250- /* retry getrandom() */
251+
252+ /* retry getrandom() if it was interrupted by a signal */
253 continue;
254 }
255
256- if (raise)
257+ if (raise) {
258 PyErr_SetFromErrno(PyExc_OSError);
259- else
260- Py_FatalError("getrandom() failed");
261+ }
262 return -1;
263 }
264
265- buffer += n;
266+ dest += n;
267 size -= n;
268 }
269 return 1;
270 }
271-#endif
272+
273+#elif defined(HAVE_GETENTROPY)
274+#define PY_GETENTROPY 1
275+
276+/* Fill buffer with size pseudo-random bytes generated by getentropy():
277+
278+ - Return 1 on success
279+ - Return 0 if getentropy() syscall is not available (failed with ENOSYS or
280+ EPERM).
281+ - Raise an exception (if raise is non-zero) and return -1 on error:
282+ if getentropy() failed with EINTR, raise is non-zero and the Python signal
283+ handler raised an exception, or if getentropy() failed with a different
284+ error.
285+
286+ getentropy() is retried if it failed with EINTR: interrupted by a signal. */
287+static int
288+py_getentropy(char *buffer, Py_ssize_t size, int raise)
289+{
290+ /* Is getentropy() supported by the running kernel? Set to 0 if
291+ getentropy() failed with ENOSYS or EPERM. */
292+ static int getentropy_works = 1;
293+
294+ if (!getentropy_works) {
295+ return 0;
296+ }
297+
298+ while (size > 0) {
299+ /* getentropy() is limited to returning up to 256 bytes. Call it
300+ multiple times if more bytes are requested. */
301+ Py_ssize_t len = Py_MIN(size, 256);
302+ int res;
303+
304+ if (raise) {
305+ Py_BEGIN_ALLOW_THREADS
306+ res = getentropy(buffer, len);
307+ Py_END_ALLOW_THREADS
308+ }
309+ else {
310+ res = getentropy(buffer, len);
311+ }
312+
313+ if (res < 0) {
314+ /* ENOSYS: the syscall is not supported by the running kernel.
315+ EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
316+ or something else. */
317+ if (errno == ENOSYS || errno == EPERM) {
318+ getentropy_works = 0;
319+ return 0;
320+ }
321+
322+ if (errno == EINTR) {
323+ if (raise) {
324+ if (PyErr_CheckSignals()) {
325+ return -1;
326+ }
327+ }
328+
329+ /* retry getentropy() if it was interrupted by a signal */
330+ continue;
331+ }
332+
333+ if (raise) {
334+ PyErr_SetFromErrno(PyExc_OSError);
335+ }
336+ return -1;
337+ }
338+
339+ buffer += len;
340+ size -= len;
341+ }
342+ return 1;
343+}
344+#endif /* defined(HAVE_GETENTROPY) && !defined(sun) */
345+
346
347 static struct {
348 int fd;
349@@ -217,127 +273,123 @@ static struct {
350 ino_t st_ino;
351 } urandom_cache = { -1 };
352
353+/* Read random bytes from the /dev/urandom device:
354
355-/* Read size bytes from /dev/urandom into buffer.
356- Call Py_FatalError() on error. */
357-static void
358-dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
359-{
360- int fd;
361- Py_ssize_t n;
362+ - Return 0 on success
363+ - Raise an exception (if raise is non-zero) and return -1 on error
364
365- assert (0 < size);
366+ Possible causes of errors:
367
368-#ifdef PY_GETRANDOM
369- if (py_getrandom(buffer, size, 0) == 1)
370- return;
371- /* getrandom() is not supported by the running kernel, fall back
372- * on reading /dev/urandom */
373-#endif
374+ - open() failed with ENOENT, ENXIO, ENODEV, EACCES: the /dev/urandom device
375+ was not found. For example, it was removed manually or not exposed in a
376+ chroot or container.
377+ - open() failed with a different error
378+ - fstat() failed
379+ - read() failed or returned 0
380
381- fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
382- if (fd < 0)
383- Py_FatalError("Failed to open /dev/urandom");
384+ read() is retried if it failed with EINTR: interrupted by a signal.
385
386- while (0 < size)
387- {
388- do {
389- n = read(fd, buffer, (size_t)size);
390- } while (n < 0 && errno == EINTR);
391- if (n <= 0)
392- {
393- /* stop on error or if read(size) returned 0 */
394- Py_FatalError("Failed to read bytes from /dev/urandom");
395- break;
396- }
397- buffer += n;
398- size -= (Py_ssize_t)n;
399- }
400- close(fd);
401-}
402+ The file descriptor of the device is kept open between calls to avoid using
403+ many file descriptors when run in parallel from multiple threads:
404+ see the issue #18756.
405+
406+ st_dev and st_ino fields of the file descriptor (from fstat()) are cached to
407+ check if the file descriptor was replaced by a different file (which is
408+ likely a bug in the application): see the issue #21207.
409
410-/* Read size bytes from /dev/urandom into buffer.
411- Return 0 on success, raise an exception and return -1 on error. */
412+ If the file descriptor was closed or replaced, open a new file descriptor
413+ but don't close the old file descriptor: it probably points to something
414+ important for some third-party code. */
415 static int
416-dev_urandom_python(char *buffer, Py_ssize_t size)
417+dev_urandom(char *buffer, Py_ssize_t size, int raise)
418 {
419 int fd;
420 Py_ssize_t n;
421- struct _Py_stat_struct st;
422-#ifdef PY_GETRANDOM
423- int res;
424-#endif
425
426- if (size <= 0)
427- return 0;
428+ if (raise) {
429+ struct _Py_stat_struct st;
430
431-#ifdef PY_GETRANDOM
432- res = py_getrandom(buffer, size, 1);
433- if (res < 0)
434- return -1;
435- if (res == 1)
436- return 0;
437- /* getrandom() is not supported by the running kernel, fall back
438- * on reading /dev/urandom */
439-#endif
440-
441- if (urandom_cache.fd >= 0) {
442- /* Does the fd point to the same thing as before? (issue #21207) */
443- if (_Py_fstat_noraise(urandom_cache.fd, &st)
444- || st.st_dev != urandom_cache.st_dev
445- || st.st_ino != urandom_cache.st_ino) {
446- /* Something changed: forget the cached fd (but don't close it,
447- since it probably points to something important for some
448- third-party code). */
449- urandom_cache.fd = -1;
450- }
451- }
452- if (urandom_cache.fd >= 0)
453- fd = urandom_cache.fd;
454- else {
455- fd = _Py_open("/dev/urandom", O_RDONLY);
456- if (fd < 0) {
457- if (errno == ENOENT || errno == ENXIO ||
458- errno == ENODEV || errno == EACCES)
459- PyErr_SetString(PyExc_NotImplementedError,
460- "/dev/urandom (or equivalent) not found");
461- /* otherwise, keep the OSError exception raised by _Py_open() */
462- return -1;
463- }
464 if (urandom_cache.fd >= 0) {
465- /* urandom_fd was initialized by another thread while we were
466- not holding the GIL, keep it. */
467- close(fd);
468- fd = urandom_cache.fd;
469+ /* Does the fd point to the same thing as before? (issue #21207) */
470+ if (_Py_fstat_noraise(urandom_cache.fd, &st)
471+ || st.st_dev != urandom_cache.st_dev
472+ || st.st_ino != urandom_cache.st_ino) {
473+ /* Something changed: forget the cached fd (but don't close it,
474+ since it probably points to something important for some
475+ third-party code). */
476+ urandom_cache.fd = -1;
477+ }
478 }
479+ if (urandom_cache.fd >= 0)
480+ fd = urandom_cache.fd;
481 else {
482- if (_Py_fstat(fd, &st)) {
483- close(fd);
484+ fd = _Py_open("/dev/urandom", O_RDONLY);
485+ if (fd < 0) {
486+ if (errno == ENOENT || errno == ENXIO ||
487+ errno == ENODEV || errno == EACCES) {
488+ PyErr_SetString(PyExc_NotImplementedError,
489+ "/dev/urandom (or equivalent) not found");
490+ }
491+ /* otherwise, keep the OSError exception raised by _Py_open() */
492 return -1;
493 }
494+ if (urandom_cache.fd >= 0) {
495+ /* urandom_fd was initialized by another thread while we were
496+ not holding the GIL, keep it. */
497+ close(fd);
498+ fd = urandom_cache.fd;
499+ }
500 else {
501- urandom_cache.fd = fd;
502- urandom_cache.st_dev = st.st_dev;
503- urandom_cache.st_ino = st.st_ino;
504+ if (_Py_fstat(fd, &st)) {
505+ close(fd);
506+ return -1;
507+ }
508+ else {
509+ urandom_cache.fd = fd;
510+ urandom_cache.st_dev = st.st_dev;
511+ urandom_cache.st_ino = st.st_ino;
512+ }
513 }
514 }
515- }
516
517- do {
518- n = _Py_read(fd, buffer, (size_t)size);
519- if (n == -1)
520- return -1;
521- if (n == 0) {
522- PyErr_Format(PyExc_RuntimeError,
523- "Failed to read %zi bytes from /dev/urandom",
524- size);
525+ do {
526+ n = _Py_read(fd, buffer, (size_t)size);
527+ if (n == -1)
528+ return -1;
529+ if (n == 0) {
530+ PyErr_Format(PyExc_RuntimeError,
531+ "Failed to read %zi bytes from /dev/urandom",
532+ size);
533+ return -1;
534+ }
535+
536+ buffer += n;
537+ size -= n;
538+ } while (0 < size);
539+ }
540+ else {
541+ fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
542+ if (fd < 0) {
543 return -1;
544 }
545
546- buffer += n;
547- size -= n;
548- } while (0 < size);
549+ while (0 < size)
550+ {
551+ do {
552+ n = read(fd, buffer, (size_t)size);
553+ } while (n < 0 && errno == EINTR);
554
555+ if (n <= 0) {
556+ /* stop on error or if read(size) returned 0 */
557+ close(fd);
558+ return -1;
559+ }
560+
561+ buffer += n;
562+ size -= n;
563+ }
564+ close(fd);
565+ }
566 return 0;
567 }
568
569@@ -349,8 +401,8 @@ dev_urandom_close(void)
570 urandom_cache.fd = -1;
571 }
572 }
573+#endif /* !MS_WINDOWS */
574
575-#endif
576
577 /* Fill buffer with pseudo-random bytes generated by a linear congruent
578 generator (LCG):
579@@ -373,29 +425,98 @@ lcg_urandom(unsigned int x0, unsigned ch
580 }
581 }
582
583-/* Fill buffer with size pseudo-random bytes from the operating system random
584- number generator (RNG). It is suitable for most cryptographic purposes
585- except long living private keys for asymmetric encryption.
586+/* Read random bytes:
587
588- Return 0 on success, raise an exception and return -1 on error. */
589-int
590-_PyOS_URandom(void *buffer, Py_ssize_t size)
591+ - Return 0 on success
592+ - Raise an exception (if raise is non-zero) and return -1 on error
593+
594+ Used sources of entropy ordered by preference, preferred source first:
595+
596+ - CryptGenRandom() on Windows
597+ - getrandom() function (ex: Linux and Solaris): call py_getrandom()
598+ - getentropy() function (ex: OpenBSD): call py_getentropy()
599+ - /dev/urandom device
600+
601+ Read from the /dev/urandom device if getrandom() or getentropy() function
602+ is not available or does not work.
603+
604+ Prefer getrandom() over getentropy() because getrandom() supports blocking
605+ and non-blocking mode and Python requires non-blocking RNG at startup to
606+ initialize its hash secret: see the PEP 524.
607+
608+ Prefer getrandom() and getentropy() over reading directly /dev/urandom
609+ because these functions don't need file descriptors and so avoid ENFILE or
610+ EMFILE errors (too many open files): see the issue #18756.
611+
612+ Only use RNG running in the kernel. They are more secure because it is
613+ harder to get the internal state of a RNG running in the kernel land than a
614+ RNG running in the user land. The kernel has a direct access to the hardware
615+ and has access to hardware RNG, they are used as entropy sources.
616+
617+ Note: the OpenSSL RAND_pseudo_bytes() function does not automatically reseed
618+ its RNG on fork(), two child processes (with the same pid) generate the same
619+ random numbers: see issue #18747. Kernel RNGs don't have this issue,
620+ they have access to good quality entropy sources.
621+
622+ If raise is zero:
623+
624+ - Don't raise an exception on error
625+ - Don't call the Python signal handler (don't call PyErr_CheckSignals()) if
626+ a function fails with EINTR: retry directly the interrupted function
627+ - Don't release the GIL to call functions.
628+*/
629+static int
630+pyurandom(void *buffer, Py_ssize_t size, int raise)
631 {
632+#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY)
633+ int res;
634+#endif
635+
636 if (size < 0) {
637- PyErr_Format(PyExc_ValueError,
638- "negative argument not allowed");
639+ if (raise) {
640+ PyErr_Format(PyExc_ValueError,
641+ "negative argument not allowed");
642+ }
643 return -1;
644 }
645- if (size == 0)
646+
647+ if (size == 0) {
648 return 0;
649+ }
650
651 #ifdef MS_WINDOWS
652- return win32_urandom((unsigned char *)buffer, size, 1);
653-#elif defined(PY_GETENTROPY)
654- return py_getentropy(buffer, size, 0);
655+ return win32_urandom((unsigned char *)buffer, size, raise);
656+#else
657+
658+#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY)
659+#ifdef PY_GETRANDOM
660+ res = py_getrandom(buffer, size, raise);
661 #else
662- return dev_urandom_python((char*)buffer, size);
663+ res = py_getentropy(buffer, size, raise);
664 #endif
665+ if (res < 0) {
666+ return -1;
667+ }
668+ if (res == 1) {
669+ return 0;
670+ }
671+ /* getrandom() or getentropy() function is not available: failed with
672+ ENOSYS, EPERM or EAGAIN. Fall back on reading from /dev/urandom. */
673+#endif
674+
675+ return dev_urandom(buffer, size, raise);
676+#endif
677+}
678+
679+/* Fill buffer with size pseudo-random bytes from the operating system random
680+ number generator (RNG). It is suitable for most cryptographic purposes
681+ except long living private keys for asymmetric encryption.
682+
683+ Return 0 on success. Raise an exception and return -1 on error. */
684+int
685+_PyOS_URandom(void *buffer, Py_ssize_t size)
686+{
687+ return pyurandom(buffer, size, 1);
688 }
689
690 void
691@@ -436,13 +557,14 @@ _PyRandom_Init(void)
692 }
693 }
694 else {
695-#ifdef MS_WINDOWS
696- (void)win32_urandom(secret, secret_size, 0);
697-#elif defined(PY_GETENTROPY)
698- (void)py_getentropy(secret, secret_size, 1);
699-#else
700- dev_urandom_noraise(secret, secret_size);
701-#endif
702+ int res;
703+
704+ /* _PyRandom_Init() is called very early in the Python initialization
705+ and so exceptions cannot be used (use raise=0). */
706+ res = pyurandom(secret, secret_size, 0);
707+ if (res < 0) {
708+ Py_FatalError("failed to get random numbers to initialize Python");
709+ }
710 }
711 }
712
713@@ -454,8 +576,6 @@ _PyRandom_Fini(void)
714 CryptReleaseContext(hCryptProv, 0);
715 hCryptProv = 0;
716 }
717-#elif defined(PY_GETENTROPY)
718- /* nothing to clean */
719 #else
720 dev_urandom_close();
721 #endif