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