From c30924b77c585cf5a28e4eb34924892f8e7e73b4 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Tue, 21 Oct 2025 17:35:15 -0700 Subject: [PATCH v2 2/2] Support getrandom() as random source where available. Use glibc's getrandom() function when strong_random_source is set to 'system' on Linux and Unix-like operating systems. This method is much faster than reading from /dev/urandom. In particular, recent Linux kernels support a vDSO implementation of getrandom(), which our performance tests showed to be approximately 10x faster. Reviewed-by: Discussion: https://postgr.es/m/ --- configure | 7 +++++-- configure.ac | 5 ++++- meson.build | 1 + src/include/pg_config.h.in | 3 +++ src/port/pg_strong_random.c | 41 ++++++++++++++++++++++++++++++++----- 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/configure b/configure index c591f8d8fbd..1f269148851 100755 --- a/configure +++ b/configure @@ -15444,7 +15444,7 @@ fi LIBS_including_readline="$LIBS" LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'` -for ac_func in backtrace_symbols copyfile copy_file_range elf_aux_info getauxval getifaddrs getpeerucred inet_pton kqueue localeconv_l mbstowcs_l posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast strsignal syncfs sync_file_range uselocale wcstombs_l +for ac_func in backtrace_symbols copyfile copy_file_range elf_aux_info getauxval getifaddrs getpeerucred getrandom inet_pton kqueue localeconv_l mbstowcs_l posix_fallocate ppoll pthread_is_threaded_np setproctitle setproctitle_fast strsignal syncfs sync_file_range uselocale wcstombs_l do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -18326,6 +18326,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; } @@ -18355,7 +18358,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 bfdb764f059..0ceced87ada 100644 --- a/configure.ac +++ b/configure.ac @@ -1780,6 +1780,7 @@ AC_CHECK_FUNCS(m4_normalize([ getauxval getifaddrs getpeerucred + getrandom inet_pton kqueue localeconv_l @@ -2321,6 +2322,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 @@ -2330,7 +2333,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([STRONG_RANDOM_SOURCE_SYSTEM], 1, [Define to 1 to use system native source for strong random number generation]) diff --git a/meson.build b/meson.build index 90918fc12da..db55125a2bf 100644 --- a/meson.build +++ b/meson.build @@ -2892,6 +2892,7 @@ func_checks = [ ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}], ['getpeereid'], ['getpeerucred'], + ['getrandom'], ['inet_aton'], ['inet_pton'], ['kqueue'], diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 4aeceb53eb4..4534db6d0ef 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 0d3f00f588f..66ee335ce17 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. glibc's 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,12 +135,42 @@ pg_strong_random(void *buf, size_t len) return false; } -#else /* STRONG_RANDOM_SOURCE_SYSTEM and not WIN32 */ +#elif HAVE_GETRANDOM /* STRONG_RANDOM_SOURCE_SYSTEM and + * HAVE_GETRANDOM */ +#include -/* - * Without OpenSSL or Win32 support, just read /dev/urandom ourselves. - */ +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 OpenSSL, WIN32, or HAVE_GETRANDOM */ void pg_strong_random_init(void) { -- 2.47.3