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