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