From 63df3df8c21abdf77ac2e696c9a16919a04bc1db Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Mon, 21 Jul 2025 23:02:24 -0700
Subject: [PATCH v1] Support getrandom() as the source of pg_strong_random()
 where available.

Author:
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 | 42 ++++++++++++++++++++++++++++++++++---
 5 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/configure b/configure
index 6d7c22e153f..79f865a00c5 100755
--- a/configure
+++ b/configure
@@ -16243,6 +16243,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
@@ -18476,6 +18495,9 @@ $as_echo "Windows native" >&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; }
+elif test x"$ac_cv_func_getrandom" = x"yes"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: getrandom" >&5
+$as_echo "getrandom" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
@@ -18502,7 +18524,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 function, or /dev/urandom as a source of random numbers." "$LINENO" 5
   fi
 fi
 
diff --git a/configure.ac b/configure.ac
index c2877e36935..de6fe13a376 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1850,6 +1850,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 <fcntl.h>])
 
+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
@@ -2311,6 +2315,8 @@ elif test x"$PORTNAME" = x"win32" ; then
   AC_MSG_RESULT([Windows native])
 elif test x"$cross_compiling" = x"yes"; then
   AC_MSG_RESULT([assuming /dev/urandom])
+elif test x"$ac_cv_func_getrandom" = x"yes"; then
+  AC_MSG_RESULT(getrandom)
 else
   AC_MSG_RESULT([/dev/urandom])
   AC_CHECK_FILE([/dev/urandom], [], [])
@@ -2318,7 +2324,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 function, or /dev/urandom as a source of random numbers.])
   fi
 fi
 
diff --git a/meson.build b/meson.build
index 5365aaf95e6..753227ee31c 100644
--- a/meson.build
+++ b/meson.build
@@ -2708,6 +2708,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 <sys/random.h>''')
+  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 c4dc5d72bdb..aa742d20b18 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 <gssapi_ext.h> 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..028537ba9a9 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,10 +135,45 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#elif HAVE_GETRANDOM
+
+#include <sys/random.h>
+
+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(buf, 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.
+ * Without OpenSSL, Win32, or getrandom() support, just read /dev/urandom ourselves.
  */
 
 void
-- 
2.43.5

