From 8de85697dd0c8d334168749d2e104a97a455d395 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 21 Oct 2025 17:35:15 -0700 Subject: [PATCH v1 2/2] Support getrandom() as random source where available. getrandom system call is used when random_source is 'system' on Linux and Unix-like operating systems. It's more faster than reading /dev/urandom. Reviewed-by: Discussion: https://postgr.es/m/ Backpatch-through: --- configure | 24 +++++++++++++++++++++- configure.ac | 8 +++++++- meson.build | 5 +++++ src/include/pg_config.h.in | 3 +++ src/port/pg_strong_random.c | 40 +++++++++++++++++++++++++++++++++++-- 5 files changed, 76 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 809691fd61c..bee4d57131b 100755 --- a/configure +++ b/configure @@ -16058,6 +16058,25 @@ cat >>confdefs.h <<_ACEOF _ACEOF +ac_fn_c_check_header_mongrel "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_random_h" = xyes; then : + for ac_func in getrandom +do : + ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom" +if test "x$ac_cv_func_getrandom" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETRANDOM 1 +_ACEOF + +$as_echo "#define HAVE_GETRANDOM 1" >>confdefs.h + +fi +done + +fi + + + ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" if test "x$ac_cv_func_explicit_bzero" = xyes; then : $as_echo "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h @@ -18336,6 +18355,9 @@ else if test x"$PORTNAME" = x"win32" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5 $as_echo "Windows native" >&6; } + elif test x"$ac_cv_func_getrandom" = x"yes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: getrandom" >&5 +$as_echo "getrandom" >&6; } elif test x"$cross_compiling" = x"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5 $as_echo "assuming /dev/urandom" >&6; } @@ -18365,7 +18387,7 @@ fi if test x"$ac_cv_file__dev_urandom" = x"no" ; then as_fn_error $? " no source of strong random numbers was found -PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers." "$LINENO" 5 +PostgreSQL can use OpenSSL, native Windows API, getrandom, or /dev/urandom as a source of random numbers." "$LINENO" 5 fi fi diff --git a/configure.ac b/configure.ac index 2690b71527b..2a4ef82e145 100644 --- a/configure.ac +++ b/configure.ac @@ -1842,6 +1842,10 @@ AC_CHECK_DECLS([memset_s], [], [], [#define __STDC_WANT_LIB_EXT1__ 1 # This is probably only present on macOS, but may as well check always AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include ]) +AC_CHECK_HEADER([sys/random.h], + [AC_CHECK_FUNCS([getrandom], + [AC_DEFINE(HAVE_GETRANDOM, 1, [Define to 1 if you have getrandom])])]) + AC_REPLACE_FUNCS(m4_normalize([ explicit_bzero getopt @@ -2328,6 +2332,8 @@ else # be used. if test x"$PORTNAME" = x"win32" ; then AC_MSG_RESULT([Windows native]) + elif test x"$ac_cv_func_getrandom" = x"yes" ; then + AC_MSG_RESULT(getrandom) elif test x"$cross_compiling" = x"yes"; then AC_MSG_RESULT([assuming /dev/urandom]) else @@ -2337,7 +2343,7 @@ else if test x"$ac_cv_file__dev_urandom" = x"no" ; then AC_MSG_ERROR([ no source of strong random numbers was found -PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of random numbers.]) +PostgreSQL can use OpenSSL, native Windows API, getrandom, or /dev/urandom as a source of random numbers.]) fi fi AC_DEFINE([USE_RANDOM_SOURCE_SYSTEM] , 1, [Define to 1 to use system native source for random number generation]) diff --git a/meson.build b/meson.build index fce1e1436e7..01c3c308b65 100644 --- a/meson.build +++ b/meson.build @@ -2710,6 +2710,11 @@ return 0; don't.'''.format(func)) endforeach +if cc.has_header('sys/random.h') and cc.has_function('getrandom', + args: test_c_args, prefix: ''' +#include ''') + cdata.set('HAVE_GETRANDOM', 1) +endif if cc.has_type('struct option', args: test_c_args, include_directories: postgres_inc, diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 35543a3e3c6..bf76baf0617 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -190,6 +190,9 @@ /* Define to 1 if you have the `getpeerucred' function. */ #undef HAVE_GETPEERUCRED +/* Define to 1 if you have the `getrandom' function. */ +#undef HAVE_GETRANDOM + /* Define to 1 if you have the header file. */ #undef HAVE_GSSAPI_EXT_H diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c index ea6780dcc9f..0d2b5bc8ad5 100644 --- a/src/port/pg_strong_random.c +++ b/src/port/pg_strong_random.c @@ -40,7 +40,8 @@ * * 1. OpenSSL's RAND_bytes() * 2. Windows' CryptGenRandom() function - * 3. /dev/urandom + * 3. getrandom() function + * 4. /dev/urandom * * Returns true on success, and false if none of the sources * were available. NB: It is important to check the return value! @@ -134,7 +135,42 @@ pg_strong_random(void *buf, size_t len) return false; } -#else /* not USE_OPENSSL or WIN32 */ +#elif HAVE_GETRANDOM + +#include + +void +pg_strong_random_init(void) +{ + /* No initialization needed */ +} + +bool +pg_strong_random(void *buf, size_t len) +{ + char *p = buf; + ssize_t res; + + while (len) + { + /* Get random data from the urandom source in blocking mode */ + res = getrandom(p, len, 0); + if (res <= 0) + { + if (errno == EINTR) + continue; /* interrupted by signal, just retry */ + + return false; + } + + p += res; + len -= res; + } + + return true; +} + +#else /* not USE_OPENSSL, WIN32, or HAVE_GETRANDOM */ /* * Without OpenSSL or Win32 support, just read /dev/urandom ourselves. -- 2.47.3