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 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 if (!getrandom_works) {
98 return 0;
99 }
100
101 flags = blocking ? 0 : GRND_NONBLOCK;
102 dest = buffer;
103 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 n = Py_MIN(size, LONG_MAX);
111 #endif
112
113 errno = 0;
114 #ifdef HAVE_GETRANDOM
115 if (raise) {
116 Py_BEGIN_ALLOW_THREADS
117 n = getrandom(dest, n, flags);
118 Py_END_ALLOW_THREADS
119 }
120 else {
121 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 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 if (errno == ENOSYS || errno == EPERM) {
147 getrandom_works = 0;
148 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 if (errno == EAGAIN && !raise && !blocking) {
157 return 0;
158 }
159
160 if (errno == EINTR) {
161 if (raise) {
162 if (PyErr_CheckSignals()) {
163 return -1;
164 }
165 }
166
167 /* retry getrandom() if it was interrupted by a signal */
168 continue;
169 }
170
171 if (raise) {
172 PyErr_SetFromErrno(PyExc_OSError);
173 }
174 return -1;
175 }
176
177 dest += n;
178 size -= n;
179 }
180 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 dev_urandom(char *buffer, Py_ssize_t size, int raise)
298 {
299 int fd;
300 Py_ssize_t n;
301
302 if (raise) {
303 struct _Py_stat_struct st;
304 int fstat_result;
305
306 if (urandom_cache.fd >= 0) {
307 Py_BEGIN_ALLOW_THREADS
308 fstat_result = _Py_fstat_noraise(urandom_cache.fd, &st);
309 Py_END_ALLOW_THREADS
310
311 /* Does the fd point to the same thing as before? (issue #21207) */
312 if (fstat_result
313 || st.st_dev != urandom_cache.st_dev
314 || 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 urandom_cache.fd = -1;
319 }
320 }
321 if (urandom_cache.fd >= 0)
322 fd = urandom_cache.fd;
323 else {
324 fd = _Py_open("/dev/urandom", O_RDONLY);
325 if (fd < 0) {
326 if (errno == ENOENT || errno == ENXIO ||
327 errno == ENODEV || errno == EACCES) {
328 PyErr_SetString(PyExc_NotImplementedError,
329 "/dev/urandom (or equivalent) not found");
330 }
331 /* otherwise, keep the OSError exception raised by _Py_open() */
332 return -1;
333 }
334 if (urandom_cache.fd >= 0) {
335 /* urandom_fd was initialized by another thread while we were
336 not holding the GIL, keep it. */
337 close(fd);
338 fd = urandom_cache.fd;
339 }
340 else {
341 if (_Py_fstat(fd, &st)) {
342 close(fd);
343 return -1;
344 }
345 else {
346 urandom_cache.fd = fd;
347 urandom_cache.st_dev = st.st_dev;
348 urandom_cache.st_ino = st.st_ino;
349 }
350 }
351 }
352
353 do {
354 n = _Py_read(fd, buffer, (size_t)size);
355 if (n == -1)
356 return -1;
357 if (n == 0) {
358 PyErr_Format(PyExc_RuntimeError,
359 "Failed to read %zi bytes from /dev/urandom",
360 size);
361 return -1;
362 }
363
364 buffer += n;
365 size -= n;
366 } while (0 < size);
367 }
368 else {
369 fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
370 if (fd < 0) {
371 return -1;
372 }
373
374 while (0 < size)
375 {
376 do {
377 n = read(fd, buffer, (size_t)size);
378 } while (n < 0 && errno == EINTR);
379
380 if (n <= 0) {
381 /* stop on error or if read(size) returned 0 */
382 close(fd);
383 return -1;
384 }
385
386 buffer += n;
387 size -= n;
388 }
389 close(fd);
390 }
391 return 0;
392 }
393
394 static void
395 dev_urandom_close(void)
396 {
397 if (urandom_cache.fd >= 0) {
398 close(urandom_cache.fd);
399 urandom_cache.fd = -1;
400 }
401 }
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 lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
416 {
417 size_t index;
418 unsigned int x;
419
420 x = x0;
421 for (index=0; index < size; index++) {
422 x *= 214013;
423 x += 2531011;
424 /* modulo 2 ^ (8 * sizeof(int)) */
425 buffer[index] = (x >> 16) & 0xff;
426 }
427 }
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 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 if (size < 0) {
480 if (raise) {
481 PyErr_Format(PyExc_ValueError,
482 "negative argument not allowed");
483 }
484 return -1;
485 }
486
487 if (size == 0) {
488 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 res = py_getrandom(buffer, size, blocking, raise);
499 #else
500 res = py_getentropy(buffer, size, raise);
501 #endif
502 if (res < 0) {
503 return -1;
504 }
505 if (res == 1) {
506 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 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 _PyOS_URandom(void *buffer, Py_ssize_t size)
528 {
529 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 _PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
542 {
543 return pyurandom(buffer, size, 0, 1);
544 }
545
546
547 PyStatus
548 _Py_HashRandomization_Init(const PyConfig *config)
549 {
550 void *secret = &_Py_HashSecret;
551 Py_ssize_t secret_size = sizeof(_Py_HashSecret_t);
552
553 if (_Py_HashSecret_Initialized) {
554 return _PyStatus_OK();
555 }
556 _Py_HashSecret_Initialized = 1;
557
558 if (config->use_hash_seed) {
559 if (config->hash_seed == 0) {
560 /* disable the randomized hash */
561 memset(secret, 0, secret_size);
562 }
563 else {
564 /* use the specified hash seed */
565 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 res = pyurandom(secret, secret_size, 0, 0);
578 if (res < 0) {
579 return _PyStatus_ERR("failed to get random numbers "
580 "to initialize Python");
581 }
582 }
583 return _PyStatus_OK();
584 }
585
586
587 void
588 _Py_HashRandomization_Fini(void)
589 {
590 #ifndef MS_WINDOWS
591 dev_urandom_close();
592 #endif
593 }