(root)/
Python-3.12.0/
Python/
bootstrap_hash.c
       1  #include "Python.h"
       2  #include "pycore_initconfig.h"
       3  #include "pycore_fileutils.h"     // _Py_fstat_noraise()
       4  #include "pycore_runtime.h"       // _PyRuntime
       5  
       6  #ifdef MS_WINDOWS
       7  #  include <windows.h>
       8  #  include <bcrypt.h>
       9  #else
      10  #  include <fcntl.h>
      11  #  ifdef HAVE_SYS_STAT_H
      12  #    include <sys/stat.h>
      13  #  endif
      14  #  ifdef HAVE_LINUX_RANDOM_H
      15  #    include <linux/random.h>
      16  #  endif
      17  #  if defined(HAVE_SYS_RANDOM_H) && (defined(HAVE_GETRANDOM) || defined(HAVE_GETENTROPY))
      18  #    include <sys/random.h>
      19  #  endif
      20  #  if !defined(HAVE_GETRANDOM) && defined(HAVE_GETRANDOM_SYSCALL)
      21  #    include <sys/syscall.h>
      22  #  endif
      23  #endif
      24  
      25  #ifdef _Py_MEMORY_SANITIZER
      26  #  include <sanitizer/msan_interface.h>
      27  #endif
      28  
      29  #if defined(__APPLE__) && defined(__has_builtin)
      30  #  if __has_builtin(__builtin_available)
      31  #    define HAVE_GETENTRYPY_GETRANDOM_RUNTIME __builtin_available(macOS 10.12, iOS 10.10, tvOS 10.0, watchOS 3.0, *)
      32  #  endif
      33  #endif
      34  #ifndef HAVE_GETENTRYPY_GETRANDOM_RUNTIME
      35  #  define HAVE_GETENTRYPY_GETRANDOM_RUNTIME 1
      36  #endif
      37  
      38  
      39  #ifdef Py_DEBUG
      40  int _Py_HashSecret_Initialized = 0;
      41  #else
      42  static int _Py_HashSecret_Initialized = 0;
      43  #endif
      44  
      45  #ifdef MS_WINDOWS
      46  
      47  /* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
      48     API. Return 0 on success, or raise an exception and return -1 on error. */
      49  static int
      50  win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
      51  {
      52      while (size > 0)
      53      {
      54          DWORD chunk = (DWORD)Py_MIN(size, PY_DWORD_MAX);
      55          NTSTATUS status = BCryptGenRandom(NULL, buffer, chunk, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
      56          if (!BCRYPT_SUCCESS(status)) {
      57              /* BCryptGenRandom() failed */
      58              if (raise) {
      59                  PyErr_SetFromWindowsErr(0);
      60              }
      61              return -1;
      62          }
      63          buffer += chunk;
      64          size -= chunk;
      65      }
      66      return 0;
      67  }
      68  
      69  #else /* !MS_WINDOWS */
      70  
      71  #if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
      72  #define PY_GETRANDOM 1
      73  
      74  /* Call getrandom() to get random bytes:
      75  
      76     - Return 1 on success
      77     - Return 0 if getrandom() is not available (failed with ENOSYS or EPERM),
      78       or if getrandom(GRND_NONBLOCK) failed with EAGAIN (system urandom not
      79       initialized yet) and raise=0.
      80     - Raise an exception (if raise is non-zero) and return -1 on error:
      81       if getrandom() failed with EINTR, raise is non-zero and the Python signal
      82       handler raised an exception, or if getrandom() failed with a different
      83       error.
      84  
      85     getrandom() is retried if it failed with EINTR: interrupted by a signal. */
      86  static int
      87  py_getrandom(void *buffer, Py_ssize_t size, int blocking, int raise)
      88  {
      89      /* Is getrandom() supported by the running kernel? Set to 0 if getrandom()
      90         failed with ENOSYS or EPERM. Need Linux kernel 3.17 or newer, or Solaris
      91         11.3 or newer */
      92      static int getrandom_works = 1;
      93      int flags;
      94      char *dest;
      95      long n;
      96  
      97      if (!getrandom_works) {
      98          return 0;
      99      }
     100  
     101      flags = blocking ? 0 : GRND_NONBLOCK;
     102      dest = buffer;
     103      while (0 < size) {
     104  #if defined(__sun) && defined(__SVR4)
     105          /* Issue #26735: On Solaris, getrandom() is limited to returning up
     106             to 1024 bytes. Call it multiple times if more bytes are
     107             requested. */
     108          n = Py_MIN(size, 1024);
     109  #else
     110          n = Py_MIN(size, LONG_MAX);
     111  #endif
     112  
     113          errno = 0;
     114  #ifdef HAVE_GETRANDOM
     115          if (raise) {
     116              Py_BEGIN_ALLOW_THREADS
     117              n = getrandom(dest, n, flags);
     118              Py_END_ALLOW_THREADS
     119          }
     120          else {
     121              n = getrandom(dest, n, flags);
     122          }
     123  #else
     124          /* On Linux, use the syscall() function because the GNU libc doesn't
     125             expose the Linux getrandom() syscall yet. See:
     126             https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
     127          if (raise) {
     128              Py_BEGIN_ALLOW_THREADS
     129              n = syscall(SYS_getrandom, dest, n, flags);
     130              Py_END_ALLOW_THREADS
     131          }
     132          else {
     133              n = syscall(SYS_getrandom, dest, n, flags);
     134          }
     135  #  ifdef _Py_MEMORY_SANITIZER
     136          if (n > 0) {
     137               __msan_unpoison(dest, n);
     138          }
     139  #  endif
     140  #endif
     141  
     142          if (n < 0) {
     143              /* ENOSYS: the syscall is not supported by the kernel.
     144                 EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
     145                 or something else. */
     146              if (errno == ENOSYS || errno == EPERM) {
     147                  getrandom_works = 0;
     148                  return 0;
     149              }
     150  
     151              /* getrandom(GRND_NONBLOCK) fails with EAGAIN if the system urandom
     152                 is not initialized yet. For _PyRandom_Init(), we ignore the
     153                 error and fall back on reading /dev/urandom which never blocks,
     154                 even if the system urandom is not initialized yet:
     155                 see the PEP 524. */
     156              if (errno == EAGAIN && !raise && !blocking) {
     157                  return 0;
     158              }
     159  
     160              if (errno == EINTR) {
     161                  if (raise) {
     162                      if (PyErr_CheckSignals()) {
     163                          return -1;
     164                      }
     165                  }
     166  
     167                  /* retry getrandom() if it was interrupted by a signal */
     168                  continue;
     169              }
     170  
     171              if (raise) {
     172                  PyErr_SetFromErrno(PyExc_OSError);
     173              }
     174              return -1;
     175          }
     176  
     177          dest += n;
     178          size -= n;
     179      }
     180      return 1;
     181  }
     182  
     183  #elif defined(HAVE_GETENTROPY)
     184  #define PY_GETENTROPY 1
     185  
     186  /* Fill buffer with size pseudo-random bytes generated by getentropy():
     187  
     188     - Return 1 on success
     189     - Return 0 if getentropy() syscall is not available (failed with ENOSYS or
     190       EPERM).
     191     - Raise an exception (if raise is non-zero) and return -1 on error:
     192       if getentropy() failed with EINTR, raise is non-zero and the Python signal
     193       handler raised an exception, or if getentropy() failed with a different
     194       error.
     195  
     196     getentropy() is retried if it failed with EINTR: interrupted by a signal. */
     197  
     198  #if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
     199  static int
     200  py_getentropy(char *buffer, Py_ssize_t size, int raise)
     201          __attribute__((availability(macos,introduced=10.12)))
     202          __attribute__((availability(ios,introduced=10.0)))
     203          __attribute__((availability(tvos,introduced=10.0)))
     204          __attribute__((availability(watchos,introduced=3.0)));
     205  #endif
     206  
     207  static int
     208  py_getentropy(char *buffer, Py_ssize_t size, int raise)
     209  {
     210      /* Is getentropy() supported by the running kernel? Set to 0 if
     211         getentropy() failed with ENOSYS or EPERM. */
     212      static int getentropy_works = 1;
     213  
     214      if (!getentropy_works) {
     215          return 0;
     216      }
     217  
     218      while (size > 0) {
     219          /* getentropy() is limited to returning up to 256 bytes. Call it
     220             multiple times if more bytes are requested. */
     221          Py_ssize_t len = Py_MIN(size, 256);
     222          int res;
     223  
     224          if (raise) {
     225              Py_BEGIN_ALLOW_THREADS
     226              res = getentropy(buffer, len);
     227              Py_END_ALLOW_THREADS
     228          }
     229          else {
     230              res = getentropy(buffer, len);
     231          }
     232  
     233          if (res < 0) {
     234              /* ENOSYS: the syscall is not supported by the running kernel.
     235                 EPERM: the syscall is blocked by a security policy (ex: SECCOMP)
     236                 or something else. */
     237              if (errno == ENOSYS || errno == EPERM) {
     238                  getentropy_works = 0;
     239                  return 0;
     240              }
     241  
     242              if (errno == EINTR) {
     243                  if (raise) {
     244                      if (PyErr_CheckSignals()) {
     245                          return -1;
     246                      }
     247                  }
     248  
     249                  /* retry getentropy() if it was interrupted by a signal */
     250                  continue;
     251              }
     252  
     253              if (raise) {
     254                  PyErr_SetFromErrno(PyExc_OSError);
     255              }
     256              return -1;
     257          }
     258  
     259          buffer += len;
     260          size -= len;
     261      }
     262      return 1;
     263  }
     264  #endif /* defined(HAVE_GETENTROPY) && !(defined(__sun) && defined(__SVR4)) */
     265  
     266  
     267  #define urandom_cache (_PyRuntime.pyhash_state.urandom_cache)
     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
     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          int fstat_result;
     305  
     306          if (urandom_cache.fd >= 0) {
     307              Py_BEGIN_ALLOW_THREADS
     308              fstat_result = _Py_fstat_noraise(urandom_cache.fd, &st);
     309              Py_END_ALLOW_THREADS
     310  
     311              /* Does the fd point to the same thing as before? (issue #21207) */
     312              if (fstat_result
     313                  || st.st_dev != urandom_cache.st_dev
     314                  || st.st_ino != urandom_cache.st_ino) {
     315                  /* Something changed: forget the cached fd (but don't close it,
     316                     since it probably points to something important for some
     317                     third-party code). */
     318                  urandom_cache.fd = -1;
     319              }
     320          }
     321          if (urandom_cache.fd >= 0)
     322              fd = urandom_cache.fd;
     323          else {
     324              fd = _Py_open("/dev/urandom", O_RDONLY);
     325              if (fd < 0) {
     326                  if (errno == ENOENT || errno == ENXIO ||
     327                      errno == ENODEV || errno == EACCES) {
     328                      PyErr_SetString(PyExc_NotImplementedError,
     329                                      "/dev/urandom (or equivalent) not found");
     330                  }
     331                  /* otherwise, keep the OSError exception raised by _Py_open() */
     332                  return -1;
     333              }
     334              if (urandom_cache.fd >= 0) {
     335                  /* urandom_fd was initialized by another thread while we were
     336                     not holding the GIL, keep it. */
     337                  close(fd);
     338                  fd = urandom_cache.fd;
     339              }
     340              else {
     341                  if (_Py_fstat(fd, &st)) {
     342                      close(fd);
     343                      return -1;
     344                  }
     345                  else {
     346                      urandom_cache.fd = fd;
     347                      urandom_cache.st_dev = st.st_dev;
     348                      urandom_cache.st_ino = st.st_ino;
     349                  }
     350              }
     351          }
     352  
     353          do {
     354              n = _Py_read(fd, buffer, (size_t)size);
     355              if (n == -1)
     356                  return -1;
     357              if (n == 0) {
     358                  PyErr_Format(PyExc_RuntimeError,
     359                          "Failed to read %zi bytes from /dev/urandom",
     360                          size);
     361                  return -1;
     362              }
     363  
     364              buffer += n;
     365              size -= n;
     366          } while (0 < size);
     367      }
     368      else {
     369          fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
     370          if (fd < 0) {
     371              return -1;
     372          }
     373  
     374          while (0 < size)
     375          {
     376              do {
     377                  n = read(fd, buffer, (size_t)size);
     378              } while (n < 0 && errno == EINTR);
     379  
     380              if (n <= 0) {
     381                  /* stop on error or if read(size) returned 0 */
     382                  close(fd);
     383                  return -1;
     384              }
     385  
     386              buffer += n;
     387              size -= n;
     388          }
     389          close(fd);
     390      }
     391      return 0;
     392  }
     393  
     394  static void
     395  dev_urandom_close(void)
     396  {
     397      if (urandom_cache.fd >= 0) {
     398          close(urandom_cache.fd);
     399          urandom_cache.fd = -1;
     400      }
     401  }
     402  
     403  #undef urandom_cache
     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
     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
     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
     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
     541  _PyOS_URandomNonblock(void *buffer, Py_ssize_t size)
     542  {
     543      return pyurandom(buffer, size, 0, 1);
     544  }
     545  
     546  
     547  PyStatus
     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
     588  _Py_HashRandomization_Fini(void)
     589  {
     590  #ifndef MS_WINDOWS
     591      dev_urandom_close();
     592  #endif
     593  }