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
win32_urandom(unsigned char * buffer,Py_ssize_t size,int raise)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
py_getrandom(void * buffer,Py_ssize_t size,int blocking,int raise)86 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 if (!getrandom_works) {
97 return 0;
98 }
99
100 flags = blocking ? 0 : GRND_NONBLOCK;
101 dest = buffer;
102 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 n = Py_MIN(size, LONG_MAX);
110 #endif
111
112 errno = 0;
113 #ifdef HAVE_GETRANDOM
114 if (raise) {
115 Py_BEGIN_ALLOW_THREADS
116 n = getrandom(dest, n, flags);
117 Py_END_ALLOW_THREADS
118 }
119 else {
120 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 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 if (errno == ENOSYS || errno == EPERM) {
146 getrandom_works = 0;
147 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 if (errno == EAGAIN && !raise && !blocking) {
156 return 0;
157 }
158
159 if (errno == EINTR) {
160 if (raise) {
161 if (PyErr_CheckSignals()) {
162 return -1;
163 }
164 }
165
166 /* retry getrandom() if it was interrupted by a signal */
167 continue;
168 }
169
170 if (raise) {
171 PyErr_SetFromErrno(PyExc_OSError);
172 }
173 return -1;
174 }
175
176 dest += n;
177 size -= n;
178 }
179 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
py_getentropy(char * buffer,Py_ssize_t size,int raise)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
dev_urandom(char * buffer,Py_ssize_t size,int raise)300 dev_urandom(char *buffer, Py_ssize_t size, int raise)
301 {
302 int fd;
303 Py_ssize_t n;
304
305 if (raise) {
306 struct _Py_stat_struct st;
307 int fstat_result;
308
309 if (urandom_cache.fd >= 0) {
310 Py_BEGIN_ALLOW_THREADS
311 fstat_result = _Py_fstat_noraise(urandom_cache.fd, &st);
312 Py_END_ALLOW_THREADS
313
314 /* Does the fd point to the same thing as before? (issue #21207) */
315 if (fstat_result
316 || st.st_dev != urandom_cache.st_dev
317 || 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 urandom_cache.fd = -1;
322 }
323 }
324 if (urandom_cache.fd >= 0)
325 fd = urandom_cache.fd;
326 else {
327 fd = _Py_open("/dev/urandom", O_RDONLY);
328 if (fd < 0) {
329 if (errno == ENOENT || errno == ENXIO ||
330 errno == ENODEV || errno == EACCES) {
331 PyErr_SetString(PyExc_NotImplementedError,
332 "/dev/urandom (or equivalent) not found");
333 }
334 /* otherwise, keep the OSError exception raised by _Py_open() */
335 return -1;
336 }
337 if (urandom_cache.fd >= 0) {
338 /* urandom_fd was initialized by another thread while we were
339 not holding the GIL, keep it. */
340 close(fd);
341 fd = urandom_cache.fd;
342 }
343 else {
344 if (_Py_fstat(fd, &st)) {
345 close(fd);
346 return -1;
347 }
348 else {
349 urandom_cache.fd = fd;
350 urandom_cache.st_dev = st.st_dev;
351 urandom_cache.st_ino = st.st_ino;
352 }
353 }
354 }
355
356 do {
357 n = _Py_read(fd, buffer, (size_t)size);
358 if (n == -1)
359 return -1;
360 if (n == 0) {
361 PyErr_Format(PyExc_RuntimeError,
362 "Failed to read %zi bytes from /dev/urandom",
363 size);
364 return -1;
365 }
366
367 buffer += n;
368 size -= n;
369 } while (0 < size);
370 }
371 else {
372 fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
373 if (fd < 0) {
374 return -1;
375 }
376
377 while (0 < size)
378 {
379 do {
380 n = read(fd, buffer, (size_t)size);
381 } while (n < 0 && errno == EINTR);
382
383 if (n <= 0) {
384 /* stop on error or if read(size) returned 0 */
385 close(fd);
386 return -1;
387 }
388
389 buffer += n;
390 size -= n;
391 }
392 close(fd);
393 }
394 return 0;
395 }
396
397 static void
dev_urandom_close(void)398 dev_urandom_close(void)
399 {
400 if (urandom_cache.fd >= 0) {
401 close(urandom_cache.fd);
402 urandom_cache.fd = -1;
403 }
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
lcg_urandom(unsigned int x0,unsigned char * buffer,size_t size)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
pyurandom(void * buffer,Py_ssize_t size,int blocking,int raise)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
_PyOS_URandom(void * buffer,Py_ssize_t size)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
_PyOS_URandomNonblock(void * buffer,Py_ssize_t size)541 _PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
542 {
543 return pyurandom(buffer, size, 0, 1);
544 }
545
546
547 PyStatus
_Py_HashRandomization_Init(const PyConfig * config)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
_Py_HashRandomization_Fini(void)588 _Py_HashRandomization_Fini(void)
589 {
590 #ifndef MS_WINDOWS
591 dev_urandom_close();
592 #endif
593 }
594