From b607bfdc51ebe6401f32d01d3b614b818be1c645 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 23 Sep 2025 00:24:12 -0700
Subject: [PATCH 2/2] PoC: Support getrandom() as the source of
 pg_strong_random().

getrandom() is the default random generation function when
random_source_type is set to 'system'.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch-through:
---
 configure                   | 19 +++++++++++++++++++
 configure.ac                |  4 ++++
 meson.build                 |  6 ++++++
 src/include/pg_config.h.in  |  3 +++
 src/include/port.h          |  4 ++--
 src/port/pg_strong_random.c | 38 ++++++++++++++++++++++++++++++++++++-
 6 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/configure b/configure
index 22cd866147b..08b8f04285f 100755
--- a/configure
+++ b/configure
@@ -18321,6 +18321,25 @@ PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of ra
   fi
 fi
 
+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
+
+
+
 # If not set in template file, set bytes to use libc memset()
 if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
   MEMSET_LOOP_LIMIT=1024
diff --git a/configure.ac b/configure.ac
index e44943aa6fe..71be1318be6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2317,6 +2317,10 @@ PostgreSQL can use OpenSSL, native Windows API or /dev/urandom as a source of ra
   fi
 fi
 
+AC_CHECK_HEADER([sys/random.h],
+ [AC_CHECK_FUNCS([getrandom],
+  [AC_DEFINE(HAVE_GETRANDOM, 1, [Define to 1 if you have getrandom])])])
+
 # If not set in template file, set bytes to use libc memset()
 if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
   MEMSET_LOOP_LIMIT=1024
diff --git a/meson.build b/meson.build
index 395416a6060..3d9a9ce2e9a 100644
--- a/meson.build
+++ b/meson.build
@@ -2713,6 +2713,12 @@ int main(void)
   endif
 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('socklen_t',
     args: test_c_args, include_directories: postgres_inc,
     prefix: '''
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/include/port.h b/src/include/port.h
index d7464c231a5..af1ebce15de 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -520,8 +520,8 @@ typedef void (*pg_strong_random_init_fn) (void);
 typedef bool (*pg_strong_random_fn) (void *buf, size_t len);
 
 /* Function pointers to the random data generation implementations */
-extern pg_strong_random_init_fn pg_strong_random_init_impl;
-extern pg_strong_random_fn pg_strong_random_impl;
+extern PGDLLIMPORT pg_strong_random_init_fn pg_strong_random_init_impl;
+extern PGDLLIMPORT pg_strong_random_fn pg_strong_random_impl;
 
 /*
  * Public functions to generate strong random data. The functions invoked
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index 231995e42af..6024efd0bbd 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -151,7 +151,43 @@ pg_strong_random_system(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not WIN32 */
+#elif HAVE_GETRANDOM
+
+#include <sys/random.h>
+
+void
+pg_strong_random_init_system(void)
+{
+	/* No initialization needed */
+}
+
+bool
+pg_strong_random_system(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
 
 /*
  * On Unix-like platforms, just read /dev/urandom ourselves.
-- 
2.47.3

