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