Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3abf44e

Browse files
committed
Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the getrandom()
function instead of the getentropy() function. The getentropy() function is blocking to generate very good quality entropy, os.urandom() doesn't need such high-quality entropy.
1 parent 258f17c commit 3abf44e

5 files changed

Lines changed: 110 additions & 21 deletions

File tree

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ Release date: XXXX-XX-XX
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the
14+
getrandom() function instead of the getentropy() function. The getentropy()
15+
function is blocking to generate very good quality entropy, os.urandom()
16+
doesn't need such high-quality entropy.
17+
1318
- Issue #9232: Modify Python's grammar to allow trailing commas in the
1419
argument list of a function declaration. For example, "def f(*, a =
1520
3,): pass" is now legal. Patch from Mark Dickinson.

Python/random.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
# ifdef HAVE_SYS_STAT_H
77
# include <sys/stat.h>
88
# endif
9-
# ifdef HAVE_GETRANDOM_SYSCALL
9+
# ifdef HAVE_GETRANDOM
10+
# include <sys/random.h>
11+
# elif defined(HAVE_GETRANDOM_SYSCALL)
1012
# include <sys/syscall.h>
1113
# endif
1214
#endif
@@ -70,7 +72,9 @@ win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise)
7072
return 0;
7173
}
7274

73-
#elif HAVE_GETENTROPY
75+
#elif defined(HAVE_GETENTROPY) && !defined(sun)
76+
#define PY_GETENTROPY
77+
7478
/* Fill buffer with size pseudo-random bytes generated by getentropy().
7579
Return 0 on success, or raise an exception and return -1 on error.
7680
@@ -105,16 +109,19 @@ py_getentropy(unsigned char *buffer, Py_ssize_t size, int fatal)
105109
return 0;
106110
}
107111

108-
#else /* !HAVE_GETENTROPY */
112+
#else
113+
114+
#if defined(HAVE_GETRANDOM) || defined(HAVE_GETRANDOM_SYSCALL)
115+
#define PY_GETRANDOM
109116

