mirror of
https://github.com/python/cpython.git
synced 2025-10-13 10:23:28 +00:00
Issue #27776: Cleanup random.c
* Add pyurandom() helper function to factorize the code * don't call Py_FatalError() in helper functions, but only in _PyRandom_Init() if pyurandom() failed, to uniformize the code
This commit is contained in:
parent
c35a32fe85
commit
4bad3b622e
1 changed files with 76 additions and 57 deletions
133
Python/random.c
133
Python/random.c
|
@ -39,10 +39,9 @@ win32_urandom_init(int raise)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (raise)
|
if (raise) {
|
||||||
PyErr_SetFromWindowsErr(0);
|
PyErr_SetFromWindowsErr(0);
|
||||||
else
|
}
|
||||||
Py_FatalError("Failed to initialize Windows random API (CryptoGen)");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +54,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
|
||||||
|
|
||||||
if (hCryptProv == 0)
|
if (hCryptProv == 0)
|
||||||
{
|
{
|
||||||
if (win32_urandom_init(raise) == -1)
|
if (win32_urandom_init(raise) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (size > 0)
|
while (size > 0)
|
||||||
|
@ -65,11 +65,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
|
||||||
if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer))
|
if (!CryptGenRandom(hCryptProv, (DWORD)chunk, buffer))
|
||||||
{
|
{
|
||||||
/* CryptGenRandom() failed */
|
/* CryptGenRandom() failed */
|
||||||
if (raise)
|
if (raise) {
|
||||||
PyErr_SetFromWindowsErr(0);
|
PyErr_SetFromWindowsErr(0);
|
||||||
else
|
}
|
||||||
Py_FatalError("Failed to initialized the randomized hash "
|
|
||||||
"secret using CryptoGen)");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buffer += chunk;
|
buffer += chunk;
|
||||||
|
@ -86,29 +84,28 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
|
||||||
/* Fill buffer with size pseudo-random bytes generated by getentropy().
|
/* Fill buffer with size pseudo-random bytes generated by getentropy().
|
||||||
Return 0 on success, or raise an exception and return -1 on error.
|
Return 0 on success, or raise an exception and return -1 on error.
|
||||||
|
|
||||||
If fatal is nonzero, call Py_FatalError() instead of raising an exception
|
If raise is zero, don't raise an exception on error. */
|
||||||
on error. */
|
|
||||||
static int
|
static int
|
||||||
py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
|
py_getentropy(char *buffer, Py_ssize_t size, int raise)
|
||||||
{
|
{
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
Py_ssize_t len = Py_MIN(size, 256);
|
Py_ssize_t len = Py_MIN(size, 256);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (!fatal) {
|
if (raise) {
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = getentropy(buffer, len);
|
res = getentropy(buffer, len);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (res < 0) {
|
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = getentropy(buffer, len);
|
res = getentropy(buffer, len);
|
||||||
if (res < 0)
|
}
|
||||||
Py_FatalError("getentropy() failed");
|
|
||||||
|
if (res < 0) {
|
||||||
|
if (raise) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer += len;
|
buffer += len;
|
||||||
|
@ -195,18 +192,15 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
|
||||||
|
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
if (PyErr_CheckSignals()) {
|
if (PyErr_CheckSignals()) {
|
||||||
if (!raise)
|
|
||||||
Py_FatalError("getrandom() interrupted by a signal");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* retry getrandom() */
|
/* retry getrandom() */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raise)
|
if (raise) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
else
|
}
|
||||||
Py_FatalError("getrandom() failed");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,9 +219,9 @@ static struct {
|
||||||
|
|
||||||
|
|
||||||
/* Read size bytes from /dev/urandom into buffer.
|
/* Read size bytes from /dev/urandom into buffer.
|
||||||
Call Py_FatalError() on error. */
|
Return 0 success, or return -1 on error. */
|
||||||
static void
|
static int
|
||||||
dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
|
dev_urandom_noraise(char *buffer, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
Py_ssize_t n;
|
Py_ssize_t n;
|
||||||
|
@ -235,31 +229,35 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
|
||||||
assert (0 < size);
|
assert (0 < size);
|
||||||
|
|
||||||
#ifdef PY_GETRANDOM
|
#ifdef PY_GETRANDOM
|
||||||
if (py_getrandom(buffer, size, 0) == 1)
|
if (py_getrandom(buffer, size, 0) == 1) {
|
||||||
return;
|
return 0;
|
||||||
|
}
|
||||||
/* getrandom() is not supported by the running kernel, fall back
|
/* getrandom() is not supported by the running kernel, fall back
|
||||||
* on reading /dev/urandom */
|
* on reading /dev/urandom */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
|
fd = _Py_open_noraise("/dev/urandom", O_RDONLY);
|
||||||
if (fd < 0)
|
if (fd < 0) {
|
||||||
Py_FatalError("Failed to open /dev/urandom");
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (0 < size)
|
while (0 < size)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
n = read(fd, buffer, (size_t)size);
|
n = read(fd, buffer, (size_t)size);
|
||||||
} while (n < 0 && errno == EINTR);
|
} while (n < 0 && errno == EINTR);
|
||||||
if (n <= 0)
|
|
||||||
{
|
if (n <= 0) {
|
||||||
/* stop on error or if read(size) returned 0 */
|
/* stop on error or if read(size) returned 0 */
|
||||||
Py_FatalError("Failed to read bytes from /dev/urandom");
|
return -1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer += n;
|
buffer += n;
|
||||||
size -= n;
|
size -= n;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read size bytes from /dev/urandom into buffer.
|
/* Read size bytes from /dev/urandom into buffer.
|
||||||
|
@ -379,6 +377,40 @@ lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If raise is zero:
|
||||||
|
* - Don't raise exceptions on error
|
||||||
|
* - Don't call PyErr_CheckSignals() on EINTR (retry directly the interrupted
|
||||||
|
* syscall)
|
||||||
|
* - Don't release the GIL to call syscalls. */
|
||||||
|
static int
|
||||||
|
pyurandom(void *buffer, Py_ssize_t size, int raise)
|
||||||
|
{
|
||||||
|
if (size < 0) {
|
||||||
|
if (raise) {
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"negative argument not allowed");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
return win32_urandom((unsigned char *)buffer, size, raise);
|
||||||
|
#elif defined(PY_GETENTROPY)
|
||||||
|
return py_getentropy(buffer, size, raise);
|
||||||
|
#else
|
||||||
|
if (raise) {
|
||||||
|
return dev_urandom_python(buffer, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return dev_urandom_noraise(buffer, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill buffer with size pseudo-random bytes from the operating system random
|
/* Fill buffer with size pseudo-random bytes from the operating system random
|
||||||
number generator (RNG). It is suitable for most cryptographic purposes
|
number generator (RNG). It is suitable for most cryptographic purposes
|
||||||
except long living private keys for asymmetric encryption.
|
except long living private keys for asymmetric encryption.
|
||||||
|
@ -387,21 +419,7 @@ lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size)
|
||||||
int
|
int
|
||||||
_PyOS_URandom(void *buffer, Py_ssize_t size)
|
_PyOS_URandom(void *buffer, Py_ssize_t size)
|
||||||
{
|
{
|
||||||
if (size < 0) {
|
return pyurandom(buffer, size, 1);
|
||||||
PyErr_Format(PyExc_ValueError,
|
|
||||||
"negative argument not allowed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (size == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
|
||||||
return win32_urandom((unsigned char *)buffer, size, 1);
|
|
||||||
#elif defined(PY_GETENTROPY)
|
|
||||||
return py_getentropy(buffer, size, 0);
|
|
||||||
#else
|
|
||||||
return dev_urandom_python((char*)buffer, size);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -442,13 +460,14 @@ _PyRandom_Init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#ifdef MS_WINDOWS
|
int res;
|
||||||
(void)win32_urandom(secret, secret_size, 0);
|
|
||||||
#elif defined(PY_GETENTROPY)
|
/* _PyRandom_Init() is called very early in the Python initialization
|
||||||
(void)py_getentropy(secret, secret_size, 1);
|
* and so exceptions cannot be used. */
|
||||||
#else
|
res = pyurandom(secret, secret_size, 0);
|
||||||
dev_urandom_noraise(secret, secret_size);
|
if (res < 0) {
|
||||||
#endif
|
Py_FatalError("failed to get random numbers to initialize Python");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue