1#include "Python.h"
2#include "pycore_initconfig.h"
3#ifdef MS_WINDOWS
4# include <windows.h>
5/* All sample MSDN wincrypt programs include the header below. It is at least
6 * required with Min GW. */
7# include <wincrypt.h>
8#else
9# include <fcntl.h>
10# ifdef HAVE_SYS_STAT_H
11# include <sys/stat.h>
12# endif
13# ifdef HAVE_LINUX_RANDOM_H
14# include <linux/random.h>
15# endif
16# if defined(HAVE_SYS_RANDOM_H) && (defined(HAVE_GETRANDOM) || defined(HAVE_GETENTROPY))
17# include <sys/random.h>
18# endif
19# if !defined(HAVE_GETRANDOM) && defined(HAVE_GETRANDOM_SYSCALL)
20# include <sys/syscall.h>
21# endif
22#endif
23
24#ifdef _Py_MEMORY_SANITIZER
25# include <sanitizer/msan_interface.h>
26#endif
27
28#if defined(__APPLE__) && defined(__has_builtin)
29# if __has_builtin(__builtin_available)
30# define HAVE_GETENTRYPY_GETRANDOM_RUNTIME __builtin_available(macOS 10.12, iOS 10.10, tvOS 10.0, watchOS 3.0, *)
31# endif
32#endif
33#ifndef HAVE_GETENTRYPY_GETRANDOM_RUNTIME
34# define HAVE_GETENTRYPY_GETRANDOM_RUNTIME 1
35#endif
36
37
38#ifdef Py_DEBUG
39int _Py_HashSecret_Initialized = 0;
40#else
41static int _Py_HashSecret_Initialized = 0;
42#endif
43
44#ifdef MS_WINDOWS
45static HCRYPTPROV hCryptProv = 0;
46
47static int
48win32_urandom_init(int raise)
49{
50 /* Acquire context */
51 if (!CryptAcquireContextW(&hCryptProv, NULL, NULL,
52 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
53 goto error;
54
55 return 0;
56
57error:
58 if (raise) {
59 PyErr_SetFromWindowsErr(0);
60 }
61 return -1;
62}
63
64/* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
65 API. Return 0 on success, or raise an exception and return -1 on error. */
66static int
67win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
68{
69 if (hCryptProv == 0)
70 {
71 if (win32_urandom_init(raise) == -1) {
72 return -1;
73 }
74 }
75
76 while (size > 0)
77 {
78 DWORD chunk = (DWORD)Py_MIN(size, PY_DWORD_MAX);
79 if (!CryptGenRandom(hCryptProv, chunk, buffer))
80 {
81 /* CryptGenRandom() failed */
82 if (raise) {
83 PyErr_SetFromWindowsErr(0);
84 }
85 return -1;
86 }
87 buffer += chunk;
88 size -= chunk;
89 }
90 return 0;
91}
92
93#else /* !MS_WINDOWS */
94
95#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
96#define PY_GETRANDOM 1
97
98/* Call getrandom() to get random bytes:
99
100 - Return 1 on success
101 - Return 0 if getrandom() is not available (failed with ENOSYS or EPERM),
102 or if getrandom(GRND_NONBLOCK) failed with EAGAIN (system urandom not
103 initialized yet) and raise=0.
104 - Raise an exception (if raise is non-zero) and return -1 on error:
105 if getrandom() failed with EINTR, raise is non-zero and the Python signal
106 handler raised an exception, or if getrandom() failed with a different
107 error.
108
109 getrandom() is retried if it failed with EINTR: interrupted by a signal. */
110static int
111py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
112{
113 /* Is getrandom() supported by the running kernel? Set to 0 if getrandom()
114 failed with ENOSYS or EPERM. Need Linux kernel 3.17 or newer, or Solaris
115 11.3 or newer */
116 static int getrandom_works = 1;
117 int flags;
118 char *dest;
119 long n;
120
121 if (!getrandom_works) {
122 return 0;
123 }
124
125 flags = blocking ? 0 : GRND_NONBLOCK;
126 dest = buffer;
127 while (0 < size) {
128#if defined(__sun) && defined(__SVR4)
129 /* Issue #26735: On Solaris, getrandom() is limited to returning up
130 to 1024 bytes. Call it multiple times if more bytes are
131 requested. */
132 n = Py_MIN(size, 1024);
133#else
134 n = Py_MIN(size, LONG_MAX);
135#endif
136
137 errno = 0;
138#ifdef HAVE_GETRANDOM
139 if (raise) {
140 Py_BEGIN_ALLOW_THREADS
141 n = getrandom(dest, n, flags);
142 Py_END_ALLOW_THREADS
143 }
144 else {
145 n = getrandom(dest, n, flags);
146 }
147#else
148 /* On Linux, use the syscall() function because the GNU libc doesn't
149 expose the Linux getrandom() syscall yet. See:
150 https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
151 if (raise) {
152 Py_BEGIN_ALLOW_THREADS
153 n = syscall(SYS_getrandom, dest, n, flags);
154 Py_END_ALLOW_THREADS
155 }
156 else {
157 n = syscall(SYS_getrandom, dest, n, flags);
158 }
159# ifdef _Py_MEMORY_SANITIZER
160 if (n > 0) {
161 __msan_unpoison(dest, n);
162 }
163# endif
164#endif
165
166 if (n < 0) {
167 /* ENOSYS: the syscall is not supported by the kernel.
168 EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
169 or something else. */
170 if (errno == ENOSYS || errno == EPERM) {
171 getrandom_works = 0;
172 return 0;
173 }
174
175 /* getrandom(GRND_NONBLOCK) fails with EAGAIN if the system urandom
176 is not initialized yet. For _PyRandom_Init(), we ignore the
177 error and fall back on reading /dev/urandom which never blocks,
178 even if the system urandom is not initialized yet:
179 see the PEP 524. */
180 if (errno == EAGAIN && !raise && !blocking) {
181 return 0;
182 }
183
184 if (errno == EINTR) {
185 if (raise) {
186 if (PyErr_CheckSignals()) {
187 return -1;
188 }
189 }
190
191 /* retry getrandom() if it was interrupted by a signal */
192 continue;
193 }
194
195 if (raise) {
196 PyErr_SetFromErrno(PyExc_OSError);
197 }
198 return -1;
199 }
200
201 dest += n;
202 size -= n;
203 }
204 return 1;
205}
206
207#elif defined(HAVE_GETENTROPY)
208#define PY_GETENTROPY 1
209
210/* Fill buffer with size pseudo-random bytes generated by getentropy():
211
212 - Return 1 on success
213 - Return 0 if getentropy() syscall is not available (failed with ENOSYS or
214 EPERM).
215 - Raise an exception (if raise is non-zero) and return -1 on error:
216 if getentropy() failed with EINTR, raise is non-zero and the Python signal
217 handler raised an exception, or if getentropy() failed with a different
218 error.
219
220 getentropy() is retried if it failed with EINTR: interrupted by a signal. */
221
222#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
223static int
224py_getentropy(char *buffer, Py_ssize_t size, int raise)
225 __attribute__((availability(macos,introduced=10.12)))
226 __attribute__((availability(ios,introduced=10.0)))
227 __attribute__((availability(tvos,introduced=10.0)))
228 __attribute__((availability(watchos,introduced=3.0)));
229#endif
230
231static int
232py_getentropy(char *buffer, Py_ssize_t size, int raise)
233{
234 /* Is getentropy() supported by the running kernel? Set to 0 if
235 getentropy() failed with ENOSYS or EPERM. */
236 static int getentropy_works = 1;
237
238 if (!getentropy_works) {
239 return 0;
240 }
241
242 while (size > 0) {
243 /* getentropy() is limited to returning up to 256 bytes. Call it
244 multiple times if more bytes are requested. */
245 Py_ssize_t len = Py_MIN(size, 256);
246 int res;
247
248 if (raise) {
249 Py_BEGIN_ALLOW_THREADS
250 res = getentropy(buffer, len);
251 Py_END_ALLOW_THREADS
252 }
253 else {
254 res = getentropy(buffer, len);
255 }
256
257 if (res < 0) {
258 /* ENOSYS: the syscall is not supported by the running kernel.
259 EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
260 or something else. */
261 if (errno == ENOSYS || errno == EPERM) {
262 getentropy_works = 0;
263 return 0;
264 }
265
266 if (errno == EINTR) {
267 if (raise) {
268 if (PyErr_CheckSignals()) {
269 return -1;
270 }
271 }
272
273 /* retry getentropy() if it was interrupted by a signal */
274 continue;
275 }
276
277 if (raise) {
278 PyErr_SetFromErrno(PyExc_OSError);
279 }
280 return -1;
281 }
282
283 buffer += len;
284 size -= len;
285 }
286 return 1;
287}
288#endif /* defined(HAVE_GETENTROPY) && !(defined(__sun) && defined(__SVR4)) */
289
290
291static struct {
292 int fd;
293 dev_t st_dev;
294 ino_t st_ino;
295} urandom_cache = { -1 };
296
297/* Read random bytes from the /dev/urandom device:
298
299 - Return 0 on success
300 - Raise an exception (if raise is non-zero) and return -1 on error
301
302 Possible causes of errors:
303
304 - open() failed with ENOENT, ENXIO, ENODEV, EACCES: the /dev/urandom device
305 was not found. For example, it was removed manually or not exposed in a
306 chroot or container.
307 - open() failed with a different error
308 - fstat() failed
309 - read() failed or returned 0
310
311 read() is retried if it failed with EINTR: interrupted by a signal.
312
313 The file descriptor of the device is kept open between calls to avoid using
314 many file descriptors when run in parallel from multiple threads:
315 see the issue #18756.
316
317 st_dev and st_ino fields of the file descriptor (from fstat()) are cached to
318 check if the file descriptor was replaced by a different file (which is
319 likely a bug in the application): see the issue #21207.
320
321 If the file descriptor was closed or replaced, open a new file descriptor
322 but don't close the old file descriptor: it probably points to something
323 important for some third-party code. */
324static int
325dev_urandom(char *buffer, Py_ssize_t size, int raise)
326{
327 int fd;
328 Py_ssize_t n;
329
330 if (raise) {
331 struct _Py_stat_struct st;
332 int fstat_result;
333
334 if (urandom_cache.fd >= 0) {
335 Py_BEGIN_ALLOW_THREADS
336 fstat_result = _Py_fstat_noraise(urandom_cache.fd, &st);
337 Py_END_ALLOW_THREADS
338
339 /* Does the fd point to the same thing as before? (issue #21207) */
340 if (fstat_result
341 || st.st_dev != urandom_cache.st_dev
342 || st.st_ino != urandom_cache.st_ino) {
343 /* Something changed: forget the cached fd (but don't close it,
344 since it probably points to something important for some
345 third-party code). */
346 urandom_cache.fd = -1;
347 }
348 }
349 if (urandom_cache.fd >= 0)
350 fd = urandom_cache.fd;
351 else {
352 fd = _Py_open("/dev/urandom", O_RDONLY);
353 if (fd < 0) {
354 if (errno == ENOENT || errno == ENXIO ||
355 errno == ENODEV || errno == EACCES) {
356 PyErr_SetString(PyExc_NotImplementedError,
357 "/dev/urandom (or equivalent) not found");
358 }
359 /* otherwise, keep the OSError exception raised by _Py_open() */
360 return -1;
361 }
362 if (urandom_cache.fd >= 0) {
363 /* urandom_fd was initialized by another thread while we were
364 not holding the GIL, keep it. */
365 close(fd);
366 fd = urandom_cache.fd;
367 }
368 else {
369 if (_Py_fstat(fd, &st)) {
370 close(fd);
371 return -1;
372 }
373 else {
374 urandom_cache.fd = fd;
375 urandom_cache.st_dev = st.st_dev;
376 urandom_cache.st_ino = st.st_ino;
377 }
378 }
379 }
380
381 do {
382 n = _Py_read(fd, buffer, (size_t)size);
383 if (n == -1)
384 return -1;
385 if (n == 0) {
386 PyErr_Format(PyExc_RuntimeError,
387 "Failed to read %zi bytes from /dev/urandom",
388 size);
389 return -1;
390 }
391
392 buffer += n;
393 size -= n;
394 } while (0 < size);
395 }
396 else {
397 fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
398 if (fd < 0) {
399 return -1;
400 }
401
402 while (0 < size)
403 {
404 do {
405 n = read(fd, buffer, (size_t)size);
406 } while (n < 0 && errno == EINTR);
407
408 if (n <= 0) {
409 /* stop on error or if read(size) returned 0 */
410 close(fd);
411 return -1;
412 }
413
414 buffer += n;
415 size -= n;
416 }
417 close(fd);
418 }
419 return 0;
420}
421
422static void
423dev_urandom_close(void)
424{
425 if (urandom_cache.fd >= 0) {
426 close(urandom_cache.fd);
427 urandom_cache.fd = -1;
428 }
429}
430#endif /* !MS_WINDOWS */
431
432
433/* Fill buffer with pseudo-random bytes generated by a linear congruent
434 generator (LCG):
435
436 x(n+1) = (x(n) * 214013 + 2531011) % 2^32
437
438 Use bits 23..16 of x(n) to generate a byte. */
439static void
440lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
441{
442 size_t index;
443 unsigned int x;
444
445 x = x0;
446 for (index=0; index < size; index++) {
447 x *= 214013;
448 x += 2531011;
449 /* modulo 2 ^ (8 * sizeof(int)) */
450 buffer[index] = (x >> 16) & 0xff;
451 }
452}
453
454/* Read random bytes:
455
456 - Return 0 on success
457 - Raise an exception (if raise is non-zero) and return -1 on error
458
459 Used sources of entropy ordered by preference, preferred source first:
460
461 - CryptGenRandom() on Windows
462 - getrandom() function (ex: Linux and Solaris): call py_getrandom()
463 - getentropy() function (ex: OpenBSD): call py_getentropy()
464 - /dev/urandom device
465
466 Read from the /dev/urandom device if getrandom() or getentropy() function
467 is not available or does not work.
468
469 Prefer getrandom() over getentropy() because getrandom() supports blocking
470 and non-blocking mode: see the PEP 524. Python requires non-blocking RNG at
471 startup to initialize its hash secret, but os.urandom() must block until the
472 system urandom is initialized (at least on Linux 3.17 and newer).
473
474 Prefer getrandom() and getentropy() over reading directly /dev/urandom
475 because these functions don't need file descriptors and so avoid ENFILE or
476 EMFILE errors (too many open files): see the issue #18756.
477
478 Only the getrandom() function supports non-blocking mode.
479
480 Only use RNG running in the kernel. They are more secure because it is
481 harder to get the internal state of a RNG running in the kernel land than a
482 RNG running in the user land. The kernel has a direct access to the hardware
483 and has access to hardware RNG, they are used as entropy sources.
484
485 Note: the OpenSSL RAND_pseudo_bytes() function does not automatically reseed
486 its RNG on fork(), two child processes (with the same pid) generate the same
487 random numbers: see issue #18747. Kernel RNGs don't have this issue,
488 they have access to good quality entropy sources.
489
490 If raise is zero:
491
492 - Don't raise an exception on error
493 - Don't call the Python signal handler (don't call PyErr_CheckSignals()) if
494 a function fails with EINTR: retry directly the interrupted function
495 - Don't release the GIL to call functions.
496*/
497static int
498pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise)
499{
500#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY)
501 int res;
502#endif
503
504 if (size < 0) {
505 if (raise) {
506 PyErr_Format(PyExc_ValueError,
507 "negative argument not allowed");
508 }
509 return -1;
510 }
511
512 if (size == 0) {
513 return 0;
514 }
515
516#ifdef MS_WINDOWS
517 return win32_urandom((unsigned char *)buffer, size, raise);
518#else
519
520#if defined(PY_GETRANDOM) || defined(PY_GETENTROPY)
521 if (HAVE_GETENTRYPY_GETRANDOM_RUNTIME) {
522#ifdef PY_GETRANDOM
523 res = py_getrandom(buffer, size, blocking, raise);
524#else
525 res = py_getentropy(buffer, size, raise);
526#endif
527 if (res < 0) {
528 return -1;
529 }
530 if (res == 1) {
531 return 0;
532 }
533 /* getrandom() or getentropy() function is not available: failed with
534 ENOSYS or EPERM. Fall back on reading from /dev/urandom. */
535 } /* end of availability block */
536#endif
537
538 return dev_urandom(buffer, size, raise);
539#endif
540}
541
542/* Fill buffer with size pseudo-random bytes from the operating system random
543 number generator (RNG). It is suitable for most cryptographic purposes
544 except long living private keys for asymmetric encryption.
545
546 On Linux 3.17 and newer, the getrandom() syscall is used in blocking mode:
547 block until the system urandom entropy pool is initialized (128 bits are
548 collected by the kernel).
549
550 Return 0 on success. Raise an exception and return -1 on error. */
551int
552_PyOS_URandom(void *buffer, Py_ssize_t size)
553{
554 return pyurandom(buffer, size, 1, 1);
555}
556
557/* Fill buffer with size pseudo-random bytes from the operating system random
558 number generator (RNG). It is not suitable for cryptographic purpose.
559
560 On Linux 3.17 and newer (when getrandom() syscall is used), if the system
561 urandom is not initialized yet, the function returns "weak" entropy read
562 from /dev/urandom.
563
564 Return 0 on success. Raise an exception and return -1 on error. */
565int
566_PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
567{
568 return pyurandom(buffer, size, 0, 1);
569}
570
571
572PyStatus
573_Py_HashRandomization_Init(const PyConfig *config)
574{
575 void *secret = &_Py_HashSecret;
576 Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
577
578 if (_Py_HashSecret_Initialized) {
579 return _PyStatus_OK();
580 }
581 _Py_HashSecret_Initialized = 1;
582
583 if (config->use_hash_seed) {
584 if (config->hash_seed == 0) {
585 /* disable the randomized hash */
586 memset(secret, 0, secret_size);
587 }
588 else {
589 /* use the specified hash seed */
590 lcg_urandom(config->hash_seed, secret, secret_size);
591 }
592 }
593 else {
594 /* use a random hash seed */
595 int res;
596
597 /* _PyRandom_Init() is called very early in the Python initialization
598 and so exceptions cannot be used (use raise=0).
599
600 _PyRandom_Init() must not block Python initialization: call
601 pyurandom() is non-blocking mode (blocking=0): see the PEP 524. */
602 res = pyurandom(secret, secret_size, 0, 0);
603 if (res < 0) {
604 return _PyStatus_ERR("failed to get random numbers "
605 "to initialize Python");
606 }
607 }
608 return _PyStatus_OK();
609}
610
611
612void
613_Py_HashRandomization_Fini(void)
614{
615#ifdef MS_WINDOWS
616 if (hCryptProv) {
617 CryptReleaseContext(hCryptProv, 0);
618 hCryptProv = 0;
619 }
620#else
621 dev_urandom_close();
622#endif
623}
624