110-
#ifdef HAVE_GETRANDOM_SYSCALL
111117
static int
112118
py_getrandom(void *buffer, Py_ssize_t size, int raise)
113119
{
114-
/* is getrandom() supported by the running kernel?
115-
* need Linux kernel 3.17 or later */
120+
/* Is getrandom() supported by the running kernel?
121+
* Need Linux kernel 3.17 or newer, or Solaris 11.3 or newer */
116122
static int getrandom_works = 1;
117-
/* Use /dev/urandom, block if the kernel has no entropy */
123+
/* Use non-blocking /dev/urandom device. On Linux at boot, the getrandom()
124+
* syscall blocks until /dev/urandom is initialized with enough entropy. */
118125
const int flags = 0;
119126
int n;
120127

@@ -124,7 +131,18 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
124131
while (0 < size) {
125132
errno = 0;
126133

127-
/* Use syscall() because the libc doesn't expose getrandom() yet, see:
134+
#ifdef HAVE_GETRANDOM
135+
if (raise) {
136+
Py_BEGIN_ALLOW_THREADS
137+
n = getrandom(buffer, size, flags);
138+
Py_END_ALLOW_THREADS
139+
}
140+
else {
141+
n = getrandom(buffer, size, flags);
142+
}
143+
#else
144+
/* On Linux, use the syscall() function because the GNU libc doesn't
145+
* expose the Linux getrandom() syscall yet. See:
128146
* https://sourceware.org/bugzilla/show_bug.cgi?id=17252 */
129147
if (raise) {
130148
Py_BEGIN_ALLOW_THREADS
@@ -134,6 +152,7 @@ py_getrandom(void *buffer, Py_ssize_t size, int raise)
134152
else {
135153
n = syscall(SYS_getrandom, buffer, size, flags);
136154
}
155+
#endif
137156

138157
if (n < 0) {
139158
if (errno == ENOSYS) {
@@ -182,7 +201,7 @@ dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
182201

183202
assert (0 < size);
184203

185-
#ifdef HAVE_GETRANDOM_SYSCALL
204+
#ifdef PY_GETRANDOM
186205
if (py_getrandom(buffer, size, 0) == 1)
187206
return;
188207
/* getrandom() is not supported by the running kernel, fall back
@@ -218,14 +237,14 @@ dev_urandom_python(char *buffer, Py_ssize_t size)
218237
int fd;
219238
Py_ssize_t n;
220239
struct _Py_stat_struct st;
221-
#ifdef HAVE_GETRANDOM_SYSCALL
240+
#ifdef PY_GETRANDOM
222241
int res;
223242
#endif
224243

225244
if (size <= 0)
226245
return 0;
227246

228-
#ifdef HAVE_GETRANDOM_SYSCALL
247+
#ifdef PY_GETRANDOM
229248
res = py_getrandom(buffer, size, 1);
230249
if (res < 0)
231250
return -1;
@@ -304,7 +323,7 @@ dev_urandom_close(void)
304323
}
305324
}
306325

307-
#endif /* HAVE_GETENTROPY */
326+
#endif
308327

309328
/* Fill buffer with pseudo-random bytes generated by a linear congruent
310329
generator (LCG):
@@ -345,7 +364,7 @@ _PyOS_URandom(void *buffer, Py_ssize_t size)
345364

346365
#ifdef MS_WINDOWS
347366
return win32_urandom((unsigned char *)buffer, size, 1);
348-
#elif HAVE_GETENTROPY
367+
#elif PY_GETENTROPY
349368
return py_getentropy(buffer, size, 0);
350369
#else
351370
return dev_urandom_python((char*)buffer, size);
@@ -392,7 +411,7 @@ _PyRandom_Init(void)
392411
else {
393412
#ifdef MS_WINDOWS
394413
(void)win32_urandom(secret, secret_size, 0);
395-
#elif HAVE_GETENTROPY
414+
#elif PY_GETENTROPY
396415
(void)py_getentropy(secret, secret_size, 1);
397416
#else
398417
dev_urandom_noraise(secret, secret_size);
@@ -408,7 +427,7 @@ _PyRandom_Fini(void)
408427
CryptReleaseContext(hCryptProv, 0);
409428
hCryptProv = 0;
410429
}
411-
#elif HAVE_GETENTROPY
430+
#elif PY_GETENTROPY
412431
/* nothing to clean */
413432
#else
414433
dev_urandom_close();

configure

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16005,11 +16005,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
1600516005
#include <sys/syscall.h>
1600616006
1600716007
int main() {
16008-
const int flags = 0;
1600916008
char buffer[1];
16010-
int n;
16009+
const size_t buflen = sizeof(buffer);
16010+
const int flags = 0;
1601116011
/* ignore the result, Python checks for ENOSYS at runtime */
16012-
(void)syscall(SYS_getrandom, buffer, sizeof(buffer), flags);
16012+
(void)syscall(SYS_getrandom, buffer, buflen, flags);
1601316013
return 0;
1601416014
}
1601516015
@@ -16031,6 +16031,43 @@ $as_echo "#define HAVE_GETRANDOM_SYSCALL 1" >>confdefs.h
1603116031

1603216032
fi
1603316033

16034+
# check if the getrandom() function is available
16035+
# the test was written for the Solaris function of <sys/random.h>
16036+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the getrandom() function" >&5
16037+
$as_echo_n "checking for the getrandom() function... " >&6; }
16038+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
16039+
/* end confdefs.h. */
16040+
16041+
16042+
#include <sys/random.h>
16043+
16044+
int main() {
16045+
char buffer[1];
16046+
const size_t buflen = sizeof(buffer);
16047+
const int flags = 0;
16048+
/* ignore the result, Python checks for ENOSYS at runtime */
16049+
(void)getrandom(buffer, buflen, flags);
16050+
return 0;
16051+
}
16052+
16053+
16054+
_ACEOF
16055+
if ac_fn_c_try_link "$LINENO"; then :
16056+
have_getrandom=yes
16057+
else
16058+
have_getrandom=no
16059+
fi
16060+
rm -f core conftest.err conftest.$ac_objext \
16061+
conftest$ac_exeext conftest.$ac_ext
16062+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_getrandom" >&5
16063+
$as_echo "$have_getrandom" >&6; }
16064+
16065+
if test "$have_getrandom" = yes; then
16066+
16067+
$as_echo "#define HAVE_GETRANDOM 1" >>confdefs.h
16068+
16069+
fi
16070+
1603416071
# generate output files
1603516072
ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh"
1603616073

configure.ac

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5111,11 +5111,11 @@ AC_LINK_IFELSE(
51115111
#include <sys/syscall.h>
51125112
51135113
int main() {
5114-
const int flags = 0;
51155114
char buffer[1];
5116-
int n;
5115+
const size_t buflen = sizeof(buffer);
5116+
const int flags = 0;
51175117
/* ignore the result, Python checks for ENOSYS at runtime */
5118-
(void)syscall(SYS_getrandom, buffer, sizeof(buffer), flags);
5118+
(void)syscall(SYS_getrandom, buffer, buflen, flags);
51195119
return 0;
51205120
}
51215121
]])
@@ -5127,6 +5127,31 @@ if test "$have_getrandom_syscall" = yes; then
51275127
[Define to 1 if the Linux getrandom() syscall is available])
51285128
fi
51295129

5130+
# check if the getrandom() function is available
5131+
# the test was written for the Solaris function of <sys/random.h>
5132+
AC_MSG_CHECKING(for the getrandom() function)
5133+
AC_LINK_IFELSE(
5134+
[
5135+
AC_LANG_SOURCE([[
5136+
#include <sys/random.h>
5137+
5138+
int main() {
5139+
char buffer[1];
5140+
const size_t buflen = sizeof(buffer);
5141+
const int flags = 0;
5142+
/* ignore the result, Python checks for ENOSYS at runtime */
5143+
(void)getrandom(buffer, buflen, flags);
5144+
return 0;
5145+
}
5146+
]])
5147+
],[have_getrandom=yes],[have_getrandom=no])
5148+
AC_MSG_RESULT($have_getrandom)
5149+
5150+
if test "$have_getrandom" = yes; then
5151+
AC_DEFINE(HAVE_GETRANDOM, 1,
5152+
[Define to 1 if the getrandom() function is available])
5153+
fi
5154+
51305155
# generate output files
51315156
AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh)
51325157
AC_CONFIG_FILES([Modules/ld_so_aix], [chmod +x Modules/ld_so_aix])

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,9 @@
395395
/* Define to 1 if you have the `getpwent' function. */
396396
#undef HAVE_GETPWENT
397397

398+
/* Define to 1 if the getrandom() function is available */
399+
#undef HAVE_GETRANDOM
400+
398401
/* Define to 1 if the Linux getrandom() syscall is available */
399402
#undef HAVE_GETRANDOM_SYSCALL
400403

0 commit comments

Comments
 (0)