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

Skip to content

Commit bae2d62

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 87bddba commit bae2d62

6 files changed

Lines changed: 119 additions & 28 deletions

File tree

Lib/test/test_os.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,13 +1226,15 @@ def test_urandom_subprocess(self):
12261226
self.assertNotEqual(data1, data2)
12271227

12281228

1229-
HAVE_GETENTROPY = (sysconfig.get_config_var('HAVE_GETENTROPY') == 1)
1230-
HAVE_GETRANDOM = (sysconfig.get_config_var('HAVE_GETRANDOM_SYSCALL') == 1)
1231-
1232-
@unittest.skipIf(HAVE_GETENTROPY,
1233-
"getentropy() does not use a file descriptor")
1234-
@unittest.skipIf(HAVE_GETRANDOM,
1235-
"getrandom() does not use a file descriptor")
1229+
# os.urandom() doesn't use a file descriptor when it is implemented with the
1230+
# getentropy() function, the getrandom() function or the getrandom() syscall
1231+
OS_URANDOM_DONT_USE_FD = (
1232+
sysconfig.get_config_var('HAVE_GETENTROPY') == 1
1233+
or sysconfig.get_config_var('HAVE_GETRANDOM') == 1
1234+
or sysconfig.get_config_var('HAVE_GETRANDOM_SYSCALL') == 1)
1235+
1236+
@unittest.skipIf(OS_URANDOM_DONT_USE_FD ,
1237+
"os.random() does not use a file descriptor")
12361238
class URandomFDTests(unittest.TestCase):
12371239
@unittest.skipUnless(resource, "test requires the resource module")
12381240
def test_urandom_failure(self):

Misc/NEWS

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

14+
- Issue #25003: On Solaris 11.3 or newer, os.urandom() now uses the
15+
getrandom() function instead of the getentropy() function. The getentropy()
16+
function is blocking to generate very good quality entropy, os.urandom()
17+
doesn't need such high-quality entropy.
18+
1419
- Issue #25182: The stdprinter (used as sys.stderr before the io module is
1520
imported at startup) now uses the backslashreplace error handler.
1621

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 1
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 1
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 defined(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 defined(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 defined(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
@@ -16085,11 +16085,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
1608516085
#include <sys/syscall.h>
1608616086
1608716087
int main() {
16088-
const int flags = 0;
1608916088
char buffer[1];
16090-
int n;
16089+
const size_t buflen = sizeof(buffer);
16090+
const int flags = 0;
1609116091
/* ignore the result, Python checks for ENOSYS at runtime */
16092-
(void)syscall(SYS_getrandom, buffer, sizeof(buffer), flags);
16092+
(void)syscall(SYS_getrandom, buffer, buflen, flags);
1609316093
return 0;
1609416094
}
1609516095
@@ -16111,6 +16111,43 @@ $as_echo "#define HAVE_GETRANDOM_SYSCALL 1" >>confdefs.h
1611116111

1611216112
fi
1611316113

16114+
# check if the getrandom() function is available
16115+
# the test was written for the Solaris function of <sys/random.h>
16116+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the getrandom() function" >&5
16117+
$as_echo_n "checking for the getrandom() function... " >&6; }
16118+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
16119+
/* end confdefs.h. */
16120+
16121+
16122+
#include <sys/random.h>
16123+
16124+
int main() {
16125+
char buffer[1];
16126+
const size_t buflen = sizeof(buffer);
16127+
const int flags = 0;
16128+
/* ignore the result, Python checks for ENOSYS at runtime */
16129+
(void)getrandom(buffer, buflen, flags);
16130+
return 0;
16131+
}
16132+
16133+
16134+
_ACEOF
16135+
if ac_fn_c_try_link "$LINENO"; then :
16136+
have_getrandom=yes
16137+
else
16138+
have_getrandom=no
16139+
fi
16140+
rm -f core conftest.err conftest.$ac_objext \
16141+
conftest$ac_exeext conftest.$ac_ext
16142+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_getrandom" >&5
16143+
$as_echo "$have_getrandom" >&6; }
16144+
16145+
if test "$have_getrandom" = yes; then
16146+
16147+
$as_echo "#define HAVE_GETRANDOM 1" >>confdefs.h
16148+
16149+
fi
16150+
1611416151
# generate output files
1611516152
ac_config_files="$ac_config_files Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh"
1611616153

configure.ac

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5154,11 +5154,11 @@ AC_LINK_IFELSE(
51545154
#include <sys/syscall.h>
51555155
51565156
int main() {
5157-
const int flags = 0;
51585157
char buffer[1];
5159-
int n;
5158+
const size_t buflen = sizeof(buffer);
5159+
const int flags = 0;
51605160
/* ignore the result, Python checks for ENOSYS at runtime */
5161-
(void)syscall(SYS_getrandom, buffer, sizeof(buffer), flags);
5161+
(void)syscall(SYS_getrandom, buffer, buflen, flags);
51625162
return 0;
51635163
}
51645164
]])
@@ -5170,6 +5170,31 @@ if test "$have_getrandom_syscall" = yes; then
51705170
[Define to 1 if the Linux getrandom() syscall is available])
51715171
fi
51725172

5173+
# check if the getrandom() function is available
5174+
# the test was written for the Solaris function of <sys/random.h>
5175+
AC_MSG_CHECKING(for the getrandom() function)
5176+
AC_LINK_IFELSE(
5177+
[
5178+
AC_LANG_SOURCE([[
5179+
#include <sys/random.h>
5180+
5181+
int main() {
5182+
char buffer[1];
5183+
const size_t buflen = sizeof(buffer);
5184+
const int flags = 0;
5185+
/* ignore the result, Python checks for ENOSYS at runtime */
5186+
(void)getrandom(buffer, buflen, flags);
5187+
return 0;
5188+
}
5189+
]])
5190+
],[have_getrandom=yes],[have_getrandom=no])
5191+
AC_MSG_RESULT($have_getrandom)
5192+
5193+
if test "$have_getrandom" = yes; then
5194+
AC_DEFINE(HAVE_GETRANDOM, 1,
5195+
[Define to 1 if the getrandom() function is available])
5196+
fi
5197+
51735198
# generate output files
51745199
AC_CONFIG_FILES(Makefile.pre Modules/Setup.config Misc/python.pc Misc/python-config.sh)
51755200
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)