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