Line data Source code
1 : #include "Python.h"
2 : #include "pycore_initconfig.h"
3 : #include "pycore_fileutils.h" // _Py_fstat_noraise()
4 :
5 : #ifdef MS_WINDOWS
6 : # include <windows.h>
7 : # include <bcrypt.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
39 : int _Py_HashSecret_Initialized = 0;
40 : #else
41 : static int _Py_HashSecret_Initialized = 0;
42 : #endif
43 :
44 : #ifdef MS_WINDOWS
45 :
46 : /* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
47 : API. Return 0 on success, or raise an exception and return -1 on error. */
48 : static int
49 : win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
50 : {
51 : while (size > 0)
52 : {
53 : DWORD chunk = (DWORD)Py_MIN(size, PY_DWORD_MAX);
54 : NTSTATUS status = BCryptGenRandom(NULL, buffer, chunk, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
55 : if (!BCRYPT_SUCCESS(status)) {
56 : /* BCryptGenRandom() failed */
57 : if (raise) {
58 : PyErr_SetFromWindowsErr(0);
59 : }
60 : return -1;
61 : }
62 : buffer += chunk;
63 : size -= chunk;
64 : }
65 : return 0;
66 : }
67 :
68 : #else /* !MS_WINDOWS */
69 :
70 : #if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
71 : #define PY_GETRANDOM 1
72 :
73 : /* Call getrandom() to get random bytes:
74 :
75 : - Return 1 on success
76 : - Return 0 if getrandom() is not available (failed with ENOSYS or EPERM),
77 : or if getrandom(GRND_NONBLOCK) failed with EAGAIN (system urandom not
78 : initialized yet) and raise=0.
79 : - Raise an exception (if raise is non-zero) and return -1 on error:
80 : if getrandom() failed with EINTR, raise is non-zero and the Python signal
81 : handler raised an exception, or if getrandom() failed with a different
82 : error.
83 :
84 : getrandom() is retried if it failed with EINTR: interrupted by a signal. */
85 : static int
86 173576 : py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
87 : {
88 : /* Is getrandom() supported by the running kernel? Set to 0 if getrandom()
89 : failed with ENOSYS or EPERM. Need Linux kernel 3.17 or newer, or Solaris
90 : 11.3 or newer */
91 : static int getrandom_works = 1;
92 : int flags;
93 : char *dest;
94 : long n;
95 :
96 173576 : if (!getrandom_works) {
97 0 : return 0;
98 : }
99 :
100 173576 : flags = blocking ? 0 : GRND_NONBLOCK;
101 173576 : dest = buffer;
102 347152 : while (0 < size) {
103 : #if defined(__sun) && defined(__SVR4)
104 : /* Issue #26735: On Solaris, getrandom() is limited to returning up
105 : to 1024 bytes. Call it multiple times if more bytes are
106 : requested. */
107 : n = Py_MIN(size, 1024);
108 : #else
109 173576 : n = Py_MIN(size, LONG_MAX);
110 : #endif
111 :
112 173576 : errno = 0;
113 : #ifdef HAVE_GETRANDOM
114 173576 : if (raise) {
115 170672 : Py_BEGIN_ALLOW_THREADS
116 170672 : n = getrandom(dest, n, flags);
117 170672 : Py_END_ALLOW_THREADS
118 : }
119 : else {
120 2904 : n = getrandom(dest, n, flags);
121 : }
122 : #else
123 : /* On Linux, use the syscall() function because the GNU libc doesn't
124 : expose the Linux getrandom() syscall yet. See:
125 : https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
126 : if (raise) {
127 : Py_BEGIN_ALLOW_THREADS
128 : n = syscall(SYS_getrandom, dest, n, flags);
129 : Py_END_ALLOW_THREADS
130 : }
131 : else {
132 : n = syscall(SYS_getrandom, dest, n, flags);
133 : }
134 : # ifdef _Py_MEMORY_SANITIZER
135 : if (n > 0) {
136 : __msan_unpoison(dest, n);
137 : }
138 : # endif
139 : #endif
140 :
141 173576 : if (n < 0) {
142 : /* ENOSYS: the syscall is not supported by the kernel.
143 : EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
144 : or something else. */
145 0 : if (errno == ENOSYS || errno == EPERM) {
146 0 : getrandom_works = 0;
147 0 : return 0;
148 : }
149 :
150 : /* getrandom(GRND_NONBLOCK) fails with EAGAIN if the system urandom
151 : is not initialized yet. For _PyRandom_Init(), we ignore the
152 : error and fall back on reading /dev/urandom which never blocks,
153 : even if the system urandom is not initialized yet:
154 : see the PEP 524. */
155 0 : if (errno == EAGAIN && !raise && !blocking) {
156 0 : return 0;
157 : }
158 :
159 0 : if (errno == EINTR) {
160 0 : if (raise) {
161 0 : if (PyErr_CheckSignals()) {
162 0 : return -1;
163 : }
164 : }
165 :
166 : /* retry getrandom() if it was interrupted by a signal */
167 0 : continue;
168 : }
169 :
170 0 : if (raise) {
171 0 : PyErr_SetFromErrno(PyExc_OSError);
172 : }
173 0 : return -1;
174 : }
175 :
176 173576 : dest += n;
177 173576 : size -= n;
178 : }
179 173576 : return 1;
180 : }
181 :
182 : #elif defined(HAVE_GETENTROPY)
183 : #define PY_GETENTROPY 1
184 :
185 : /* Fill buffer with size pseudo-random bytes generated by getentropy():
186 :
187 : - Return 1 on success
188 : - Return 0 if getentropy() syscall is not available (failed with ENOSYS or
189 : EPERM).
190 : - Raise an exception (if raise is non-zero) and return -1 on error:
191 : if getentropy() failed with EINTR, raise is non-zero and the Python signal
192 : handler raised an exception, or if getentropy() failed with a different
193 : error.
194 :
195 : getentropy() is retried if it failed with EINTR: interrupted by a signal. */
196 :
197 : #if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
198 : static int
199 : py_getentropy(char *buffer, Py_ssize_t size, int raise)
200 : __attribute__((availability(macos,introduced=10.12)))
201 : __attribute__((availability(ios,introduced=10.0)))
202 : __attribute__((availability(tvos,introduced=10.0)))
203 : __attribute__((availability(watchos,introduced=3.0)));
204 : #endif
205 :
206 : static int
207 : py_getentropy(char *buffer, Py_ssize_t size, int raise)
208 : {
209 : /* Is getentropy() supported by the running kernel? Set to 0 if
210 : getentropy() failed with ENOSYS or EPERM. */
211 : static int getentropy_works = 1;
212 :
213 : if (!getentropy_works) {
214 : return 0;
215 : }
216 :
217 : while (size > 0) {
218 : /* getentropy() is limited to returning up to 256 bytes. Call it
219 : multiple times if more bytes are requested. */
220 : Py_ssize_t len = Py_MIN(size, 256);
221 : int res;
222 :
223 : if (raise) {
224 : Py_BEGIN_ALLOW_THREADS
225 : res = getentropy(buffer, len);
226 : Py_END_ALLOW_THREADS
227 : }
228 : else {
229 : res = getentropy(buffer, len);
230 : }
231 :
232 : if (res < 0) {
233 : /* ENOSYS: the syscall is not supported by the running kernel.
234 : EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
235 : or something else. */
236 : if (errno == ENOSYS || errno == EPERM) {
237 : getentropy_works = 0;
238 : return 0;
239 : }
240 :
241 : if (errno == EINTR) {
242 : if (raise) {
243 : if (PyErr_CheckSignals()) {
244 : return -1;
245 : }
246 : }
247 :
248 : /* retry getentropy() if it was interrupted by a signal */
249 : continue;
250 : }
251 :
252 : if (raise) {
253 : PyErr_SetFromErrno(PyExc_OSError);
254 : }
255 : return -1;
256 : }
257 :
258 : buffer += len;
259 : size -= len;
260 : }
261 : return 1;
262 : }
263 : #endif /* defined(HAVE_GETENTROPY) && !(defined(__sun) && defined(__SVR4)) */
264 :
265 :
266 : static struct {
267 : int fd;
268 : dev_t st_dev;
269 : ino_t st_ino;
270 : } urandom_cache = { -1 };
271 :
272 : /* Read random bytes from the /dev/urandom device:
273 :
274 : - Return 0 on success
275 : - Raise an exception (if raise is non-zero) and return -1 on error
276 :
277 : Possible causes of errors:
278 :
279 : - open() failed with ENOENT, ENXIO, ENODEV, EACCES: the /dev/urandom device
280 : was not found. For example, it was removed manually or not exposed in a
281 : chroot or container.
282 : - open() failed with a different error
283 : - fstat() failed
284 : - read() failed or returned 0
285 :
286 : read() is retried if it failed with EINTR: interrupted by a signal.
287 :
288 : The file descriptor of the device is kept open between calls to avoid using
289 : many file descriptors when run in parallel from multiple threads:
290 : see the issue #18756.
291 :
292 : st_dev and st_ino fields of the file descriptor (from fstat()) are cached to
293 : check if the file descriptor was replaced by a different file (which is
294 : likely a bug in the application): see the issue #21207.
295 :
296 : If the file descriptor was closed or replaced, open a new file descriptor
297 : but don't close the old file descriptor: it probably points to something
298 : important for some third-party code. */
299 : static int
300 0 : dev_urandom(char *buffer, Py_ssize_t size, int raise)
301 : {
302 : int fd;
303 : Py_ssize_t n;
304 :
305 0 : if (raise) {
306 : struct _Py_stat_struct st;
307 : int fstat_result;
308 :
309 0 : if (urandom_cache.fd >= 0) {
310 0 : Py_BEGIN_ALLOW_THREADS
311 0 : fstat_result = _Py_fstat_noraise(urandom_cache.fd, &st);
312 0 : Py_END_ALLOW_THREADS
313 :
314 : /* Does the fd point to the same thing as before? (issue #21207) */
315 0 : if (fstat_result
316 0 : || st.st_dev != urandom_cache.st_dev
317 0 : || st.st_ino != urandom_cache.st_ino) {
318 : /* Something changed: forget the cached fd (but don't close it,
319 : since it probably points to something important for some
320 : third-party code). */
321 0 : urandom_cache.fd = -1;
322 : }
323 : }
324 0 : if (urandom_cache.fd >= 0)
325 0 : fd = urandom_cache.fd;
326 : else {
327 0 : fd = _Py_open("/dev/urandom", O_RDONLY);
328 0 : if (fd < 0) {
329 0 : if (errno == ENOENT || errno == ENXIO ||
330 0 : errno == ENODEV || errno == EACCES) {
331 0 : PyErr_SetString(PyExc_NotImplementedError,
332 : "/dev/urandom (or equivalent) not found");
333 : }
334 : /* otherwise, keep the OSError exception raised by _Py_open() */
335 0 : return -1;
336 : }
337 0 : if (urandom_cache.fd >= 0) {
338 : /* urandom_fd was initialized by another thread while we were
339 : not holding the GIL, keep it. */
340 0 : close(fd);
341 0 : fd = urandom_cache.fd;
342 : }
343 : else {
344 0 : if (_Py_fstat(fd, &st)) {
345 0 : close(fd);
346 0 : return -1;
347 : }
348 : else {
349 0 : urandom_cache.fd = fd;
350 0 : urandom_cache.st_dev = st.st_dev;
351 0 : urandom_cache.st_ino = st.st_ino;
352 : }
353 : }
354 : }
355 :
356 : do {
357 0 : n = _Py_read(fd, buffer, (size_t)size);
358 0 : if (n == -1)
359 0 : return -1;
360 0 : if (n == 0) {
361 0 : PyErr_Format(PyExc_RuntimeError,
362 : "Failed to read %zi bytes from /dev/urandom",
363 : size);
364 0 : return -1;
365 : }
366 :
367 0 : buffer += n;
368 0 : size -= n;
369 0 : } while (0 < size);
370 : }
371 : else {
372 0 : fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
373 0 : if (fd < 0) {
374 0 : return -1;
375 : }
376 :
377 0 : while (0 < size)
378 : {
379 : do {
380 0 : n = read(fd, buffer, (size_t)size);
381 0 : } while (n < 0 && errno == EINTR);
382 :
383 0 : if (n <= 0) {
384 : /* stop on error or if read(size) returned 0 */
385 0 : close(fd);
386 0 : return -1;
387 : }
388 :
389 0 : buffer += n;
390 0 : size -= n;
391 : }
392 0 : close(fd);
393 : }
394 0 : return 0;
395 : }
396 :
397 : static void
398 2951 : dev_urandom_close(void)
399 : {
400 2951 : if (urandom_cache.fd >= 0) {
401 0 : close(urandom_cache.fd);
402 0 : urandom_cache.fd = -1;
403 : }
404 2951 : }
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 16 : lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
416 : {
417 : size_t index;
418 : unsigned int x;
419 :
420 16 : x = x0;
421 400 : for (index=0; index < size; index++) {
422 384 : x *= 214013;
423 384 : x += 2531011;
424 : /* modulo 2 ^ (8 * sizeof(int)) */
425 384 : buffer[index] = (x >> 16) & 0xff;
426 : }
427 16 : }
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 173579 : 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 173579 : 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 173579 : if (size == 0) {
488 3 : 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 173576 : res = py_getrandom(buffer, size, blocking, raise);
499 : #else
500 : res = py_getentropy(buffer, size, raise);
501 : #endif
502 173576 : if (res < 0) {
503 0 : return -1;
504 : }
505 173576 : if (res == 1) {
506 173576 : 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 168920 : _PyOS_URandom(void *buffer, Py_ssize_t size)
528 : {
529 168920 : 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 1755 : _PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
542 : {
543 1755 : return pyurandom(buffer, size, 0, 1);
544 : }
545 :
546 :
547 : PyStatus
548 2963 : _Py_HashRandomization_Init(const PyConfig *config)
549 : {
550 2963 : void *secret = &_Py_HashSecret;
551 2963 : Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
552 :
553 2963 : if (_Py_HashSecret_Initialized) {
554 34 : return _PyStatus_OK();
555 : }
556 2929 : _Py_HashSecret_Initialized = 1;
557 :
558 2929 : if (config->use_hash_seed) {
559 25 : if (config->hash_seed == 0) {
560 : /* disable the randomized hash */
561 9 : memset(secret, 0, secret_size);
562 : }
563 : else {
564 : /* use the specified hash seed */
565 16 : 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 2904 : res = pyurandom(secret, secret_size, 0, 0);
578 2904 : if (res < 0) {
579 0 : return _PyStatus_ERR("failed to get random numbers "
580 : "to initialize Python");
581 : }
582 : }
583 2929 : return _PyStatus_OK();
584 : }
585 :
586 :
587 : void
588 2951 : _Py_HashRandomization_Fini(void)
589 : {
590 : #ifndef MS_WINDOWS
591 2951 : dev_urandom_close();
592 : #endif
593 2951 : }
|