Home | History | Annotate | Download | only in Python
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    545 _PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
    546 {
    547     return pyurandom(buffer, size, 0, 1);
    548 }
    549 
    550 int
    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
    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
    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