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