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