Support getrandom() for pg_strong_random() source

Started by Masahiko Sawada6 months ago67 messages
#1Masahiko Sawada
sawada.mshk@gmail.com
1 attachment(s)

Hi all,

Currently we have three options for pg_strong_random() sources:

1. OpenSSL's RAND_bytes()
2. Windows' CryptGenRandom() function
3. /dev/urandom

The patch supports the getrandom() function as a new source of
pg_strong_random(). The getrandom() function uses the same source as
the /dev/urandom device but it seems much faster than opening,
reading, and closing /dev/urandom. Here is the execution time of
generating 1 million UUIDv4 data measured on my environment:

HEAD(/dev/urandom): 1863.064 ms
Patched(getrandom()): 516.627 ms

I guess that while OpenSSL's RAND_bytes() should still be prioritized
where available it might be a good idea to support getrandom() for
builds where RAND_bytes() is not available.

Feedback is very welcome.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-Support-getrandom-as-the-source-of-pg_strong_rand.patchapplication/octet-stream; name=v1-0001-Support-getrandom-as-the-source-of-pg_strong_rand.patchDownload
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

#2Michael Paquier
michael@paquier.xyz
In reply to: Masahiko Sawada (#1)
Re: Support getrandom() for pg_strong_random() source

On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:

The patch supports the getrandom() function as a new source of
pg_strong_random(). The getrandom() function uses the same source as
the /dev/urandom device but it seems much faster than opening,
reading, and closing /dev/urandom. Here is the execution time of
generating 1 million UUIDv4 data measured on my environment:

HEAD(/dev/urandom): 1863.064 ms
Patched(getrandom()): 516.627 ms

Interesting. Are there platforms where this is not available? I'd be
pretty sure that some animals in the buildfarm would not like this
suggestion but I'm saying it anyway. Perhaps we could even drop
/dev/urandom?

I guess that while OpenSSL's RAND_bytes() should still be prioritized
where available it might be a good idea to support getrandom() for
builds where RAND_bytes() is not available.

Feedback is very welcome.

I am wondering how much non-OpenSSL builds matter these days, TBH, so
I am not sure that this is worth the addition of an extra
configure/meson check and this stuff has its cost just for such
builds. I am not saying that we should make OpenSSL mandatory, of
course not, but all production instances of Postgres have likely
OpenSSL enabled anyway. Perhaps some embedded deployments like
--without-openssl, who knows..
--
Michael

#3Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Michael Paquier (#2)
Re: Support getrandom() for pg_strong_random() source

On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:

On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:

The patch supports the getrandom() function as a new source of
pg_strong_random(). The getrandom() function uses the same source as
the /dev/urandom device but it seems much faster than opening,
reading, and closing /dev/urandom. Here is the execution time of
generating 1 million UUIDv4 data measured on my environment:

HEAD(/dev/urandom): 1863.064 ms
Patched(getrandom()): 516.627 ms

Interesting. Are there platforms where this is not available? I'd be
pretty sure that some animals in the buildfarm would not like this
suggestion but I'm saying it anyway. Perhaps we could even drop
/dev/urandom?

As far as I know macOS doesn't support getrandom() but supports
getentropy() instead. And an older glibc version might not support it.
It's supported since Linux 3.17 and glibc 2.25.

I guess that while OpenSSL's RAND_bytes() should still be prioritized
where available it might be a good idea to support getrandom() for
builds where RAND_bytes() is not available.

Feedback is very welcome.

I am wondering how much non-OpenSSL builds matter these days, TBH, so
I am not sure that this is worth the addition of an extra
configure/meson check and this stuff has its cost just for such
builds. I am not saying that we should make OpenSSL mandatory, of
course not, but all production instances of Postgres have likely
OpenSSL enabled anyway. Perhaps some embedded deployments like
--without-openssl, who knows..

Fair point. In fact, I was not using OpenSSL and just realized
generating UUID by PostgreSQL's uuidv4() and uuidv7() was much slower
than generating it by Rust's UUID crate. On my environment,
getrandom() is faster than RAND_bytes() so I thought there are some
cases where users want to use the getrandom() source rather than
RAND_bytes(), but I'm not sure since there is also a difference in the
secureness.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

In reply to: Masahiko Sawada (#3)
Re: Support getrandom() for pg_strong_random() source

Masahiko Sawada <sawada.mshk@gmail.com> writes:

On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:

On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:

The patch supports the getrandom() function as a new source of
pg_strong_random(). The getrandom() function uses the same source as
the /dev/urandom device but it seems much faster than opening,
reading, and closing /dev/urandom. Here is the execution time of
generating 1 million UUIDv4 data measured on my environment:

HEAD(/dev/urandom): 1863.064 ms
Patched(getrandom()): 516.627 ms

Interesting. Are there platforms where this is not available? I'd be
pretty sure that some animals in the buildfarm would not like this
suggestion but I'm saying it anyway. Perhaps we could even drop
/dev/urandom?

As far as I know macOS doesn't support getrandom() but supports
getentropy() instead. And an older glibc version might not support it.
It's supported since Linux 3.17 and glibc 2.25.

getrandom() is Linux-specific, while getentropy() is specified by POSIX
(since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024

Sources:

https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html
https://dotat.at/@/2024-10-01-getentropy.html

So I think it's more worthwhile to add support for getentropy() than
getrandom().

- ilmari

#5Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Dagfinn Ilmari Mannsåker (#4)
Re: Support getrandom() for pg_strong_random() source

On Tue, Jul 22, 2025 at 4:12 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:

Masahiko Sawada <sawada.mshk@gmail.com> writes:

On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:

On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:

The patch supports the getrandom() function as a new source of
pg_strong_random(). The getrandom() function uses the same source as
the /dev/urandom device but it seems much faster than opening,
reading, and closing /dev/urandom. Here is the execution time of
generating 1 million UUIDv4 data measured on my environment:

HEAD(/dev/urandom): 1863.064 ms
Patched(getrandom()): 516.627 ms

Interesting. Are there platforms where this is not available? I'd be
pretty sure that some animals in the buildfarm would not like this
suggestion but I'm saying it anyway. Perhaps we could even drop
/dev/urandom?

As far as I know macOS doesn't support getrandom() but supports
getentropy() instead. And an older glibc version might not support it.
It's supported since Linux 3.17 and glibc 2.25.

getrandom() is Linux-specific, while getentropy() is specified by POSIX
(since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024

Sources:

https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html
https://dotat.at/@/2024-10-01-getentropy.html

So I think it's more worthwhile to add support for getentropy() than
getrandom().

While getentropy() has better portability, according to the
getentropy() manual, the maximum length is limited to 256 bytes. It
works in some cases such as generating UUID data but seems not
appropriate for our general pg_strong_random() use cases.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#6Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#5)
Re: Support getrandom() for pg_strong_random() source

On Tue, Jul 22, 2025 at 11:32 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

While getentropy() has better portability, according to the
getentropy() manual, the maximum length is limited to 256 bytes. It
works in some cases such as generating UUID data but seems not
appropriate for our general pg_strong_random() use cases.

I imagine that the code would look very similar to your patch, though
(loop, in chunks of size GETENTROPY_MAX, until the required length is
met). Without looking too deeply, I have to say that implementing a
newer POSIX API as opposed to a Linux-specific one does seem like a
better cost-benefit tradeoff, if we decide to do this.

Can you talk more about this part:

On my environment,
getrandom() is faster than RAND_bytes() so I thought there are some
cases where users want to use the getrandom() source rather than
RAND_bytes(), but I'm not sure since there is also a difference in the
secureness.

That is _really_ surprising to me at first glance. I thought
RAND_bytes() was supposed to be a userspace PRNG, which I would
naively expect to take much less time than pulling data from Linux.
(Once the OpenSSL PRNG has been seeded, that is.) Are there any other
details about your environment (or the test itself) that are unusual?

Thanks,
--Jacob

#7DINESH  NAIR
Dinesh_Nair@iitmpravartak.net
In reply to: Masahiko Sawada (#5)
Re: Support getrandom() for pg_strong_random() source

Hi ,

            On Tue, Jul 22, 2025 at 4:12 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:

Masahiko Sawada <sawada.mshk@gmail.com> writes:

On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:

On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:

The patch supports the getrandom() function as a new source of
pg_strong_random(). The getrandom() function uses the same source as
the /dev/urandom device but it seems much faster than opening,
reading, and closing /dev/urandom. Here is the execution time of
generating 1 million UUIDv4 data measured on my environment:

HEAD(/dev/urandom): 1863.064 ms
Patched(getrandom()): 516.627 ms

Interesting. Are there platforms where this is not available? I'd be
pretty sure that some animals in the buildfarm would not like this
suggestion but I'm saying it anyway. Perhaps we could even drop
/dev/urandom?

As far as I know macOS doesn't support getrandom() but supports
getentropy() instead. And an older glibc version might not support it.
It's supported since Linux 3.17 and glibc 2.25.

getrandom() is Linux-specific, while getentropy() is specified by POSIX
(since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024

Sources:
While getentropy() has better portability, according to the
getentropy() manual, the maximum length is limited to 256 bytes. It
works in some cases such as generating UUID data but seems not
appropriate for our general pg_strong_random() use cases.

The getentropy() function has a limitation of generating a maximum of 256 bytes of entropy per call and is not supported on Windows platforms. For cryptographic operations that require large buffers of high-quality randomness efficiently, it's not recommended to use getentropy().
https://brandur.org/fragments/secure-bytes-without-pgcrypto
A few secure, random bytes without `pgcrypto` — brandur.org<https://brandur.org/fragments/secure-bytes-without-pgcrypto&gt;
In Postgres it’s common to see the SQL random() function used to generate a random number, but it’s a pseudo-random number generator, and not suitable for cases where real randomness is required critical. Postgres also provides a way of getting secure random numbers as well, but only through the use of the pgcrypto extension, which makes gen_random_bytes available. Pulling pgcrypto into ...
brandur.org

Thanks

Regards

Dinesh Nair

________________________________
From: Masahiko Sawada <sawada.mshk@gmail.com>
Sent: Wednesday, July 23, 2025 12:02 AM
To: Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>
Cc: Michael Paquier <michael@paquier.xyz>; PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: Re: Support getrandom() for pg_strong_random() source

Caution: This email was sent from an external source. Please verify the sender’s identity before clicking links or opening attachments.

On Tue, Jul 22, 2025 at 4:12 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:

Masahiko Sawada <sawada.mshk@gmail.com> writes:

On Tue, Jul 22, 2025 at 12:13 AM Michael Paquier <michael@paquier.xyz> wrote:

On Mon, Jul 21, 2025 at 11:43:35PM -0700, Masahiko Sawada wrote:

The patch supports the getrandom() function as a new source of
pg_strong_random(). The getrandom() function uses the same source as
the /dev/urandom device but it seems much faster than opening,
reading, and closing /dev/urandom. Here is the execution time of
generating 1 million UUIDv4 data measured on my environment:

HEAD(/dev/urandom): 1863.064 ms
Patched(getrandom()): 516.627 ms

Interesting. Are there platforms where this is not available? I'd be
pretty sure that some animals in the buildfarm would not like this
suggestion but I'm saying it anyway. Perhaps we could even drop
/dev/urandom?

As far as I know macOS doesn't support getrandom() but supports
getentropy() instead. And an older glibc version might not support it.
It's supported since Linux 3.17 and glibc 2.25.

getrandom() is Linux-specific, while getentropy() is specified by POSIX
(since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024

Sources:

https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpubs.opengroup.org%2Fonlinepubs%2F9799919799%2Ffunctions%2Fgetentropy.html&amp;data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824005298%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&amp;sdata=C5abb70MrRMb8YrRpFZreelrwfXgKtxWYNWvEc3oPFg%3D&amp;reserved=0&lt;https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html&gt;
https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdotat.at%2F%40%2F2024-10-01-getentropy.html&amp;data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824035506%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&amp;sdata=RwqnnTVGURh7kw31OLW0kRUu%2BCUVVRlt%2Fx9FDDesb58%3D&amp;reserved=0&lt;https://dotat.at/@/2024-10-01-getentropy.html&gt;

So I think it's more worthwhile to add support for getentropy() than
getrandom().

While getentropy() has better portability, according to the
getentropy() manual, the maximum length is limited to 256 bytes. It
works in some cases such as generating UUID data but seems not
appropriate for our general pg_strong_random() use cases.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://ind01.safelinks.protection.outlook.com/?url=https%3A%2F%2Faws.amazon.com%2F&amp;data=05%7C02%7Cdinesh_nair%40iitmpravartak.net%7C6063a2ac8d4f45e1a74808ddc94e2e4e%7C3e964837c2384683915549f4ec04f8e9%7C0%7C0%7C638888059824052980%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&amp;sdata=NNEQNe%2Fibr6VRZAmBPWTy6r5J4pH2yza4PVGA4E9LO4%3D&amp;reserved=0&lt;https://aws.amazon.com/&gt;

#8Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#6)
Re: Support getrandom() for pg_strong_random() source

On Tue, Jul 22, 2025 at 11:46 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Tue, Jul 22, 2025 at 11:32 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

While getentropy() has better portability, according to the
getentropy() manual, the maximum length is limited to 256 bytes. It
works in some cases such as generating UUID data but seems not
appropriate for our general pg_strong_random() use cases.

I imagine that the code would look very similar to your patch, though
(loop, in chunks of size GETENTROPY_MAX, until the required length is
met). Without looking too deeply, I have to say that implementing a
newer POSIX API as opposed to a Linux-specific one does seem like a
better cost-benefit tradeoff, if we decide to do this.

Can you talk more about this part:

On my environment,
getrandom() is faster than RAND_bytes() so I thought there are some
cases where users want to use the getrandom() source rather than
RAND_bytes(), but I'm not sure since there is also a difference in the
secureness.

That is _really_ surprising to me at first glance. I thought
RAND_bytes() was supposed to be a userspace PRNG, which I would
naively expect to take much less time than pulling data from Linux.
(Once the OpenSSL PRNG has been seeded, that is.) Are there any other
details about your environment (or the test itself) that are unusual?

Yes, it surprised me too. The environment I used for this benchmark was:

% cat /etc/redhat-release
Red Hat Enterprise Linux release 8.10 (Ootpa)
% uname -r
4.18.0-553.22.1.el8_10.x86_64
% rpm -qa | grep openssl
openssl-libs-1.1.1k-14.el8_6.x86_64
openssl-debugsource-1.1.1k-14.el8_6.x86_64
rubygem-openssl-2.1.2-114.module+el8.10.0+23088+750dc6ca.x86_64
openssl-devel-1.1.1k-14.el8_6.x86_64
openssl-pkcs11-0.4.10-3.el8.x86_64
openssl-1.1.1k-14.el8_6.x86_64
openssl-debuginfo-1.1.1k-14.el8_6.x86_64
% openssl version
OpenSSL 1.1.1k FIPS 25 Mar 2021

and I measured the execution time of the following query:

explain analyze select uuidv4() from generate_series(1, 1_000_000);

The result is:

getrandom: 517.120ms
RAND_bytes: 1150.051 ms
/dev/urandom: 1862.483 ms

Since on the above environment I used an old Linux kernel and openssl
version, I've does the same benchmark on another environment:

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.2 LTS
Release: 24.04
Codename: noble
$ apt list --installed | grep ssl
libssl-dev/noble-updates,noble-security,now 3.0.13-0ubuntu3.5 amd64 [installed]
libssl3t64/noble-updates,noble-security,now 3.0.13-0ubuntu3.5 amd64
[installed,automatic]
libxmlsec1t64-openssl/noble,now 1.2.39-5build2 amd64 [installed,automatic]
openssl/noble-updates,noble-security,now 3.0.13-0ubuntu3.5 amd64
[installed,automatic]
python3-openssl/noble,now 23.2.0-1 all [installed,automatic]
ssl-cert/noble,now 1.1.2ubuntu1 all [installed,automatic]

The trend of the results were similar:

getrandom: 497.061 ms
RAND_bytes: 1152.260 ms ms
/dev/urandom: 1696.065 ms

Please let me know if I'm missing configurations or settings to
measure this workload properly.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#9Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#8)
Re: Support getrandom() for pg_strong_random() source

On Tue, Jul 22, 2025 at 4:23 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

The trend of the results were similar:

getrandom: 497.061 ms
RAND_bytes: 1152.260 ms ms
/dev/urandom: 1696.065 ms

Please let me know if I'm missing configurations or settings to
measure this workload properly.

I don't think you're missing anything, or else I'm missing something
too. If I modify pg_strong_random() to call getentropy() in addition
to the existing RAND_bytes() code, `perf` shows RAND_bytes() taking up
2.4x the samples that getentropy() does. That's very similar to your
results.

On Tue, Jul 22, 2025 at 11:46 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

That is _really_ surprising to me at first glance. I thought
RAND_bytes() was supposed to be a userspace PRNG, which I would
naively expect to take much less time than pulling data from Linux.

So my expectation was naive for sure. This has sent me down a bit of a
rabbit hole, starting with Adam Langley's BoringSSL post [1]https://www.imperialviolet.org/2015/10/17/boringssl.html which led
to a post/rant on urandom [2]https://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/. I don't think an API that advertises
"strong randomness" should ever prioritize performance over strength.
But maybe the pendulum has swung far enough that we can expect any
kernel supporting getentropy() to be able to do the job just as well
as OpenSSL does in userspace, except also faster? I think it might be
worth a discussion.

Thanks,
--Jacob

[1]: https://www.imperialviolet.org/2015/10/17/boringssl.html
[2]: https://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/

#10Daniel Gustafsson
daniel@yesql.se
In reply to: Jacob Champion (#9)
Re: Support getrandom() for pg_strong_random() source

On 23 Jul 2025, at 19:11, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

.. maybe the pendulum has swung far enough that we can expect any
kernel supporting getentropy() to be able to do the job just as well
as OpenSSL does in userspace, except also faster? I think it might be
worth a discussion.

There has in the past been discussions (at least off-list in hallway tracks)
about allowing randomness to be chosen separately from underlying factors such
as OpenSSL support, at the time it didn't seem worth the trouble but that may
well have changed.

With OpenSSL 1.1.1 being the baseline we can also make use of the _priv_bytes
functions to get increased isolation.

--
Daniel Gustafsson

#11Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Daniel Gustafsson (#10)
Re: Support getrandom() for pg_strong_random() source

On Mon, Jul 28, 2025 at 4:36 AM Daniel Gustafsson <daniel@yesql.se> wrote:

There has in the past been discussions (at least off-list in hallway tracks)
about allowing randomness to be chosen separately from underlying factors such
as OpenSSL support, at the time it didn't seem worth the trouble but that may
well have changed.

Yeah, especially if other options with similar strength could be much
faster. But the comparison is really going to be OS-dependent [1, 2].

With OpenSSL 1.1.1 being the baseline we can also make use of the _priv_bytes
functions to get increased isolation.

Hmm, that's an interesting idea too.

To move this forward a tiny bit: I would be okay with maintaining a
new getentropy() case. (I'm less excited about getrandom() because of
its reduced reach.) And maybe down the line we should discuss choosing
an option at configure time?

--Jacob

[1]: https://lwn.net/Articles/983186/
[2]: https://dotat.at/@/2024-10-01-getentropy.html

#12Daniel Gustafsson
daniel@yesql.se
In reply to: Jacob Champion (#11)
Re: Support getrandom() for pg_strong_random() source

On 28 Jul 2025, at 17:29, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

To move this forward a tiny bit: I would be okay with maintaining a
new getentropy() case. (I'm less excited about getrandom() because of
its reduced reach.) And maybe down the line we should discuss choosing
an option at configure time?

I would not be opposed to starting there.

--
Daniel Gustafsson

#13Michael Paquier
michael@paquier.xyz
In reply to: Daniel Gustafsson (#12)
Re: Support getrandom() for pg_strong_random() source

On Mon, Jul 28, 2025 at 06:14:20PM +0200, Daniel Gustafsson wrote:

On 28 Jul 2025, at 17:29, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

To move this forward a tiny bit: I would be okay with maintaining a
new getentropy() case. (I'm less excited about getrandom() because of
its reduced reach.) And maybe down the line we should discuss choosing
an option at configure time?

I would not be opposed to starting there.

Both of you know the options of these areas of the code more than the
average committer, I think, so if you think that getentropy() could be
a good choice, while making the choice configurable to give the
possibility to be outside of OpenSSL, why not.

My understanding of the problem is that it is a choice of efficiency
vs entropy, and that it's not really possible to have both parts of
the cake. If we make that configurable, documentation sounds like the
key point to me, to explain which one has more benefits over the
other.

Could getentropy() be more efficient at the end on most platforms,
meaning that this could limit the meaning of having a GUC switch?
Having it in POSIX is appealing with the long-term picture in mind..
--
Michael

#14Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Michael Paquier (#13)
Re: Support getrandom() for pg_strong_random() source

On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote:

My understanding of the problem is that it is a choice of efficiency
vs entropy, and that it's not really possible to have both parts of
the cake.

That was my understanding too, but then [1]https://www.imperialviolet.org/2015/10/17/boringssl.html called that into question.
If -- and I don't really have enough expertise to verify that "if" --
the reason OpenSSL is slower isn't because of "entropy", but because
of operations and safety checks that it has to ask the kernel to make
for it, then it stands to reason that the kernel could do that a lot
faster.

If it turns out that's not the case (the post at [1]https://www.imperialviolet.org/2015/10/17/boringssl.html is ten years old;
things change, or Adam could have been wrong, or...), I think that
getentropy() is still a straight upgrade from /dev/urandom, due to its
increased safety guarantees at startup.

If we make that configurable, documentation sounds like the
key point to me, to explain which one has more benefits over the
other.

Agreed.

Could getentropy() be more efficient at the end on most platforms,
meaning that this could limit the meaning of having a GUC switch?

I don't know. [2]https://dotat.at/@/2024-10-01-getentropy.html implies that the performance comparison depends on
several factors, and falls in favor of OpenSSL when the number of
bytes per call is large -- but our use of pg_strong_random() is
generally on small buffers. We would need to do a _lot_ more research
before, say, switching any defaults.

Thanks,
--Jacob

[1]: https://www.imperialviolet.org/2015/10/17/boringssl.html
[2]: https://dotat.at/@/2024-10-01-getentropy.html

In reply to: Jacob Champion (#14)
Re: Support getrandom() for pg_strong_random() source

Jacob Champion <jacob.champion@enterprisedb.com> writes:

On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote:

Could getentropy() be more efficient at the end on most platforms,
meaning that this could limit the meaning of having a GUC switch?

I don't know. [2] implies that the performance comparison depends on
several factors, and falls in favor of OpenSSL when the number of
bytes per call is large

[...]

[2] https://dotat.at/@/2024-10-01-getentropy.html

Note that that test was done on an older Linux kernel without the vDSO
implementation of getentropy(), so on newer kernel (>=6.11) and glibc
(>= 2.41) versions the difference might be smaller or the other way
around.

- ilmari

#16Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#14)
1 attachment(s)
Re: Support getrandom() for pg_strong_random() source

On Tue, Jul 29, 2025 at 8:55 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote:

My understanding of the problem is that it is a choice of efficiency
vs entropy, and that it's not really possible to have both parts of
the cake.

Agreed. I think the optimal choice would depend on the specific use
case. For instance, since UUIDs are not intended for security
purposes, they don't require particularly high entropy. In UUID
generation, the efficiency of random data generation tends to be
prioritized over the quality of randomness.

Could getentropy() be more efficient at the end on most platforms,
meaning that this could limit the meaning of having a GUC switch?

I don't know. [2] implies that the performance comparison depends on
several factors, and falls in favor of OpenSSL when the number of
bytes per call is large -- but our use of pg_strong_random() is
generally on small buffers. We would need to do a _lot_ more research
before, say, switching any defaults.

The performance issue with getentropy, particularly when len=1024,
likely stems from the need for multiple getentropy() calls due to its
256-byte length restriction.

Analysis of RAND_bytes() through strace reveals that it internally
makes calls to getrandom() with a fixed length of 32 bytes. While I'm
uncertain of the exact purpose, it's logical that a single
getentropy() call would be more efficient than RAND_bytes(), which
involves additional overhead beyond just calling getrandom(),
especially when dealing with smaller byte sizes.

I've updated the patch to support getentropy() instead of getrandom().

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-Support-getentropy-as-source-of-pg_strong_random-.patchapplication/octet-stream; name=v2-0001-Support-getentropy-as-source-of-pg_strong_random-.patchDownload
From ff529f2ce5a5fc472ecf70649b7c31a82a7239c8 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 v2] Support getentropy() as 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 | 40 ++++++++++++++++++++++++++++++++++---
 5 files changed, 75 insertions(+), 5 deletions(-)

diff --git a/configure b/configure
index 507a2437c33..f11cd4265bf 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 getentropy
+do :
+  ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
+if test "x$ac_cv_func_getentropy" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETENTROPY 1
+_ACEOF
+
+$as_echo "#define HAVE_GETENTROPY 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
@@ -18479,6 +18498,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_getentropy" = x"yes"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: getentropy" >&5
+$as_echo "getentropy" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
@@ -18505,7 +18527,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, getentropy function, or /dev/urandom as a source of random numbers." "$LINENO" 5
   fi
 fi
 
diff --git a/configure.ac b/configure.ac
index 5f4548adc5c..9cf453fcd23 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([getentropy],
+  [AC_DEFINE(HAVE_GETENTROPY, 1, [Define to 1 if you have getentropy])])])
+
 AC_REPLACE_FUNCS(m4_normalize([
 	explicit_bzero
 	getopt
@@ -2314,6 +2318,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_getentropy" = x"yes"; then
+  AC_MSG_RESULT(getentropy)
 else
   AC_MSG_RESULT([/dev/urandom])
   AC_CHECK_FILE([/dev/urandom], [], [])
@@ -2321,7 +2327,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, getentropy function, or /dev/urandom as a source of random numbers.])
   fi
 fi
 
diff --git a/meson.build b/meson.build
index ca423dc8e12..d34c6ae39f2 100644
--- a/meson.build
+++ b/meson.build
@@ -2705,6 +2705,11 @@ return 0;
    don't.'''.format(func))
 endforeach
 
+if cc.has_header('sys/random.h') and cc.has_function('getentropy',
+    args: test_c_args, prefix: '''
+#include <sys/random.h>''')
+  cdata.set('HAVE_GETENTROPY', 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..eb02137f92d 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -172,6 +172,9 @@
 /* Define to 1 if you have the `getauxval' function. */
 #undef HAVE_GETAUXVAL
 
+/* Define to 1 if you have getentropy */
+#undef HAVE_GETENTROPY
+
 /* Define to 1 if you have the `getifaddrs' function. */
 #undef HAVE_GETIFADDRS
 
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index ea6780dcc9f..c3ea5f7b779 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. getentropy() 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,43 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#elif HAVE_GETENTROPY
+
+#include <sys/random.h>
+
+#define GETENTROPY_MAX_LEN	256
+
+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)
+	{
+		size_t		l = Min(len, GETENTROPY_MAX_LEN);
+
+		res = getentropy(buf, l);
+		if (res < 0)
+			return false;
+
+		p += l;
+		len -= l;
+	}
+
+	return true;
+}
+
+#else							/* not USE_OPENSSL, WIN32, or HAVE_GETENTROPY */
 
 /*
- * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
+ * Without OpenSSL, Win32, or getentropy() support, just read /dev/urandom ourselves.
  */
 
 void
-- 
2.47.3

#17Peter Eisentraut
peter@eisentraut.org
In reply to: Dagfinn Ilmari Mannsåker (#4)
Re: Support getrandom() for pg_strong_random() source

On 22.07.25 13:11, Dagfinn Ilmari Mannsåker wrote:

getrandom() is Linux-specific, while getentropy() is specified by POSIX
(since 2024). It was originally introduced by OpenBSD 5.6 in 2014, and
was added to macOS 10.12 in 2016, glibc 2.25 (same as getrandom()) in
2017, musl 1.1.20 and FreeBSD 12.0 in 2018, and NetBSD 10.0 in 2024

Sources:

https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html
https://dotat.at/@/2024-10-01-getentropy.html

So I think it's more worthwhile to add support for getentropy() than
getrandom().

The POSIX description of getentropy() says:

"The intended use of this function is to create a seed for other
pseudo-random number generators."

So using getentropy() for generating the random numbers that are passed
back to the application code would appear to be the wrong use.

#18Peter Eisentraut
peter@eisentraut.org
In reply to: Masahiko Sawada (#16)
Re: Support getrandom() for pg_strong_random() source

On 30.07.25 08:59, Masahiko Sawada wrote:

I've updated the patch to support getentropy() instead of getrandom().

The point still stands that the number of installations without OpenSSL
support is approximately zero, so what is the purpose of this patch if
approximately no one will be able to use it?

In reply to: Masahiko Sawada (#16)
1 attachment(s)
Re: Support getrandom() for pg_strong_random() source

Masahiko Sawada <sawada.mshk@gmail.com> writes:

On Tue, Jul 29, 2025 at 8:55 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote:

My understanding of the problem is that it is a choice of efficiency
vs entropy, and that it's not really possible to have both parts of
the cake.

Agreed. I think the optimal choice would depend on the specific use
case. For instance, since UUIDs are not intended for security
purposes, they don't require particularly high entropy. In UUID
generation, the efficiency of random data generation tends to be
prioritized over the quality of randomness.

Could getentropy() be more efficient at the end on most platforms,
meaning that this could limit the meaning of having a GUC switch?

I don't know. [2] implies that the performance comparison depends on
several factors, and falls in favor of OpenSSL when the number of
bytes per call is large -- but our use of pg_strong_random() is
generally on small buffers. We would need to do a _lot_ more research
before, say, switching any defaults.

The performance issue with getentropy, particularly when len=1024,
likely stems from the need for multiple getentropy() calls due to its
256-byte length restriction.

Analysis of RAND_bytes() through strace reveals that it internally
makes calls to getrandom() with a fixed length of 32 bytes. While I'm
uncertain of the exact purpose, it's logical that a single
getentropy() call would be more efficient than RAND_bytes(), which
involves additional overhead beyond just calling getrandom(),
especially when dealing with smaller byte sizes.

I've updated the patch to support getentropy() instead of getrandom().

Thanks, just a few comments:

The blog post at
https://dotat.at/@/2024-10-01-getentropy.html#portability-of-getentropy-
points out a couple of caveats:

* Originally getentropy() was declared in <sys/random.h> but POSIX
declares it in <unistd.h>. You need to include both headers to be
sure.

So the probes need to include both <sys/random.h> (if avaliable) and
<unistd.h>, and in the code <sys/random.h> should only be included if
available.

* POSIX specifies a GETENTROPY_MAX macro in <limits.h> for the largest
buffer getentropy() will fill. Most systems don’t yet have this
macro; if it isn’t defined the limit is 256 bytes.

And this means we should include <limits.h> and only define
GETENTROPY_MAX to 256 if it's not already defined.

+bool
+pg_strong_random(void *buf, size_t len)
+{
+	char	   *p = buf;
+	ssize_t		res;
+
+	while (len)
+	{
+		size_t		l = Min(len, GETENTROPY_MAX_LEN);
+
+		res = getentropy(buf, l);

This should be getentropy(p, l), otherwise it will will just fill the
first GETENTROPY_MAX_LEN bytes of buf repeatedly. On my machine I got a
warning about that:

../postgresql/src/port/pg_strong_random.c:159:11: warning: variable 'p' set but not used [-Wunused-but-set-variable]
159 | char *p = buf;
| ^

Do we not have any tests for pg_strong_random that make sure it fills
the entire bufffer for various sizes?

I've attached an updated patch for the above, except I don't know enough
autoconf/m4 to make it include <unistd.h> and optionally <sys/random.h>
in the check there.

- ilmari

Attachments:

v3-0001-Support-getentropy-as-source-of-pg_strong_random-.patchtext/x-diffDownload
From 05a53fe6ab33cfa9d6673ee8b868ce66b349e35b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilmari@ilmari.org>
Date: Wed, 30 Jul 2025 12:36:46 +0100
Subject: [PATCH v3] Support getentropy() as source of pg_strong_random() where
 available

---
 configure                   | 24 ++++++++++++++++++-
 configure.ac                |  8 ++++++-
 meson.build                 |  9 ++++++++
 src/include/pg_config.h.in  |  6 +++++
 src/port/pg_strong_random.c | 46 ++++++++++++++++++++++++++++++++++---
 5 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/configure b/configure
index 507a2437c33..f11cd4265bf 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 getentropy
+do :
+  ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
+if test "x$ac_cv_func_getentropy" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETENTROPY 1
+_ACEOF
+
+$as_echo "#define HAVE_GETENTROPY 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
@@ -18479,6 +18498,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_getentropy" = x"yes"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: getentropy" >&5
+$as_echo "getentropy" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
@@ -18505,7 +18527,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, getentropy function, or /dev/urandom as a source of random numbers." "$LINENO" 5
   fi
 fi
 
diff --git a/configure.ac b/configure.ac
index 5f4548adc5c..9cf453fcd23 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([getentropy],
+  [AC_DEFINE(HAVE_GETENTROPY, 1, [Define to 1 if you have getentropy])])])
+
 AC_REPLACE_FUNCS(m4_normalize([
 	explicit_bzero
 	getopt
@@ -2314,6 +2318,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_getentropy" = x"yes"; then
+  AC_MSG_RESULT(getentropy)
 else
   AC_MSG_RESULT([/dev/urandom])
   AC_CHECK_FILE([/dev/urandom], [], [])
@@ -2321,7 +2327,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, getentropy function, or /dev/urandom as a source of random numbers.])
   fi
 fi
 
diff --git a/meson.build b/meson.build
index ca423dc8e12..b422b623db1 100644
--- a/meson.build
+++ b/meson.build
@@ -2627,6 +2627,7 @@ header_checks = [
   'sys/personality.h',
   'sys/prctl.h',
   'sys/procctl.h',
+  'sys/random.h',
   'sys/signalfd.h',
   'sys/ucred.h',
   'termios.h',
@@ -2705,6 +2706,14 @@ return 0;
    don't.'''.format(func))
 endforeach
 
+if cc.has_function('getentropy',
+    args: test_c_args,
+    prefix: '''
+#include <unistd.h>
+@0@
+'''.format(cdata.get('HAVE_SYS_RANDOM_H') == 1 ? '#include <sys/random.h>' : ''))
+  cdata.set('HAVE_GETENTROPY', 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..147ab293518 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -172,6 +172,9 @@
 /* Define to 1 if you have the `getauxval' function. */
 #undef HAVE_GETAUXVAL
 
+/* Define to 1 if you have getentropy */
+#undef HAVE_GETENTROPY
+
 /* Define to 1 if you have the `getifaddrs' function. */
 #undef HAVE_GETIFADDRS
 
@@ -448,6 +451,9 @@
 /* Define to 1 if you have the <sys/procctl.h> header file. */
 #undef HAVE_SYS_PROCCTL_H
 
+/* Define to 1 if you have the <sys/random.h> header file. */
+#undef HAVE_SYS_RANDOM_H
+
 /* Define to 1 if you have the <sys/signalfd.h> header file. */
 #undef HAVE_SYS_SIGNALFD_H
 
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index ea6780dcc9f..da482e96ae7 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. getentropy() 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,49 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#elif HAVE_GETENTROPY
+
+#include <limits.h>
+
+#ifdef HAVE_SYS_RANDOM_H
+#include <sys/random.h>
+#endif
+
+#ifndef GETENTROPY_MAX
+#define GETENTROPY_MAX	256
+#endif
+
+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)
+	{
+		size_t		l = Min(len, GETENTROPY_MAX);
+
+		res = getentropy(p, l);
+		if (res < 0)
+			return false;
+
+		p += l;
+		len -= l;
+	}
+
+	return true;
+}
+
+#else							/* not USE_OPENSSL, WIN32, or HAVE_GETENTROPY */
 
 /*
- * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
+ * Without OpenSSL, Win32, or getentropy() support, just read /dev/urandom ourselves.
  */
 
 void
-- 
2.50.1

#20Daniel Gustafsson
daniel@yesql.se
In reply to: Peter Eisentraut (#18)
Re: Support getrandom() for pg_strong_random() source

On 30 Jul 2025, at 13:10, Peter Eisentraut <peter@eisentraut.org> wrote:

On 30.07.25 08:59, Masahiko Sawada wrote:

I've updated the patch to support getentropy() instead of getrandom().

The point still stands that the number of installations without OpenSSL support is approximately zero, so what is the purpose of this patch if approximately no one will be able to use it?

The main usecase I've heard discussed (mostly in hallway tracks IIRC) is to
allow multiple PRNG's so that codepaths which favor performance over
cryptographic properties can choose, this would not be that but a small step on
that path (whether or not that's the appropriate step is debatable).

For installations without OpenSSL, getrandom() as an API over /dev/urandom
still works when /dev is chrooted away. That subset might be too small to
spend code on though.

--
Daniel Gustafsson

In reply to: Dagfinn Ilmari Mannsåker (#19)
1 attachment(s)
Re: Support getrandom() for pg_strong_random() source

Dagfinn Ilmari Mannsåker <ilmari@ilmari.org> writes:

Masahiko Sawada <sawada.mshk@gmail.com> writes:

On Tue, Jul 29, 2025 at 8:55 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote:

My understanding of the problem is that it is a choice of efficiency
vs entropy, and that it's not really possible to have both parts of
the cake.

Agreed. I think the optimal choice would depend on the specific use
case. For instance, since UUIDs are not intended for security
purposes, they don't require particularly high entropy. In UUID
generation, the efficiency of random data generation tends to be
prioritized over the quality of randomness.

Could getentropy() be more efficient at the end on most platforms,
meaning that this could limit the meaning of having a GUC switch?

I don't know. [2] implies that the performance comparison depends on
several factors, and falls in favor of OpenSSL when the number of
bytes per call is large -- but our use of pg_strong_random() is
generally on small buffers. We would need to do a _lot_ more research
before, say, switching any defaults.

The performance issue with getentropy, particularly when len=1024,
likely stems from the need for multiple getentropy() calls due to its
256-byte length restriction.

Analysis of RAND_bytes() through strace reveals that it internally
makes calls to getrandom() with a fixed length of 32 bytes. While I'm
uncertain of the exact purpose, it's logical that a single
getentropy() call would be more efficient than RAND_bytes(), which
involves additional overhead beyond just calling getrandom(),
especially when dealing with smaller byte sizes.

I've updated the patch to support getentropy() instead of getrandom().

Thanks, just a few comments:

The blog post at
https://dotat.at/@/2024-10-01-getentropy.html#portability-of-getentropy-
points out a couple of caveats:

* Originally getentropy() was declared in <sys/random.h> but POSIX
declares it in <unistd.h>. You need to include both headers to be
sure.

So the probes need to include both <sys/random.h> (if avaliable) and
<unistd.h>,

I realised I got the conditional for this wrong, since
cdata.get('HAVE_SYS_RANDOM_H') can return either the integer 1 or the
boolean false, so it needs to be format()-ed and compared to a string.

Updated patch attached.

- ilmari

Attachments:

v4-0001-Support-getentropy-as-source-of-pg_strong_random-.patchtext/x-diffDownload
From 88b155c691806bd116b001334cad8ffc1f43e741 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dagfinn=20Ilmari=20Manns=C3=A5ker?= <ilmari@ilmari.org>
Date: Wed, 30 Jul 2025 12:36:46 +0100
Subject: [PATCH v4] Support getentropy() as source of pg_strong_random() where
 available

---
 configure                   | 24 ++++++++++++++++++-
 configure.ac                |  8 ++++++-
 meson.build                 |  9 ++++++++
 src/include/pg_config.h.in  |  6 +++++
 src/port/pg_strong_random.c | 46 ++++++++++++++++++++++++++++++++++---
 5 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/configure b/configure
index 507a2437c33..f11cd4265bf 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 getentropy
+do :
+  ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
+if test "x$ac_cv_func_getentropy" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GETENTROPY 1
+_ACEOF
+
+$as_echo "#define HAVE_GETENTROPY 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
@@ -18479,6 +18498,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_getentropy" = x"yes"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: getentropy" >&5
+$as_echo "getentropy" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
@@ -18505,7 +18527,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, getentropy function, or /dev/urandom as a source of random numbers." "$LINENO" 5
   fi
 fi
 
diff --git a/configure.ac b/configure.ac
index 5f4548adc5c..9cf453fcd23 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([getentropy],
+  [AC_DEFINE(HAVE_GETENTROPY, 1, [Define to 1 if you have getentropy])])])
+
 AC_REPLACE_FUNCS(m4_normalize([
 	explicit_bzero
 	getopt
@@ -2314,6 +2318,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_getentropy" = x"yes"; then
+  AC_MSG_RESULT(getentropy)
 else
   AC_MSG_RESULT([/dev/urandom])
   AC_CHECK_FILE([/dev/urandom], [], [])
@@ -2321,7 +2327,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, getentropy function, or /dev/urandom as a source of random numbers.])
   fi
 fi
 
diff --git a/meson.build b/meson.build
index ca423dc8e12..70f5d6494cb 100644
--- a/meson.build
+++ b/meson.build
@@ -2627,6 +2627,7 @@ header_checks = [
   'sys/personality.h',
   'sys/prctl.h',
   'sys/procctl.h',
+  'sys/random.h',
   'sys/signalfd.h',
   'sys/ucred.h',
   'termios.h',
@@ -2705,6 +2706,14 @@ return 0;
    don't.'''.format(func))
 endforeach
 
+if cc.has_function('getentropy',
+    args: test_c_args,
+    prefix: '''
+#include <unistd.h>
+@0@
+'''.format('@0@'.format(cdata.get('HAVE_SYS_RANDOM_H')) == '1' ? '#include <sys/random.h>' : ''))
+  cdata.set('HAVE_GETENTROPY', 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..147ab293518 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -172,6 +172,9 @@
 /* Define to 1 if you have the `getauxval' function. */
 #undef HAVE_GETAUXVAL
 
+/* Define to 1 if you have getentropy */
+#undef HAVE_GETENTROPY
+
 /* Define to 1 if you have the `getifaddrs' function. */
 #undef HAVE_GETIFADDRS
 
@@ -448,6 +451,9 @@
 /* Define to 1 if you have the <sys/procctl.h> header file. */
 #undef HAVE_SYS_PROCCTL_H
 
+/* Define to 1 if you have the <sys/random.h> header file. */
+#undef HAVE_SYS_RANDOM_H
+
 /* Define to 1 if you have the <sys/signalfd.h> header file. */
 #undef HAVE_SYS_SIGNALFD_H
 
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index ea6780dcc9f..da482e96ae7 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. getentropy() 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,49 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#elif HAVE_GETENTROPY
+
+#include <limits.h>
+
+#ifdef HAVE_SYS_RANDOM_H
+#include <sys/random.h>
+#endif
+
+#ifndef GETENTROPY_MAX
+#define GETENTROPY_MAX	256
+#endif
+
+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)
+	{
+		size_t		l = Min(len, GETENTROPY_MAX);
+
+		res = getentropy(p, l);
+		if (res < 0)
+			return false;
+
+		p += l;
+		len -= l;
+	}
+
+	return true;
+}
+
+#else							/* not USE_OPENSSL, WIN32, or HAVE_GETENTROPY */
 
 /*
- * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
+ * Without OpenSSL, Win32, or getentropy() support, just read /dev/urandom ourselves.
  */
 
 void
-- 
2.50.1

#22Peter Eisentraut
peter@eisentraut.org
In reply to: Daniel Gustafsson (#20)
Re: Support getrandom() for pg_strong_random() source

On 30.07.25 13:55, Daniel Gustafsson wrote:

The point still stands that the number of installations without OpenSSL support is approximately zero, so what is the purpose of this patch if approximately no one will be able to use it?

The main usecase I've heard discussed (mostly in hallway tracks IIRC) is to
allow multiple PRNG's so that codepaths which favor performance over
cryptographic properties can choose, this would not be that but a small step on
that path (whether or not that's the appropriate step is debatable).

This sounds like a reasonable goal. Intuitively, you want stronger
randomness for hashing a password than for generating UUIDs. Then
again, it's not clear how much stronger exactly. RFC 9562 does call for
"cryptographically secure" random numbers. Do we want multiple levels
of "strong" or "secure"? This needs a lot more analysis.

#23Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Peter Eisentraut (#18)
Re: Support getrandom() for pg_strong_random() source

On Wed, Jul 30, 2025 at 4:09 AM Peter Eisentraut <peter@eisentraut.org> wrote:

The POSIX description of getentropy() says:

"The intended use of this function is to create a seed for other
pseudo-random number generators."

So using getentropy() for generating the random numbers that are passed
back to the application code would appear to be the wrong use.

What are the situations in which a stream of numbers would be suitable
for seeding a CSPRNG, but not suitable as output from a CSPRNG?

On Wed, Jul 30, 2025 at 4:10 AM Peter Eisentraut <peter@eisentraut.org> wrote:

The point still stands that the number of installations without OpenSSL
support is approximately zero, so what is the purpose of this patch if
approximately no one will be able to use it?

Upthread I'd suggested that we put some thought into making it
configurable, with the understanding that we'd need to document
exactly what we think the advantages of the approaches are.

--Jacob

#24Peter Eisentraut
peter@eisentraut.org
In reply to: Jacob Champion (#23)
Re: Support getrandom() for pg_strong_random() source

On 30.07.25 18:13, Jacob Champion wrote:

On Wed, Jul 30, 2025 at 4:09 AM Peter Eisentraut<peter@eisentraut.org> wrote:

The POSIX description of getentropy() says:

"The intended use of this function is to create a seed for other
pseudo-random number generators."

So using getentropy() for generating the random numbers that are passed
back to the application code would appear to be the wrong use.

What are the situations in which a stream of numbers would be suitable
for seeding a CSPRNG, but not suitable as output from a CSPRNG?

I imagine a "get entropy" operation could be very slow or even blocking,
whereas a random number generator might just have to do some arithmetic
starting from the previous seed state.

I mean, they called it "get entropy", not "get random", for a reason?

#25Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Peter Eisentraut (#24)
Re: Support getrandom() for pg_strong_random() source

On Wed, Jul 30, 2025 at 12:58 PM Peter Eisentraut <peter@eisentraut.org> wrote:

I imagine a "get entropy" operation could be very slow or even blocking,
whereas a random number generator might just have to do some arithmetic
starting from the previous seed state.

Agreed -- it could absolutely be slower, but if it's not slower in
practice in a user's environment, is there a problem with using it as
the basis for pg_strong_random()? That doesn't seem "wrong" to me; it
just seems like a tradeoff that would take investigation.

(The "blocking" fear is related to the research I linked above -- we
don't really want our CSPRNG to block in the way that /dev/random used
to, because that's not helpful. But we absolutely want it to block if
the CSPRNG state hasn't initialized yet. The goal continues to be
strength over performance IMO -- but there is circumstantial evidence
here that getentropy() could maybe get us both, in some environments.)

--Jacob

#26Michael Paquier
michael@paquier.xyz
In reply to: Jacob Champion (#25)
Re: Support getrandom() for pg_strong_random() source

On Wed, Jul 30, 2025 at 02:03:53PM -0700, Jacob Champion wrote:

On Wed, Jul 30, 2025 at 12:58 PM Peter Eisentraut <peter@eisentraut.org> wrote:

I imagine a "get entropy" operation could be very slow or even blocking,
whereas a random number generator might just have to do some arithmetic
starting from the previous seed state.

Agreed -- it could absolutely be slower, but if it's not slower in
practice in a user's environment, is there a problem with using it as
the basis for pg_strong_random()? That doesn't seem "wrong" to me; it
just seems like a tradeoff that would take investigation.

Yeah, we need to be careful here. Having a blocking or less efficient
operation would be bad for the UUID generation, especially in
INSERT-only workloads and there are a lot of such things these days
that also want to maintain some uniqueness of the data gathered across
multiple nodes. I'm questioning whether the UUID generation could
become a bottleneck if we are not careful, showing high in profiles.
--
Michael

#27Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#25)
Re: Support getrandom() for pg_strong_random() source

On Wed, Jul 30, 2025 at 2:04 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Wed, Jul 30, 2025 at 12:58 PM Peter Eisentraut <peter@eisentraut.org> wrote:

I imagine a "get entropy" operation could be very slow or even blocking,
whereas a random number generator might just have to do some arithmetic
starting from the previous seed state.

Agreed -- it could absolutely be slower, but if it's not slower in
practice in a user's environment, is there a problem with using it as
the basis for pg_strong_random()? That doesn't seem "wrong" to me; it
just seems like a tradeoff that would take investigation.

Regarding glibc's getrandom() and getentropy() implementation[1]https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getentropy.c;h=a62c9fb09962d4918a9c8cdd5545ad803b62fb82;hb=d2097651cc57834dbfcaa102ddfacae0d86cfb66,
getentropy() seems to be implemented as a wrapper of getrandom() in a
sense. That is, getrandom() has more fine grained control such as
specifying blocking behavior and the source (/dev/random or
/dev/urandom). glibc's getentropy() simply calls getrandom() with
flag=0 and 256 byte limitation. I think there is no difference between
random bytes generated by getrandom() and getentropy() in strength.
And according Linux manual for getentropy(),

A call to getentropy() may block if the system has just booted and the
kernel has not yet collected enough randomness to initialize the
entropy pool.

Which is the same behavior of calling getrandom() without GRND_NONBLOCK.

I believe FreeBSD's getentropy() is almost the same; it internally
calls getrandom()[2]https://github.com/freebsd/freebsd-src/blob/main/lib/libc/gen/getentropy.c.

On the other hand, I found a blog post[3]https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2 (10 years-old post) that on
Solaris the output of getentropy() should not be used where randomness
is needed. I'm not sure it's still true but I guess that it might be
reasonable to consider that this is correct behavior in principle, and
that the behavior of glibc etc. is in some sense an exception.

Regards,

[1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getentropy.c;h=a62c9fb09962d4918a9c8cdd5545ad803b62fb82;hb=d2097651cc57834dbfcaa102ddfacae0d86cfb66
[2]: https://github.com/freebsd/freebsd-src/blob/main/lib/libc/gen/getentropy.c
[3]: https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#28Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#27)
Re: Support getrandom() for pg_strong_random() source

On Fri, Aug 8, 2025 at 3:25 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

On the other hand, I found a blog post[3] (10 years-old post) that on
Solaris the output of getentropy() should not be used where randomness
is needed. I'm not sure it's still true but I guess that it might be
reasonable to consider that this is correct behavior in principle, and
that the behavior of glibc etc. is in some sense an exception.

Thanks for finding that! Ah, FIPS:

More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG applied to it.

So FIPS compliance is a case where "a stream of numbers would be
suitable for seeding a CSPRNG, but not suitable as output from a
CSPRNG". That's evidence enough for me to abandon my preference for
getentropy() (whether Solaris still does that or not).

I've been looking at libsodium's randomness implementations [1]https://doc.libsodium.org/generating_random_data:

On Windows systems, the RtlGenRandom() function is used.
On OpenBSD and Bitrig, the arc4random() function is used.
On recent FreeBSD and Linux kernels, the getrandom system call is used.
On other Unices, the /dev/urandom device is used.

(Note that libsodium has some internal concept of a "safe" arc4random
implementation, which it locks to certain platforms. If an OS is still
literally using RC4 we would not want to use it.)

So, my next question: is getrandom() always preferable to /dev/urandom?

--Jacob

[1]: https://doc.libsodium.org/generating_random_data

#29Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Dagfinn Ilmari Mannsåker (#15)
1 attachment(s)
Re: Support getrandom() for pg_strong_random() source

On Tue, Jul 29, 2025 at 9:38 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:

Jacob Champion <jacob.champion@enterprisedb.com> writes:

On Mon, Jul 28, 2025 at 6:30 PM Michael Paquier <michael@paquier.xyz> wrote:

Could getentropy() be more efficient at the end on most platforms,
meaning that this could limit the meaning of having a GUC switch?

I don't know. [2] implies that the performance comparison depends on
several factors, and falls in favor of OpenSSL when the number of
bytes per call is large

[...]

[2] https://dotat.at/@/2024-10-01-getentropy.html

Note that that test was done on an older Linux kernel without the vDSO
implementation of getentropy(), so on newer kernel (>=6.11) and glibc
(>= 2.41) versions the difference might be smaller or the other way
around.

FYI I've benchmarked vDSO implementation of getrandom() with Fedora 42
(kernel 6.15, glibc 2.41). I've modified the test program linked by
the blog post[1]https://dotat.at/@/2024-10-01-getentropy.html so that it measures vDSO implementation of
getrandom() and directly calling getrandom system call. I've attached
the test program. Here is the result:

$ ./bench
init openssl 1929533

len entropy openssl vgetrandom getrandom
16 353 400 39 235
64 373 401 125 368
256 675 420 432 664
1024 2651 494 1352 1792

The 'vgetrandom' column shows nanoseconds per function call of vDSO
implementation of getrandom() function whereas the 'getrandom' column
shows nanoseconds per getrandom system call.

For smaller bytes, vgetrandom (i.e., simply calling the getrandom()
function) is much faster than other methods. For larger bytes (such
1024), openssl had the best performance. This fact is very attractive
to me in terms of using it for UUID generation.

Regards,

[1]: https://dotat.at/@/2024-10-01-getentropy.html

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

bench.capplication/octet-stream; name=bench.cDownload
#30Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#28)
Re: Support getrandom() for pg_strong_random() source

On Fri, Aug 8, 2025 at 3:37 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Fri, Aug 8, 2025 at 3:25 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

On the other hand, I found a blog post[3] (10 years-old post) that on
Solaris the output of getentropy() should not be used where randomness
is needed. I'm not sure it's still true but I guess that it might be
reasonable to consider that this is correct behavior in principle, and
that the behavior of glibc etc. is in some sense an exception.

Thanks for finding that! Ah, FIPS:

More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG applied to it.

So FIPS compliance is a case where "a stream of numbers would be
suitable for seeding a CSPRNG, but not suitable as output from a
CSPRNG". That's evidence enough for me to abandon my preference for
getentropy() (whether Solaris still does that or not).

Makes sense.

I've been looking at libsodium's randomness implementations [1]:

On Windows systems, the RtlGenRandom() function is used.
On OpenBSD and Bitrig, the arc4random() function is used.
On recent FreeBSD and Linux kernels, the getrandom system call is used.
On other Unices, the /dev/urandom device is used.

(Note that libsodium has some internal concept of a "safe" arc4random
implementation, which it locks to certain platforms. If an OS is still
literally using RC4 we would not want to use it.)

So, my next question: is getrandom() always preferable to /dev/urandom?

I believe so. While /dev/urandom source should be kept as a fallback
for older kernels, we should use getrandom() if available. For
example, getrandom() can be used even in the face of file-descriptor
exhaustion and lack of access to the random devices[1]https://lwn.net/Articles/884875/. Also, it would
be much faster than reading /dev/urandom as I shared the benchmark
result[2]/messages/by-id/CAD21AoD1+6FwGb0d4W3YEwOVJi_McuyuvpnjUJE8B8Ejy21MMw@mail.gmail.com.

Regards,

[1]: https://lwn.net/Articles/884875/
[2]: /messages/by-id/CAD21AoD1+6FwGb0d4W3YEwOVJi_McuyuvpnjUJE8B8Ejy21MMw@mail.gmail.com

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#31Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#30)
Re: Support getrandom() for pg_strong_random() source

On Thu, Aug 14, 2025 at 3:16 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

On Fri, Aug 8, 2025 at 3:37 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

So, my next question: is getrandom() always preferable to /dev/urandom?

I believe so. While /dev/urandom source should be kept as a fallback
for older kernels, we should use getrandom() if available. For
example, getrandom() can be used even in the face of file-descriptor
exhaustion and lack of access to the random devices[1]. Also, it would
be much faster than reading /dev/urandom as I shared the benchmark
result[2].

Yeah. My personal reasons to be excited about it are
1) the newer, more sensible one-shot blocking behavior for safety, and
2) the ability for the OS to figure out when a virtualized environment
has potentially "forked"

So I think I would be in favor of adding this as an always-preferred
alternative to /dev/urandom, to begin.

Thinking a bit further ahead: what are some criteria we would need to
research to decide whether getrandom() would be preferable to OpenSSL?
Gathering a couple of considerations from upthread:
- FIPS behavior
- Speed vs. size of a "typical" request
- Version-specific behavior of OpenSSL and/or the OS
- Need for safety in virtualized environments
- ...?

Thanks,
--Jacob

#32Michael Paquier
michael@paquier.xyz
In reply to: Jacob Champion (#31)
Re: Support getrandom() for pg_strong_random() source

On Mon, Aug 18, 2025 at 08:38:25AM -0700, Jacob Champion wrote:

- Need for safety in virtualized environments
- ...?

Interesting. What do you mean by this point? Isolation of the
random computations on a VM/container basis even if these are
originally from the same host?
--
Michael

#33Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Michael Paquier (#32)
Re: Support getrandom() for pg_strong_random() source

On Mon, Aug 18, 2025 at 4:17 PM Michael Paquier <michael@paquier.xyz> wrote:

On Mon, Aug 18, 2025 at 08:38:25AM -0700, Jacob Champion wrote:

- Need for safety in virtualized environments
- ...?

Interesting. What do you mean by this point? Isolation of the
random computations on a VM/container basis even if these are
originally from the same host?

One motivating example is "I paused my VM and cloned it and now both
application instances are giving me the same random numbers." (I
haven't looked into OpenSSL enough to know if it has developed some
magic way around this, for the record.) NetBSD talks about this a bit
at [1]https://man.netbsd.org/acpivmgenid.4.

I'd imagine that there are other nice things about moving it down into
the kernel, like core dumps becoming ever so slightly less dangerous?
But that's pretty out there.

--Jacob

[1]: https://man.netbsd.org/acpivmgenid.4

#34Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#31)
Re: Support getrandom() for pg_strong_random() source

On Mon, Aug 18, 2025 at 8:38 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Thu, Aug 14, 2025 at 3:16 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

On Fri, Aug 8, 2025 at 3:37 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

So, my next question: is getrandom() always preferable to /dev/urandom?

I believe so. While /dev/urandom source should be kept as a fallback
for older kernels, we should use getrandom() if available. For
example, getrandom() can be used even in the face of file-descriptor
exhaustion and lack of access to the random devices[1]. Also, it would
be much faster than reading /dev/urandom as I shared the benchmark
result[2].

Yeah. My personal reasons to be excited about it are
1) the newer, more sensible one-shot blocking behavior for safety, and
2) the ability for the OS to figure out when a virtualized environment
has potentially "forked"

So I think I would be in favor of adding this as an always-preferred
alternative to /dev/urandom, to begin.

Thinking a bit further ahead: what are some criteria we would need to
research to decide whether getrandom() would be preferable to OpenSSL?
Gathering a couple of considerations from upthread:
- FIPS behavior

Do you mean random numbers generated by getrandom() complaints FIPS?
Based on my research, there doesn't appear to be any explicit
statement indicating that Linux's CSPRNG module complies with FIPS
requirements. However, there is a proposal to implement LRNG[1]https://lwn.net/Articles/877607/, which
would be FIPS-compliant. In systems that require FIPS compliance, it
seems that random numbers generated by getrandom() (or getentropy())
are typically used as a seed for FIPS-compliant random number
generators, such as OpenSSL's RAND_bytes() function.

Regards,

[1]: https://lwn.net/Articles/877607/

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#35Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#34)
Re: Support getrandom() for pg_strong_random() source

On Mon, Aug 25, 2025 at 11:30 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

Gathering a couple of considerations from upthread:
- FIPS behavior

Do you mean random numbers generated by getrandom() complaints FIPS?
Based on my research, there doesn't appear to be any explicit
statement indicating that Linux's CSPRNG module complies with FIPS
requirements. However, there is a proposal to implement LRNG[1], which
would be FIPS-compliant.

Right. I guess what I'm asking with that particular bullet point is:

If, tomorrow, I threw caution to the wind and proposed that we use
getrandom() on Linux over OpenSSL by default, would any FIPS users
complain? Or are they all using distributions that have already
applied FIPS patches to the getrandom() part of the kernel anyway?

(But I intended for that to be a possible future point of discussion,
not a blocker for your smaller proposal.)

Thanks,
--Jacob

#36Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#35)
Re: Support getrandom() for pg_strong_random() source

On Mon, Aug 25, 2025 at 1:07 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Mon, Aug 25, 2025 at 11:30 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

Gathering a couple of considerations from upthread:
- FIPS behavior

Do you mean random numbers generated by getrandom() complaints FIPS?
Based on my research, there doesn't appear to be any explicit
statement indicating that Linux's CSPRNG module complies with FIPS
requirements. However, there is a proposal to implement LRNG[1], which
would be FIPS-compliant.

Right. I guess what I'm asking with that particular bullet point is:

If, tomorrow, I threw caution to the wind and proposed that we use
getrandom() on Linux over OpenSSL by default, would any FIPS users
complain? Or are they all using distributions that have already
applied FIPS patches to the getrandom() part of the kernel anyway?

Valid point. I guess the approach of selecting the random number
source at compile time might be inflexible, and there does not seem to
be a one-size-fits-all solution when it comes to things like this. The
fact made me think we could have PostgreSQL select its random number
source when it starts up instead of compile time, giving us the
flexibility to cater to various scenarios. For instance, we could
introduce a GUC parameter that lets users specify their preferred
random number source. Or the server can automatically select it based
on the kernel's FIPS mode (i.e., checking
/proc/sys/crypto/fips_enabled).

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#37Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#36)
Re: Support getrandom() for pg_strong_random() source

On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

For instance, we could
introduce a GUC parameter that lets users specify their preferred
random number source. Or the server can automatically select it based
on the kernel's FIPS mode (i.e., checking
/proc/sys/crypto/fips_enabled).

Interesting idea. (Are there any users reading along who would
definitely use such a feature?)

--Jacob

#38Daniel Gustafsson
daniel@yesql.se
In reply to: Jacob Champion (#37)
Re: Support getrandom() for pg_strong_random() source

On 26 Aug 2025, at 00:38, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

For instance, we could
introduce a GUC parameter that lets users specify their preferred
random number source. Or the server can automatically select it based
on the kernel's FIPS mode (i.e., checking
/proc/sys/crypto/fips_enabled).

Interesting idea. (Are there any users reading along who would
definitely use such a feature?)

I worry about the added complexity this would bring. It's already quite
complicated to configure postgres, and making an informed decision about which
RNG source to choose for cryptographically strong random won't be easy without
domain knowledge.

Taking a step back and re-reading the thread, this started as a proposal to
improve uuid generation on non-Windows platforms when not using OpenSSL. While
non-SSL installations will be incredibly rare in production, it will likely be
a bit more common in PG development situations and speeding up test-runs in
such situations has value. I think this thread has shown merit to the idea of
replacing using /dev/urandom with a more modern API, but after sleeping on it
I'm less convinced that a'la carte CSPRNG configuration has enough upsides to
warrant the risk of users accidentally becoming non-FIPS compliant.

Another related thing to consider, uuid-ossp contrib module use arc4random() in
the non e2fs case.

--
Daniel Gustafsson

#39Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Daniel Gustafsson (#38)
Re: Support getrandom() for pg_strong_random() source

On Tue, Aug 26, 2025 at 12:42 AM Daniel Gustafsson <daniel@yesql.se> wrote:

On 26 Aug 2025, at 00:38, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

For instance, we could
introduce a GUC parameter that lets users specify their preferred
random number source. Or the server can automatically select it based
on the kernel's FIPS mode (i.e., checking
/proc/sys/crypto/fips_enabled).

Interesting idea. (Are there any users reading along who would
definitely use such a feature?)

I worry about the added complexity this would bring. It's already quite
complicated to configure postgres, and making an informed decision about which
RNG source to choose for cryptographically strong random won't be easy without
domain knowledge.

Taking a step back and re-reading the thread, this started as a proposal to
improve uuid generation on non-Windows platforms when not using OpenSSL. While
non-SSL installations will be incredibly rare in production, it will likely be
a bit more common in PG development situations and speeding up test-runs in
such situations has value. I think this thread has shown merit to the idea of
replacing using /dev/urandom with a more modern API, but after sleeping on it
I'm less convinced that a'la carte CSPRNG configuration has enough upsides to
warrant the risk of users accidentally becoming non-FIPS compliant.

The primary motivation is to enhance the performance of random data
generation and UUID creation in scenarios where FIPS compliance is not
mandatory. As I previously reported[1]/messages/by-id/CAD21AoD1+6FwGb0d4W3YEwOVJi_McuyuvpnjUJE8B8Ejy21MMw@mail.gmail.com, getrandom() demonstrates
superior performance for small random data operations, with the
efficiency gain becoming even more significant in newer kernels thanks
to the vDSO implementation of getrandom() (note that I assume
cryptographic equivalence between random data generated by
RAND_bytes() in non-FIPS mode and that produced by getrandom()).

Although this would introduce additional configuration complexity, I
guess that FIPS-compliant random data is unnecessary for most users,
and getrandom()'s output is typically sufficient for many
implementations. I think while maintaining RAND_bytes() as the default
option for OpenSSL-enabled installations, we could somehow provide
users with the flexibility to opt for getrandom() when preferred.

Another related thing to consider, uuid-ossp contrib module use arc4random() in
the non e2fs case.

An alternative approach for users seeking to generate UUIDs via
getrandom() would be to utilize UUIDv7 through uuid_generate_time_v7()
provided by libuuid in e2fs cases. Since this method internally
leverages getrandom(), it should benefit from vDSO execution
capabilities. However, we need to note that UUIDv7 values generated
through uuid_generate_time_v7() exhibit several distinctions from
those produced by PostgreSQL's implementation.

Regards,

[1]: /messages/by-id/CAD21AoD1+6FwGb0d4W3YEwOVJi_McuyuvpnjUJE8B8Ejy21MMw@mail.gmail.com

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#40Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Masahiko Sawada (#39)
2 attachment(s)
Re: Support getrandom() for pg_strong_random() source

On Wed, Aug 27, 2025 at 4:48 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

On Tue, Aug 26, 2025 at 12:42 AM Daniel Gustafsson <daniel@yesql.se> wrote:

On 26 Aug 2025, at 00:38, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

On Mon, Aug 25, 2025 at 3:22 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

For instance, we could
introduce a GUC parameter that lets users specify their preferred
random number source. Or the server can automatically select it based
on the kernel's FIPS mode (i.e., checking
/proc/sys/crypto/fips_enabled).

Interesting idea. (Are there any users reading along who would
definitely use such a feature?)

I worry about the added complexity this would bring. It's already quite
complicated to configure postgres, and making an informed decision about which
RNG source to choose for cryptographically strong random won't be easy without
domain knowledge.

Taking a step back and re-reading the thread, this started as a proposal to
improve uuid generation on non-Windows platforms when not using OpenSSL. While
non-SSL installations will be incredibly rare in production, it will likely be
a bit more common in PG development situations and speeding up test-runs in
such situations has value. I think this thread has shown merit to the idea of
replacing using /dev/urandom with a more modern API, but after sleeping on it
I'm less convinced that a'la carte CSPRNG configuration has enough upsides to
warrant the risk of users accidentally becoming non-FIPS compliant.

The primary motivation is to enhance the performance of random data
generation and UUID creation in scenarios where FIPS compliance is not
mandatory. As I previously reported[1], getrandom() demonstrates
superior performance for small random data operations, with the
efficiency gain becoming even more significant in newer kernels thanks
to the vDSO implementation of getrandom() (note that I assume
cryptographic equivalence between random data generated by
RAND_bytes() in non-FIPS mode and that produced by getrandom()).

Although this would introduce additional configuration complexity, I
guess that FIPS-compliant random data is unnecessary for most users,
and getrandom()'s output is typically sufficient for many
implementations. I think while maintaining RAND_bytes() as the default
option for OpenSSL-enabled installations, we could somehow provide
users with the flexibility to opt for getrandom() when preferred.

I've drafted this idea and attached two patches. The first patch
allows the user to select the random source function used in the
backend. 'openssl' is the default value if PostgreSQL is built with
openssl but users can set it to 'system' use the '/dev/urandom/'
approach (or CryptGenRandom on Windows) instead if they want. In
frontend code, there is nothing changed; the actual implementation of
pg_strong_random is chosed at build time and openssl's RAND_bytes() is
always used if the source code is built with openssl. Therefore, it
doesn't break any existing use cases but provides a way to select the
random source function.The second patch adds support for getrandom()
as the default random source of 'system' random source type on
Unix-like platforms.

With these two patches, for example, users can set random_source_type
to 'system' in the configuration file or a connection string in order
to use getrandom() for random data generation for UUID generation even
on openssl-enabled builds:

% echo "show random_source_type; select uuidv7();" | bin/psql -d
"dbname=postgres port=5432 options='-c random_source_type=openssl'" -X
random_source_type
--------------------
openssl
(1 row)

uuidv7
--------------------------------------
01997599-b6b6-7590-9825-f36253059956
(1 row)

% echo "show random_source_type; select uuidv7();" | bin/psql -d
"dbname=postgres port=5432 options='-c random_source_type=system'" -X
random_source_type
--------------------
system
(1 row)

uuidv7
--------------------------------------
01997599-f069-76b6-9ce2-0308d0cd6a0b
(1 row)

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

0001-PoC-Select-random-source-type.patchapplication/octet-stream; name=0001-PoC-Select-random-source-type.patchDownload
From 2e1f3ef7233f9ecafc0f4bfccdb1195bdebbf256 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Mon, 22 Sep 2025 23:20:06 -0700
Subject: [PATCH 1/2] PoC: Select random source type.

---
 src/backend/utils/misc/Makefile               |  1 +
 src/backend/utils/misc/guc_parameters.dat     |  8 +++
 src/backend/utils/misc/guc_tables.c           |  1 +
 src/backend/utils/misc/meson.build            |  1 +
 src/backend/utils/misc/postgresql.conf.sample |  1 +
 src/backend/utils/misc/random_source.c        | 59 +++++++++++++++++++
 src/bin/initdb/initdb.c                       | 13 ++++
 src/include/port.h                            | 31 +++++++++-
 src/include/utils/guc.h                       |  1 +
 src/include/utils/guc_hooks.h                 |  1 +
 src/include/utils/random_source.h             | 32 ++++++++++
 src/port/pg_strong_random.c                   | 37 ++++++++----
 12 files changed, 174 insertions(+), 12 deletions(-)
 create mode 100644 src/backend/utils/misc/random_source.c
 create mode 100644 src/include/utils/random_source.h

diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile
index b362ae43771..96686c50e5f 100644
--- a/src/backend/utils/misc/Makefile
+++ b/src/backend/utils/misc/Makefile
@@ -27,6 +27,7 @@ OBJS = \
 	pg_rusage.o \
 	ps_status.o \
 	queryenvironment.o \
+	random_source.o \
 	rls.o \
 	sampling.o \
 	stack_depth.o \
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index 6bc6be13d2a..22e9aa7dbab 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -3475,4 +3475,12 @@
   assign_hook => 'assign_io_method',
 },
 
+{ name => 'random_source_type', type => 'enum', context => 'PGC_BACKEND', group => 'RESOURCES_KERNEL',
+  short_desc => 'Selects the random data generation function.',
+  variable => 'random_source_type',
+  boot_val => 'DEFAULT_RANDOM_SOURCE_TYPE',
+  options => 'random_source_type_options',
+  assign_hook => 'assign_random_source_type',
+},
+
 ]
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 00c8376cf4d..0bdc144a155 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -99,6 +99,7 @@
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/ps_status.h"
+#include "utils/random_source.h"
 #include "utils/rls.h"
 #include "utils/xml.h"
 
diff --git a/src/backend/utils/misc/meson.build b/src/backend/utils/misc/meson.build
index 9e389a00d05..6b03998b942 100644
--- a/src/backend/utils/misc/meson.build
+++ b/src/backend/utils/misc/meson.build
@@ -12,6 +12,7 @@ backend_sources += files(
   'pg_rusage.c',
   'ps_status.c',
   'queryenvironment.c',
+  'random_source.c',
   'rls.c',
   'sampling.c',
   'stack_depth.c',
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index c36fcb9ab61..c148b06bd27 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -772,6 +772,7 @@ autovacuum_worker_slots = 16	# autovacuum worker slots to allocate
 #gin_pending_list_limit = 4MB
 #createrole_self_grant = ''		# set and/or inherit
 #event_triggers = on
+#random_source_type = 'system'
 
 # - Locale and Formatting -
 
diff --git a/src/backend/utils/misc/random_source.c b/src/backend/utils/misc/random_source.c
new file mode 100644
index 00000000000..8ae67cf8d85
--- /dev/null
+++ b/src/backend/utils/misc/random_source.c
@@ -0,0 +1,59 @@
+/*-------------------------------------------------------------------------
+ *
+ * random_source.c
+ *
+ * Dynamically setup random generation function based on random_source_type
+ * GUC parameter.
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994-5, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/utils/misc/random_source.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "port.h"
+#include "utils/random_source.h"
+#include "utils/guc.h"
+#include "utils/guc_hooks.h"
+
+const struct config_enum_entry random_source_type_options[] = {
+	{"system", RANDOM_SOURCE_TYPE_SYSTEM, false},
+#ifdef USE_OPENSSL
+	{"openssl", RANDOM_SOURCE_TYPE_OSSL, false},
+#endif
+	{NULL, 0, false}
+};
+
+static const struct
+{
+	pg_strong_random_init_fn initfn;
+	pg_strong_random_fn genfn;
+}			random_source_type_table[] = {
+
+	[RANDOM_SOURCE_TYPE_SYSTEM] = {
+		.initfn = pg_strong_random_init_system,
+		.genfn = pg_strong_random_system,
+	},
+#ifdef USE_OPENSSL
+	[RANDOM_SOURCE_TYPE_OSSL] = {
+		.initfn = pg_strong_random_init_openssl,
+		.genfn = pg_strong_random_openssl,
+	},
+#endif
+};
+
+int			random_source_type = DEFAULT_RANDOM_SOURCE_TYPE;
+
+/* Assign hook for random_source_type */
+void
+assign_random_source_type(int newval, void *extra)
+{
+	pg_strong_random_init_impl = random_source_type_table[newval].initfn;
+	pg_strong_random_impl = random_source_type_table[newval].genfn;
+}
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 92fe2f531f7..bcf7fb0f20c 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1109,6 +1109,16 @@ choose_dsm_implementation(void)
 #endif
 }
 
+static const char *
+choose_random_source_type(void)
+{
+#ifdef USE_OPENSSL
+	return "openssl";
+#else
+	return "system";
+#endif
+}
+
 /*
  * Determine platform-specific config settings
  *
@@ -1356,6 +1366,9 @@ setup_config(void)
 	conflines = replace_guc_value(conflines, "dynamic_shared_memory_type",
 								  dynamic_shared_memory_type, false);
 
+	conflines = replace_guc_value(conflines, "random_source_type",
+								  choose_random_source_type(), false);
+
 	/* Caution: these depend on wal_segment_size_mb, they're not constants */
 	conflines = replace_guc_value(conflines, "min_wal_size",
 								  pretty_wal_size(DEFAULT_MIN_WAL_SEGS), false);
diff --git a/src/include/port.h b/src/include/port.h
index 3964d3b1293..d7464c231a5 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -509,8 +509,35 @@ extern char *pg_inet_net_ntop(int af, const void *src, int bits,
 							  char *dst, size_t size);
 
 /* port/pg_strong_random.c */
-extern void pg_strong_random_init(void);
-extern bool pg_strong_random(void *buf, size_t len);
+extern void pg_strong_random_init_system(void);
+extern bool pg_strong_random_system(void *buf, size_t len);
+#ifdef USE_OPENSSL
+extern void pg_strong_random_init_openssl(void);
+extern bool pg_strong_random_openssl(void *buf, size_t len);
+#endif
+
+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;
+
+/*
+ * Public functions to generate strong random data. The functions invoked
+ * from these function can be replaced by setting function pointers.
+ */
+static pg_attribute_always_inline void
+pg_strong_random_init(void)
+{
+	(*pg_strong_random_init_impl) ();
+}
+
+static pg_attribute_always_inline bool
+pg_strong_random(void *buf, size_t len)
+{
+	return (*pg_strong_random_impl) (buf, len);
+}
 
 /*
  * pg_backend_random used to be a wrapper for pg_strong_random before
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index f21ec37da89..c64e99318fa 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -343,6 +343,7 @@ extern PGDLLIMPORT bool optimize_bounded_sort;
 extern PGDLLIMPORT const struct config_enum_entry archive_mode_options[];
 extern PGDLLIMPORT const struct config_enum_entry dynamic_shared_memory_options[];
 extern PGDLLIMPORT const struct config_enum_entry io_method_options[];
+extern PGDLLIMPORT const struct config_enum_entry random_source_type_options[];
 extern PGDLLIMPORT const struct config_enum_entry recovery_target_action_options[];
 extern PGDLLIMPORT const struct config_enum_entry wal_level_options[];
 extern PGDLLIMPORT const struct config_enum_entry wal_sync_method_options[];
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index 82ac8646a8d..7bc8f6217ce 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -96,6 +96,7 @@ extern bool check_primary_slot_name(char **newval, void **extra,
 									GucSource source);
 extern bool check_random_seed(double *newval, void **extra, GucSource source);
 extern void assign_random_seed(double newval, void *extra);
+extern void assign_random_source_type(int newval, void *extra);
 extern const char *show_random_seed(void);
 extern bool check_recovery_prefetch(int *new_value, void **extra,
 									GucSource source);
diff --git a/src/include/utils/random_source.h b/src/include/utils/random_source.h
new file mode 100644
index 00000000000..b4f8a88db43
--- /dev/null
+++ b/src/include/utils/random_source.h
@@ -0,0 +1,32 @@
+/*-------------------------------------------------------------------------
+ *
+ * random_source.h
+ *
+ * Copyright (c) 2007-2025, PostgreSQL Global Development Group
+ *
+ * src/include/utils/random_source.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef RANDOM_SOURCE_H
+#define RANDOM_SOURCE_H
+
+typedef enum RandomSourceType
+{
+	RANDOM_SOURCE_TYPE_SYSTEM = 0,
+#ifdef USE_OPENSSL
+	RANDOM_SOURCE_TYPE_OSSL,
+#endif
+}			RandomSourceType;
+
+#ifdef USE_OPENSSL
+#define DEFAULT_RANDOM_SOURCE_TYPE RANDOM_SOURCE_TYPE_OSSL
+#else
+#define DEFAULT_RANDOM_SOURCE_TYPE RANDOM_SOURCE_TYPE_SYSTEM
+#endif
+
+/* GUC */
+extern PGDLLIMPORT int random_source_type;
+
+#endif							/* RANDOM_SOURCE_H */
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index ea6780dcc9f..231995e42af 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -25,7 +25,7 @@
 #include <sys/time.h>
 
 /*
- * pg_strong_random & pg_strong_random_init
+ * pg_strong_random & pg_strong_random_init implementations.
  *
  * Generate requested number of random bytes. The returned bytes are
  * cryptographically secure, suitable for use e.g. in authentication.
@@ -48,6 +48,21 @@
  * would lead to predictable keys and security issues.
  */
 
+/*
+ * Set default implementations.
+ *
+ * The pg_strong_random and pg_strong_random_init implementations are fixed to
+ * the implementations follows in FRONTEND builds. On non-FRONTEND builds (i.e.,
+ * backends) the implementations could be replaced by random_source_type GUC
+ * parameter.
+ */
+#ifdef USE_OPENSSL
+pg_strong_random_init_fn pg_strong_random_init_impl = pg_strong_random_init_openssl;
+pg_strong_random_fn pg_strong_random_impl = pg_strong_random_openssl;
+#else
+pg_strong_random_init_fn pg_strong_random_init_impl = pg_strong_random_init_system;
+pg_strong_random_fn pg_strong_random_impl = pg_strong_random_system;
+#endif
 
 
 #ifdef USE_OPENSSL
@@ -55,13 +70,13 @@
 #include <openssl/rand.h>
 
 void
-pg_strong_random_init(void)
+pg_strong_random_init_openssl(void)
 {
 	/* No initialization needed */
 }
 
 bool
-pg_strong_random(void *buf, size_t len)
+pg_strong_random_openssl(void *buf, size_t len)
 {
 	int			i;
 
@@ -92,7 +107,9 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#elif WIN32
+#endif
+
+#if WIN32
 
 #include <wincrypt.h>
 /*
@@ -102,13 +119,13 @@ pg_strong_random(void *buf, size_t len)
 static HCRYPTPROV hProvider = 0;
 
 void
-pg_strong_random_init(void)
+pg_strong_random_init_system(void)
 {
 	/* No initialization needed on WIN32 */
 }
 
 bool
-pg_strong_random(void *buf, size_t len)
+pg_strong_random_system(void *buf, size_t len)
 {
 	if (hProvider == 0)
 	{
@@ -134,20 +151,20 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#else							/* not WIN32 */
 
 /*
- * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
+ * On Unix-like platforms, just read /dev/urandom ourselves.
  */
 
 void
-pg_strong_random_init(void)
+pg_strong_random_init_system(void)
 {
 	/* No initialization needed */
 }
 
 bool
-pg_strong_random(void *buf, size_t len)
+pg_strong_random_system(void *buf, size_t len)
 {
 	int			f;
 	char	   *p = buf;
-- 
2.47.3

0002-PoC-Support-getrandom-as-the-source-of-pg_strong_ran.patchapplication/octet-stream; name=0002-PoC-Support-getrandom-as-the-source-of-pg_strong_ran.patchDownload
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

#41Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#40)
Re: Support getrandom() for pg_strong_random() source

On Tue, Sep 23, 2025 at 1:41 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

With these two patches, for example, users can set random_source_type
to 'system' in the configuration file or a connection string in order
to use getrandom() for random data generation for UUID generation even
on openssl-enabled builds:

I'm wary of letting unprivileged users switch this implementation. I
think our developers should be allowed to treat the user as an
adversary when developing features on top of pg_strong_random(), and
it doesn't make sense for an adversary to control properties of your
CSPRNG. I'm also worried that allowing users to change the FIPS
properties of their systems could lead to compliance headaches for
some DBAs, but maybe somebody knows a reason why that wouldn't be a
concern in practice.

But if only a superuser can change this, I'm not sure that it's going
to fit your use case anymore. Which probably brings the conversation
back to Daniel's note upthread -- is it worth the cost to expose this
as a runtime knob?

--Jacob

#42Michael Paquier
michael@paquier.xyz
In reply to: Jacob Champion (#41)
Re: Support getrandom() for pg_strong_random() source

On Mon, Sep 29, 2025 at 03:15:37PM -0700, Jacob Champion wrote:

I'm wary of letting unprivileged users switch this implementation. I
think our developers should be allowed to treat the user as an
adversary when developing features on top of pg_strong_random(), and
it doesn't make sense for an adversary to control properties of your
CSPRNG. I'm also worried that allowing users to change the FIPS
properties of their systems could lead to compliance headaches for
some DBAs, but maybe somebody knows a reason why that wouldn't be a
concern in practice.

I'm pretty sure that all cloud vendors would face this dilemma, and
another thing that I suspect it that they would restrict entirely the
access to this GUC.

But if only a superuser can change this, I'm not sure that it's going
to fit your use case anymore. Which probably brings the conversation
back to Daniel's note upthread -- is it worth the cost to expose this
as a runtime knob?

I don't think we should expose that as a runtime-updatable parameter.
Even for UUIDs, I am reading the RFC as "more entropy the better" and
I would choose entropy over performance every single day, because it's
a no brainer if you care about cryptography, especially if this option
enforces which source to use for for *all* code paths that want random
bytes. So there is no deal about performance here, at least IMHO.

Even as a superuser parameter, I'm having cold feet with this
prospect. There are two aspects not discussed on this thread that
could justify a PGC_POSTMASTER:
- Testing, by being able to switch from one source to the other,
providing more coverage with external libraries, useful for the
buildfarm.
- Insurance policy against vendor and library bugs. By switching to a
different source with an existing build, it is possible to redirect
the source of a bug somewhere else. It was also one of the reasons
behind the GUCs that control the SSL protocol versions, where we
wanted to bypass some versions. With TLSv3, this is less an issue
these days, compared to SSLv1/2, still the argument applied when the
SSL protocol GUCs were added.
--
Michael

#43Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Michael Paquier (#42)
Re: Support getrandom() for pg_strong_random() source

On Mon, Sep 29, 2025 at 11:01 PM Michael Paquier <michael@paquier.xyz> wrote:

On Mon, Sep 29, 2025 at 03:15:37PM -0700, Jacob Champion wrote:

I'm wary of letting unprivileged users switch this implementation. I
think our developers should be allowed to treat the user as an
adversary when developing features on top of pg_strong_random(), and
it doesn't make sense for an adversary to control properties of your
CSPRNG. I'm also worried that allowing users to change the FIPS
properties of their systems could lead to compliance headaches for
some DBAs, but maybe somebody knows a reason why that wouldn't be a
concern in practice.

I'm pretty sure that all cloud vendors would face this dilemma, and
another thing that I suspect it that they would restrict entirely the
access to this GUC.

But if only a superuser can change this, I'm not sure that it's going
to fit your use case anymore. Which probably brings the conversation
back to Daniel's note upthread -- is it worth the cost to expose this
as a runtime knob?

I don't think we should expose that as a runtime-updatable parameter.

I agree that it should not be exposed as a runtime parameter.

Even for UUIDs, I am reading the RFC as "more entropy the better" and
I would choose entropy over performance every single day, because it's
a no brainer if you care about cryptography, especially if this option
enforces which source to use for for *all* code paths that want random
bytes. So there is no deal about performance here, at least IMHO.

I'm still studying this area but is there any difference in entropy
between random numbers generated by getrandom() and OpenSSL's
RAND_bytes() in terms of entropy? The RFC says "Implementations SHOULD
utilize a cryptographically secure pseudorandom number generator
(CSPRNG) to provide values that are both difficult to predict
("unguessable") and have a low likelihood of collision ("unique")."
and IIUC getrandom() generates random numbers from the kernel's CSPRNG
module.

Even as a superuser parameter, I'm having cold feet with this
prospect. There are two aspects not discussed on this thread that
could justify a PGC_POSTMASTER:
- Testing, by being able to switch from one source to the other,
providing more coverage with external libraries, useful for the
buildfarm.
- Insurance policy against vendor and library bugs. By switching to a
different source with an existing build, it is possible to redirect
the source of a bug somewhere else. It was also one of the reasons
behind the GUCs that control the SSL protocol versions, where we
wanted to bypass some versions. With TLSv3, this is less an issue
these days, compared to SSLv1/2, still the argument applied when the
SSL protocol GUCs were added.

Interesting points. If we can provide a knob as a GUC, I agree that it
should be a PGC_POSTMASTER parameter.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#44Daniel Gustafsson
daniel@yesql.se
In reply to: Jacob Champion (#41)
Re: Support getrandom() for pg_strong_random() source

On 30 Sep 2025, at 00:15, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

I'm wary of letting unprivileged users switch this implementation. I
think our developers should be allowed to treat the user as an
adversary when developing features on top of pg_strong_random(), and
it doesn't make sense for an adversary to control properties of your
CSPRNG.

Agreed.

I'm also worried that allowing users to change the FIPS
properties of their systems could lead to compliance headaches for
some DBAs,

Very much so. It might not move the needle in practice, but the fact that it
could be changed will inevitably lead to a feature request to be able to
disable it.

I think we're trying to fit two square pegs in the same not-square hole here.
While none of the pegs want poor entropy, one (for example UUID generation)
favours speed over CSPRNG properties where the other couldn't care less about
speed if any CSPRNG properties are even looked at the wrong way on a bad day.

What if we instead expand the API to provide pg_random (or pg_fast_random)
which can be a selectable implementation, and pg_strong_random is left as today
a compile time selection? This would allow extension authors and built-in *non
security/auth* features which need to squeeze all the performance they can out
of the API to use an alternative implementation while leaving pg_strong_random
to give CSPRNG guarantees to code that need it.

--
Daniel Gustafsson

#45Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Daniel Gustafsson (#44)
Re: Support getrandom() for pg_strong_random() source

On Tue, Sep 30, 2025 at 12:44 AM Daniel Gustafsson <daniel@yesql.se> wrote:

On 30 Sep 2025, at 00:15, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

I'm wary of letting unprivileged users switch this implementation. I
think our developers should be allowed to treat the user as an
adversary when developing features on top of pg_strong_random(), and
it doesn't make sense for an adversary to control properties of your
CSPRNG.

Agreed.

I'm also worried that allowing users to change the FIPS
properties of their systems could lead to compliance headaches for
some DBAs,

Very much so. It might not move the needle in practice, but the fact that it
could be changed will inevitably lead to a feature request to be able to
disable it.

I think we're trying to fit two square pegs in the same not-square hole here.
While none of the pegs want poor entropy, one (for example UUID generation)
favours speed over CSPRNG properties where the other couldn't care less about
speed if any CSPRNG properties are even looked at the wrong way on a bad day.

What if we instead expand the API to provide pg_random (or pg_fast_random)
which can be a selectable implementation, and pg_strong_random is left as today
a compile time selection? This would allow extension authors and built-in *non
security/auth* features which need to squeeze all the performance they can out
of the API to use an alternative implementation while leaving pg_strong_random
to give CSPRNG guarantees to code that need it.

Sounds reasonable. But I have one question: in systems that must be
FIPS compliant, is it okay to generate UUIDs using random numbers from
non-FIPS compliant sources? If yes, we can use
pg_random/pg_fast_random() for UUID generation in all cases.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#46Michael Paquier
michael@paquier.xyz
In reply to: Masahiko Sawada (#45)
Re: Support getrandom() for pg_strong_random() source

On Thu, Oct 02, 2025 at 04:16:43PM -0700, Masahiko Sawada wrote:

Sounds reasonable. But I have one question: in systems that must be
FIPS compliant, is it okay to generate UUIDs using random numbers from
non-FIPS compliant sources? If yes, we can use
pg_random/pg_fast_random() for UUID generation in all cases.

It seems to me that the answer is no, we should not call stuff that is
not FIPS compliant if we want to be able to say that the backend is
fully FIPS compliant (which comes down to using MD5 and to be able to
report the status and fail gracefully AFAIK, something I've spent
quite some time cleaning up in the backend and the frontend with the
hash computation code). This matters a lot for government class and
some large enterprise customers. Jacob or Daniel, please feel free to
correct me here, perhaps I'm missing a bit related to the random
function bits..
--
Michael

#47Daniel Gustafsson
daniel@yesql.se
In reply to: Masahiko Sawada (#45)
Re: Support getrandom() for pg_strong_random() source

On 3 Oct 2025, at 01:16, Masahiko Sawada <sawada.mshk@gmail.com> wrote:

Adding Joe to the thread since he usually have insights into all things FIPS.

..in systems that must be FIPS compliant, is it okay to generate UUIDs
using random numbers from non-FIPS compliant sources? If yes, we can use
pg_random/pg_fast_random() for UUID generation in all cases.

Well, with the IANAL disclaimer in place I tried to research this. FIPS 140-2
implementation guidance [0]https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/fips140-2/fips1402ig.pdf lists example scenarios where non-approved
algorithms are allowed, and while this usecase would not fit into this the
additional comments section has this:

"1) the algorithm is not used whatsoever to meet any FIPS 140-2
requirements; 2) the algorithm does not access or share CSPs in a way
that counters the requirements of this IG; 3) the algorithm is either:
i) not intended to be used as a security function (e.g.
interoperability or for memory wear leveling); ii) redundant to an
approved algorithm (e.g. double encryption); iii) a cryptographic or
mathematical operation applied for “good measure” but not for providing
sound security (e.g. XORing a CSP with a secret value, using a
proprietary algorithm, or using non-approved algorithms to obfuscate
stored CSPs which are considered plaintext); 4) the algorithm’s
non-approved use and purpose (from 3) above) is unambiguous to the
operator and can’t be easily confused for a security function.

FIPS 140-3 implementation guidance [1]https://csrc.nist.gov/CSRC/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf discuss non-approved algorithms in
processing without security claims and include this wording:

"..if it is clear that the purpose of a service does not include
providing any security functionality recognized in FIPS 140-3 then the
service can use non-approved algorithms in the approved mode if
provisions of this IG are met."

While the IG documents are intended for development of software which will
undergo FIPS certification, which is different from this discussion, they give
interesting clues (and there are no NIST publications which cover what we
discuss here).

With the above in mind I think "maybe" is the best answer here (or "it depends"
which probably fit this equally well). If UUID generation can be considered to
not provide any security functionality then a non-FIPS validated RNG (FIPS
140-2 Annex C [2]https://csrc.nist.rip/publications/fips/fips140-2/fips1402annexc.pdf talks more about RNGs) can likely be used. Any app which use
a UUID in any way which can be considered a security functionality would
however not be able to do that. If anyone is able to find official NIST
documentation which can shed more light on this then that would be great.

I guess this is a long-winded way of saying that if we provide pg_fast_random
then users must be able to shortcuircit it with pg_strong_random() along the
lines of the below pseudocode (like how pgcrypto.builtin_crypto_enabled gives
similar non-FIPS avoidance guarantees to pgcrypto).

bool
pg_fast_random(void *buf, size_t len)
{
if (must_use_strong_random)
return pg_strong_random(buf, len);
...
}

This would need to be properly documented of course. Maybe we should even
start a dedicated subsection on FIPS in the manual to collect information for
anyone wanting to use PostgreSQL in a FIPS compliant environment? (That would
be for another thread though, to keep the goalposts in sight here.)

--
Daniel Gustafsson

[0]: https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/fips140-2/fips1402ig.pdf
[1]: https://csrc.nist.gov/CSRC/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf
[2]: https://csrc.nist.rip/publications/fips/fips140-2/fips1402annexc.pdf

#48Joe Conway
mail@joeconway.com
In reply to: Daniel Gustafsson (#47)
Re: Support getrandom() for pg_strong_random() source

On 10/3/25 04:04, Daniel Gustafsson wrote:

On 3 Oct 2025, at 01:16, Masahiko Sawada <sawada.mshk@gmail.com> wrote:

Adding Joe to the thread since he usually have insights into all things FIPS.

Thanks, I do have opinions at least ;-)

..in systems that must be FIPS compliant, is it okay to generate UUIDs
using random numbers from non-FIPS compliant sources? If yes, we can use
pg_random/pg_fast_random() for UUID generation in all cases.

If UUID generation can be considered to not provide any security
functionality then a non-FIPS validated RNG (FIPS 140-2 Annex C [2] talks
more about RNGs) can likely be used. Any app which use a UUID in any way
which can be considered a security functionality would however not be able
to do that. If anyone is able to find official NIST documentation which can
shed more light on this then that would be great.

The first hit for UUID RFC[1]https://datatracker.ietf.org/doc/html/rfc4122#section-6 that I found said this:
8<------------------
6. Security Considerations

Do not assume that UUIDs are hard to guess; they should not be used
as security capabilities (identifiers whose mere possession grants
access), for example. A predictable random number source will
exacerbate the situation.
8<------------------

That RFC appears to be specific to UUIDv4, but assuming that advice is generally
applicable to UUIDs in general it seems to mean we are off the hook when it
comes to FIPS with respect to UUIDs. Perhaps we should document that though
(assuming we have not already).

This would need to be properly documented of course. Maybe we should even
start a dedicated subsection on FIPS in the manual to collect information for
anyone wanting to use PostgreSQL in a FIPS compliant environment? (That would
be for another thread though, to keep the goalposts in sight here.)

Yeah, or maybe a source code README, or maybe both. Agreed -- another thread for
another day.

[1]: https://datatracker.ietf.org/doc/html/rfc4122#section-6

--
Joe Conway
PostgreSQL Contributors Team
Amazon Web Services: https://aws.amazon.com

#49Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Joe Conway (#48)
Re: Support getrandom() for pg_strong_random() source

On Fri, Oct 3, 2025 at 5:11 AM Joe Conway <mail@joeconway.com> wrote:

That RFC appears to be specific to UUIDv4, but assuming that advice is generally
applicable to UUIDs in general it seems to mean we are off the hook when it
comes to FIPS with respect to UUIDs.

The most recent RFC still says that [1]https://www.rfc-editor.org/rfc/rfc9562.html#name-security-considerations. And it doesn't appear to
mandate the use of a CSPRNG at all, so it'd be unfortunate if UUIDs
were bound by FIPS considerations... but my opinion has no effect on
whether they're bound in practice.

--Jacob

[1]: https://www.rfc-editor.org/rfc/rfc9562.html#name-security-considerations

#50Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Daniel Gustafsson (#44)
Re: Support getrandom() for pg_strong_random() source

On Tue, Sep 30, 2025 at 12:44 AM Daniel Gustafsson <daniel@yesql.se> wrote:

What if we instead expand the API to provide pg_random (or pg_fast_random)
which can be a selectable implementation, and pg_strong_random is left as today
a compile time selection?

I like the idea of tiering it, but I'm not sure how to communicate to
developers when they should prefer pg_strong_random over
pg_fast_random over pg_prng (which is hopefully faster than
pg_fast_random!).

Is the dividing line really strong vs fast, or is it compliance vs
noncompliance? Because I have a feeling that for some users, the
"fast" alternative that is chosen will be stronger than the "strong"
version they are mandated to select.

Are there any use cases other than UUID that want CSPRNG guarantees
without needing CSPRNG security?

--Jacob

#51Michael Paquier
michael@paquier.xyz
In reply to: Jacob Champion (#50)
Re: Support getrandom() for pg_strong_random() source

On Mon, Oct 06, 2025 at 11:41:07AM -0700, Jacob Champion wrote:

On Tue, Sep 30, 2025 at 12:44 AM Daniel Gustafsson <daniel@yesql.se> wrote:

What if we instead expand the API to provide pg_random (or pg_fast_random)
which can be a selectable implementation, and pg_strong_random is left as today
a compile time selection?

I like the idea of tiering it, but I'm not sure how to communicate to
developers when they should prefer pg_strong_random over
pg_fast_random over pg_prng (which is hopefully faster than
pg_fast_random!).

Separating that at API level sounds like a good alternative, yes.

Is the dividing line really strong vs fast, or is it compliance vs
noncompliance? Because I have a feeling that for some users, the
"fast" alternative that is chosen will be stronger than the "strong"
version they are mandated to select.

Yeah.. I'm not sure that it is our job to draw a strict line, either.
We are labelled as database specialists. When it comes to
cryptography, I cannot say for all the others but I'm very confident
in the fact that I'm bad at it.

Are there any use cases other than UUID that want CSPRNG guarantees
without needing CSPRNG security?

One option would be to just document at the top of the API added the
use case that would be in the tree with the new "fast" API (aka the
UUID case) with a slight mention of the RFCs? It seems like in any
case we should be very careful when choosing "fast" call, while the
"strong" one is good option anyway if you just don't know which one
you should choose when adding a new caller that wants random bytes.
--
Michael

#52Daniel Gustafsson
daniel@yesql.se
In reply to: Jacob Champion (#49)
Re: Support getrandom() for pg_strong_random() source

On 6 Oct 2025, at 20:27, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

On Fri, Oct 3, 2025 at 5:11 AM Joe Conway <mail@joeconway.com> wrote:

That RFC appears to be specific to UUIDv4, but assuming that advice is generally
applicable to UUIDs in general it seems to mean we are off the hook when it
comes to FIPS with respect to UUIDs.

The most recent RFC still says that [1]. And it doesn't appear to
mandate the use of a CSPRNG at all, so it'd be unfortunate if UUIDs
were bound by FIPS considerations... but my opinion has no effect on
whether they're bound in practice.

Using a UUID as salt would perhaps be one scenario which would turn the RNG
used for UUIDs into security functionality according to the FIPS definitions?

--
Daniel Gustafsson

#53Daniel Gustafsson
daniel@yesql.se
In reply to: Jacob Champion (#50)
Re: Support getrandom() for pg_strong_random() source

On 6 Oct 2025, at 20:41, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

Are there any use cases other than UUID that want CSPRNG guarantees
without needing CSPRNG security?

None come to mind, and it seems increasingly likely that designing API which we
confidently can document how to use is too complicated. Maybe it's better to
re-focus on just the usecase in the UUID code and leave the API at pg_prng()
and pg_strong_random()? (We already have UUID code in contrib which in some
cases use arc4random after all.)

--
Daniel Gustafsson

In reply to: Jacob Champion (#49)
Re: Support getrandom() for pg_strong_random() source

Jacob Champion <jacob.champion@enterprisedb.com> writes:

On Fri, Oct 3, 2025 at 5:11 AM Joe Conway <mail@joeconway.com> wrote:

That RFC appears to be specific to UUIDv4, but assuming that advice is generally
applicable to UUIDs in general it seems to mean we are off the hook when it
comes to FIPS with respect to UUIDs.

The most recent RFC still says that [1]. And it doesn't appear to
mandate the use of a CSPRNG at all, so it'd be unfortunate if UUIDs
were bound by FIPS considerations... but my opinion has no effect on
whether they're bound in practice.

It doesn't mandate (MUST) a CSPRNG, but it strongly recommends (SHOULD)
it (unless unavailable) in the best practices section
(https://www.rfc-editor.org/rfc/rfc9562.html#name-unguessability):

6.9. Unguessability

Implementations SHOULD utilize a cryptographically secure
pseudorandom number generator (CSPRNG) to provide values that are
both difficult to predict ("unguessable") and have a low likelihood
of collision ("unique"). The exception is when a suitable CSPRNG is
unavailable in the execution environment. Take care to ensure the
CSPRNG state is properly reseeded upon state changes, such as
process forks, to ensure proper CSPRNG operation. CSPRNG ensures the
best of Sections 6.7 and 8 are present in modern UUIDs.

- ilmari

Show quoted text

--Jacob

[1] https://www.rfc-editor.org/rfc/rfc9562.html#name-security-considerations

#55Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Daniel Gustafsson (#52)
Re: Support getrandom() for pg_strong_random() source

On Tue, Oct 7, 2025 at 1:26 AM Daniel Gustafsson <daniel@yesql.se> wrote:

Using a UUID as salt would perhaps be one scenario which would turn the RNG
used for UUIDs into security functionality according to the FIPS definitions?

I don't know. One might idly hope that using a UUID for a salt would
itself be a FIPS violation :D but it's probably not.

I guess there's a bit of a procedural question bundled in with this
(that is getting ever further afield of Sawada-san's proposal). If we
happen to use a CSPRNG to generate some sort of non-security-related
output, and then someone uses that output to seed some crypto, do we
consider ourselves on the hook if we change the implementation? The
UUID RFCs are pretty clear that you're not supposed to treat them as
unguessable even if an ideal implementation is, and I'm starting to
agree with Joe that we need to document that ourselves.

--Jacob

#56Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Michael Paquier (#51)
Re: Support getrandom() for pg_strong_random() source

On Mon, Oct 6, 2025 at 4:11 PM Michael Paquier <michael@paquier.xyz> wrote:

Yeah.. I'm not sure that it is our job to draw a strict line, either.
We are labelled as database specialists. When it comes to
cryptography, I cannot say for all the others but I'm very confident
in the fact that I'm bad at it.

Me too... but I do think we have to draw lines if we're going to
develop features on top of pg_strong_random.

--Jacob

#57Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Dagfinn Ilmari Mannsåker (#54)
Re: Support getrandom() for pg_strong_random() source

On Tue, Oct 7, 2025 at 2:48 AM Dagfinn Ilmari Mannsåker
<ilmari@ilmari.org> wrote:

It doesn't mandate (MUST) a CSPRNG, but it strongly recommends (SHOULD)
it (unless unavailable) in the best practices section
(https://www.rfc-editor.org/rfc/rfc9562.html#name-unguessability):

Right -- and we absolutely should do that. But this is in the context
of FIPS compliance. If you haven't compiled with SSL, uuidv7() is
going to fall back to /dev/urandom anyway, which IIUC is not going to
be FIPS-compliant anyway for most people.

So it's not really clear to me that we should be worrying about FIPS
for UUIDs. The only thing that gives me pause is the fact that
libpq-without-OpenSSL is probably a vanishingly small proportion of
builds, so maybe there could be people treating our use of a CSPRNG as
a de facto guarantee.

--Jacob

#58Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Daniel Gustafsson (#53)
Re: Support getrandom() for pg_strong_random() source

On Tue, Oct 7, 2025 at 1:40 AM Daniel Gustafsson <daniel@yesql.se> wrote:

None come to mind, and it seems increasingly likely that designing API which we
confidently can document how to use is too complicated. Maybe it's better to
re-focus on just the usecase in the UUID code and leave the API at pg_prng()
and pg_strong_random()? (We already have UUID code in contrib which in some
cases use arc4random after all.)

Maybe that would be best. If a second use case does show up in the
future, we'd be better positioned to pull it out into an API (and we'd
know how to document it!).

Sawada-san: I feel like I've driven your thread off the rails (off a
cliff?). Maybe I can try to summarize some of the ideas that seem to
be emerging, without signing you up for them:

- We should let superusers switch UUID generation to a faster CSPRNG,
like getrandom().
- The UUID switch should be done at a layer above pg_strong_random().
Maybe just in the UUID code for now, so that we don't choose a bad
abstraction.
- It seems important for pg_strong_random() to default to a
known-FIPS-complaint solution whenever available.
- Packagers should be able to select a pg_strong_random alternative at
compile time, since kernel-level randomness can potentially bring
security improvements in addition to speed, not everyone cares about
FIPS anyway, and it's conceivable that some distributions might
provide FIPS-compliant kernel randomness.
- It'd be nice for superusers (only) to be able to switch
pg_strong_random at runtime, too, for the reasons Michael mentioned
upthread.
- We should document the RFC's warning about UUIDs not being
considered cryptographic secrets.

There is still a question of whether unprivileged users should be able
to switch the UUID implementation. That seems to hinge, unfortunately,
on whether or not we think someone could be relying on it for security
and/or FIPS.

Does that all seem reasonable, and are there pieces I should peel off
into other threads?

Thanks,
--Jacob

#59Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#58)
Re: Support getrandom() for pg_strong_random() source

On Thu, Oct 9, 2025 at 9:08 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Tue, Oct 7, 2025 at 1:40 AM Daniel Gustafsson <daniel@yesql.se> wrote:

None come to mind, and it seems increasingly likely that designing API which we
confidently can document how to use is too complicated. Maybe it's better to
re-focus on just the usecase in the UUID code and leave the API at pg_prng()
and pg_strong_random()? (We already have UUID code in contrib which in some
cases use arc4random after all.)

Maybe that would be best. If a second use case does show up in the
future, we'd be better positioned to pull it out into an API (and we'd
know how to document it!).

Sawada-san: I feel like I've driven your thread off the rails (off a
cliff?). Maybe I can try to summarize some of the ideas that seem to
be emerging, without signing you up for them:

Thank you for summarizing the ideas.

- We should let superusers switch UUID generation to a faster CSPRNG,
like getrandom().
- The UUID switch should be done at a layer above pg_strong_random().
Maybe just in the UUID code for now, so that we don't choose a bad
abstraction.

Agreed.

- It seems important for pg_strong_random() to default to a
known-FIPS-complaint solution whenever available.
- Packagers should be able to select a pg_strong_random alternative at
compile time, since kernel-level randomness can potentially bring
security improvements in addition to speed, not everyone cares about
FIPS anyway, and it's conceivable that some distributions might
provide FIPS-compliant kernel randomness.

Does it mean that we introduce something like pg_fast_random() and
packagers can select it as the random number generation function
instead of pg_strong_random()? Or can packagers select the function
used in pg_strong_random()?

- It'd be nice for superusers (only) to be able to switch
pg_strong_random at runtime, too, for the reasons Michael mentioned
upthread.

+1 . It seems close to the patch I drafted before.

- We should document the RFC's warning about UUIDs not being
considered cryptographic secrets.

There is still a question of whether unprivileged users should be able
to switch the UUID implementation. That seems to hinge, unfortunately,
on whether or not we think someone could be relying on it for security
and/or FIPS.

Does that all seem reasonable, and are there pieces I should peel off
into other threads?

All of these sound reasonable to me. I think we can handle this as two
separate discussions: one for the UUID implementation changes, and
another for the pg_strong_random() modifications (which would cover
both the runtime switching for superusers and the compile-time
alternatives for packagers).

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#60Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#59)
Re: Support getrandom() for pg_strong_random() source

On Thu, Oct 9, 2025 at 4:53 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

Does it mean that we introduce something like pg_fast_random() and
packagers can select it as the random number generation function
instead of pg_strong_random()? Or can packagers select the function
used in pg_strong_random()?

The latter -- packagers should be able to select the implementation of
pg_strong_random(). I think pg_fast_random() is likely to be a bad
abstraction if we don't have more use cases to guide it.

All of these sound reasonable to me. I think we can handle this as two
separate discussions: one for the UUID implementation changes, and
another for the pg_strong_random() modifications (which would cover
both the runtime switching for superusers and the compile-time
alternatives for packagers).

Sounds good to me. (Which would you like this thread to be?)

--Jacob

#61Daniel Gustafsson
daniel@yesql.se
In reply to: Jacob Champion (#60)
Re: Support getrandom() for pg_strong_random() source

On 10 Oct 2025, at 02:11, Jacob Champion <jacob.champion@enterprisedb.com> wrote:

On Thu, Oct 9, 2025 at 4:53 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

Does it mean that we introduce something like pg_fast_random() and
packagers can select it as the random number generation function
instead of pg_strong_random()? Or can packagers select the function
used in pg_strong_random()?

The latter -- packagers should be able to select the implementation of
pg_strong_random(). I think pg_fast_random() is likely to be a bad
abstraction if we don't have more use cases to guide it.

I am very much agreement with this.

--
Daniel Gustafsson

#62Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#60)
Re: Support getrandom() for pg_strong_random() source

On Thu, Oct 9, 2025 at 5:11 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Thu, Oct 9, 2025 at 4:53 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

Does it mean that we introduce something like pg_fast_random() and
packagers can select it as the random number generation function
instead of pg_strong_random()? Or can packagers select the function
used in pg_strong_random()?

The latter -- packagers should be able to select the implementation of
pg_strong_random(). I think pg_fast_random() is likely to be a bad
abstraction if we don't have more use cases to guide it.

Thank you for the clarification.

All of these sound reasonable to me. I think we can handle this as two
separate discussions: one for the UUID implementation changes, and
another for the pg_strong_random() modifications (which would cover
both the runtime switching for superusers and the compile-time
alternatives for packagers).

Sounds good to me. (Which would you like this thread to be?)

I think the second item fits better with the current thread's subject.
Having said that, these two items are somewhat related (for example,
adding getrandom() support would be a common change for both), so
perhaps we can start with the pg_strong_random() changes in this
thread?

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

#63Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#62)
Re: Support getrandom() for pg_strong_random() source

On Mon, Oct 13, 2025 at 2:49 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

I think the second item fits better with the current thread's subject.
Having said that, these two items are somewhat related (for example,
adding getrandom() support would be a common change for both), so
perhaps we can start with the pg_strong_random() changes in this
thread?

Sounds good.

--Jacob

#64Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#63)
2 attachment(s)
Re: Support getrandom() for pg_strong_random() source

On Wed, Oct 15, 2025 at 9:03 AM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Mon, Oct 13, 2025 at 2:49 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

I think the second item fits better with the current thread's subject.
Having said that, these two items are somewhat related (for example,
adding getrandom() support would be a common change for both), so
perhaps we can start with the pg_strong_random() changes in this
thread?

Sounds good.

I've drafted the patches for this item.

The 0001 patch allows the packager to select the random source:
"openssl" or "system", by using --with-random-source option. If it's
omitted and OpenSSL is used (--with-openssl or --with-ssl=openssl),
'openssl' source is automatically chosen. The selected random source
can be shown in read-only GUC parameter random_source.

The 0002 patch supports getrandom() as a 'system' random source where
available while keeping the method of reading /dev/urandom as a
fallback option.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-Add-configure-time-selection-of-random-number-sou.patchapplication/octet-stream; name=v1-0001-Add-configure-time-selection-of-random-number-sou.patchDownload
From 07b2b5de4f89a041bf534cae2e46e49bd9a9d8bd Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 21 Oct 2025 16:25:23 -0700
Subject: [PATCH v1 1/2] Add configure-time selection of random number source.

Previously, the random number source was automatically selected: OpenSSL
was the first choice, with native platform sources (Windows API or
/dev/urandom) used as fallback options.

This commit adds the ability to specify the random number source at
configure time using either the --with-random-source option for the
configure script or the -Drandom_source option for meson.

The selected random source can be viewed through the read-only GUC
parameter random_source.

XXX doc updates.

Reviewed-by:
Discussion: https://postgr.es/m/
---
 configure                                 | 78 +++++++++++++++++++----
 configure.ac                              | 50 +++++++++++----
 meson.build                               | 22 +++++++
 meson_options.txt                         |  4 ++
 src/backend/utils/misc/guc_parameters.dat |  8 ++-
 src/backend/utils/misc/guc_tables.c       |  7 ++
 src/include/pg_config.h.in                |  6 ++
 7 files changed, 149 insertions(+), 26 deletions(-)

diff --git a/configure b/configure
index 22cd866147b..809691fd61c 100755
--- a/configure
+++ b/configure
@@ -886,6 +886,7 @@ with_zstd
 with_ssl
 with_openssl
 enable_largefile
+with_random_source
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1605,6 +1606,8 @@ Optional Packages:
   --with-zstd             build with ZSTD support
   --with-ssl=LIB          use LIB for SSL/TLS support (openssl)
   --with-openssl          obsolete spelling of --with-ssl=openssl
+  --with-random-source=NAME
+                          set random number source (system,openssl)
 
 Some influential environment variables:
   PG_TEST_EXTRA
@@ -18277,24 +18280,69 @@ $as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select random number source.
+#
+
+
+
+
+# Check whether --with-random-source was given.
+if test "${with_random_source+set}" = set; then :
+  withval=$with_random_source;
+  case $withval in
+    yes)
+      as_fn_error $? "argument required for --with-random-source option" "$LINENO" 5
+      ;;
+    no)
+      as_fn_error $? "argument required for --with-random-source option" "$LINENO" 5
+      ;;
+    *)
+      random_source=$withval
+      ;;
+  esac
+
+fi
+
+
+
+# If nothing is specified to --with-random-source, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$random_source" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    random_source=openssl
+  else
+    random_source=system
+  fi
+elif test x"$random_source" != x"openssl" -a x"$random_source" != x"system" ; then
+  as_fn_error $? "--with-random-source must sepcify one of system or openssl" "$LINENO" 5
+fi
+
+if test "$random_source" = openssl -a x"$with_ssl" != x"openssl" ; then
+  as_fn_error $? "OpenSSL library is required for random number generation" "$LINENO" 5
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking which random number source to use" >&5
 $as_echo_n "checking which random number source to use... " >&6; }
-if test x"$with_ssl" = x"openssl" ; then
+if test "$random_source" = openssl ; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5
 $as_echo "OpenSSL" >&6; }
-elif test x"$PORTNAME" = x"win32" ; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5
+
+$as_echo "#define USE_RANDOM_SOURCE_OPENSSL  1" >>confdefs.h
+
+else
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  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"$cross_compiling" = x"yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5
+  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; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
 $as_echo_n "checking for /dev/urandom... " >&6; }
 if ${ac_cv_file__dev_urandom+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -18314,11 +18362,15 @@ if test "x$ac_cv_file__dev_urandom" = xyes; then :
 fi
 
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    as_fn_error $? "
+    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
+    fi
   fi
+
+$as_echo "#define USE_RANDOM_SOURCE_SYSTEM  1" >>confdefs.h
+
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/configure.ac b/configure.ac
index e44943aa6fe..2690b71527b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2296,25 +2296,51 @@ else
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select random number source.
+#
+
+PGAC_ARG_REQ(with, random-source, [NAME], [set random number source (system,openssl)],
+             [random_source=$withval])
+
+# If nothing is specified to --with-random-source, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$random_source" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    random_source=openssl
+  else
+    random_source=system
+  fi
+elif test x"$random_source" != x"openssl" -a x"$random_source" != x"system" ; then
+  AC_MSG_ERROR([--with-random-source must sepcify one of system or openssl])
+fi
+
+if test "$random_source" = openssl -a x"$with_ssl" != x"openssl" ; then
+  AC_MSG_ERROR([OpenSSL library is required for random number generation])
+fi
+
 AC_MSG_CHECKING([which random number source to use])
-if test x"$with_ssl" = x"openssl" ; then
+if test "$random_source" = openssl ; then
   AC_MSG_RESULT([OpenSSL])
-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])
+  AC_DEFINE([USE_RANDOM_SOURCE_OPENSSL] , 1, [Define to 1 to use OpenSSL libary for random number generation])
 else
-  AC_MSG_RESULT([/dev/urandom])
-  AC_CHECK_FILE([/dev/urandom], [], [])
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  if 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])
+  else
+    AC_MSG_RESULT([/dev/urandom])
+    AC_CHECK_FILE([/dev/urandom], [], [])
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    AC_MSG_ERROR([
+    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.])
+    fi
   fi
+  AC_DEFINE([USE_RANDOM_SOURCE_SYSTEM] , 1, [Define to 1 to use system native source for random number generation])
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/meson.build b/meson.build
index 395416a6060..fce1e1436e7 100644
--- a/meson.build
+++ b/meson.build
@@ -2547,7 +2547,29 @@ if not have_optimized_crc
   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
 endif
 
+###############################################################
+# Select random number source.
+###############################################################
+rand_src_opt = get_option('random_source')
+if rand_src_opt == 'auto'
+  if ssl.found()
+    rand_src_opt = 'openssl'
+  else
+    rand_src_opt = 'system'
+  endif
+endif
+
+if rand_src_opt == 'openssl' and not ssl.found()
+  error('OpenSSL library must be enabled for random number generation')
+endif
 
+if rand_src_opt == 'system'
+  cdata.set('USE_RANDOM_SOURCE_SYSTEM', 1,
+            description: 'Define to 1 to use system native source for random number generation')
+else
+  cdata.set('USE_RANDOM_SOURCE_OPENSSL', 1,
+            description: 'Define to 1 to use OpenSSL libary for random number generation')
+endif
 
 ###############################################################
 # Other CPU specific stuff
diff --git a/meson_options.txt b/meson_options.txt
index 06bf5627d3c..55f0f202c60 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -142,6 +142,10 @@ option('pltcl', type: 'feature', value: 'auto',
 option('tcl_version', type: 'string', value: 'tcl',
   description: 'Tcl version')
 
+option('random_source', type: 'combo', choices: ['auto', 'system', 'openssl'],
+  value: 'auto',
+  description: 'Select random number source')
+
 option('readline', type: 'feature', value: 'auto',
   description: 'Use GNU Readline or BSD Libedit for editing')
 
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index d6fc8333850..e3059c36b7d 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -3195,6 +3195,13 @@
   assign_hook => 'assign_log_connections',
 },
 
+{ name => 'random_source', type => 'string', context => 'PGC_INTERNAL', group => 'PRESET_OPTIONS',
+  short_desc => 'Shows implementation used for generating strong random number.',
+  flags => 'GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE',
+  variable => 'random_source',
+  boot_val => 'DEFAULT_RANDOM_SOURCE',
+},
+
 { name => 'backslash_quote', type => 'enum', context => 'PGC_USERSET', group => 'COMPAT_OPTIONS_PREVIOUS',
   short_desc => 'Sets whether "\\\\\'" is allowed in string literals.',
   variable => 'backslash_quote',
@@ -3500,5 +3507,4 @@
   options => 'io_method_options',
   assign_hook => 'assign_io_method',
 },
-
 ]
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 00c8376cf4d..52630ada573 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -620,6 +620,13 @@ static int	num_os_semaphores;
 static bool data_checksums;
 static bool integer_datetimes;
 
+#ifdef USE_RANDOM_SOURCE_OPENSSL
+#define DEFAULT_RANDOM_SOURCE "openssl"
+#else
+#define DEFAULT_RANDOM_SOURCE "system"
+#endif
+static char *random_source = DEFAULT_RANDOM_SOURCE;
+
 #ifdef USE_ASSERT_CHECKING
 #define DEFAULT_ASSERT_ENABLED true
 #else
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index c4dc5d72bdb..35543a3e3c6 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -727,6 +727,12 @@
 /* Define to 1 to build with PAM support. (--with-pam) */
 #undef USE_PAM
 
+/* Define to 1 to use system's native source for random number generation  */
+#undef USE_RANDOM_SOURCE_SYSTEM
+
+/* Define to 1 to use OpenSSL libary for random number generation */
+#undef USE_RANDOM_SOURCE_OPENSSL
+
 /* Define to 1 to use software CRC-32C implementation (slicing-by-8). */
 #undef USE_SLICING_BY_8_CRC32C
 
-- 
2.47.3

v1-0002-Support-getrandom-as-random-source-where-availabl.patchapplication/octet-stream; name=v1-0002-Support-getrandom-as-random-source-where-availabl.patchDownload
From 8de85697dd0c8d334168749d2e104a97a455d395 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
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 <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
@@ -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 <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 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 <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..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 <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(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

#65Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Masahiko Sawada (#64)
Re: Support getrandom() for pg_strong_random() source

On Thu, Oct 23, 2025 at 2:48 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

I've drafted the patches for this item.

Thanks!

The 0001 patch allows the packager to select the random source:
"openssl" or "system", by using --with-random-source option. If it's
omitted and OpenSSL is used (--with-openssl or --with-ssl=openssl),
'openssl' source is automatically chosen. The selected random source
can be shown in read-only GUC parameter random_source.

I think 0001 is missing logic to switch pg_strong_random.c according
to the new #defines; selecting `system` still uses OpenSSL on my
machine.

+  --with-random-source=NAME
+                          set random number source (system,openssl)

Bikeshedding: should we make it clear in the name that this covers
only the "strong" random implementation, for cryptography? Maybe
--with-strong-random, or --with-crypt-random, or...

+ AC_DEFINE([USE_RANDOM_SOURCE_OPENSSL] , 1, [Define to 1 to use OpenSSL libary for random number generation])

autoreconf 2.69 is refusing to process these AC_DEFINEs on my machine,
and I think it's because of the space between the end bracket ']' and
the comma. Removing it fixes generation for me.

@@ -3500,5 +3507,4 @@
options => 'io_method_options',
assign_hook => 'assign_io_method',
},
-
]

(FWIW, I prefer the extra newline there; it's easier for me to read
and it matches the spacing at the top.)

The 0002 patch supports getrandom() as a 'system' random source where
available while keeping the method of reading /dev/urandom as a
fallback option.

+AC_CHECK_HEADER([sys/random.h],
+ [AC_CHECK_FUNCS([getrandom],
+  [AC_DEFINE(HAVE_GETRANDOM, 1, [Define to 1 if you have getrandom])])])

AC_CHECK_FUNCS([getrandom]) by itself should let autoconf take care of
the description; I think the extra AC_DEFINE there will duplicate some
handling.

+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

Some of the more complicated prefixes use multiline literals, but for
this case I think `prefix: '#include <sys/random.h'` would be more
readable. Also, is there a way to merge this check into the
check_funcs logic later on?

Thanks,
--Jacob

#66Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Jacob Champion (#65)
2 attachment(s)
Re: Support getrandom() for pg_strong_random() source

On Fri, Oct 31, 2025 at 1:31 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Thu, Oct 23, 2025 at 2:48 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

I've drafted the patches for this item.

Thanks!

The 0001 patch allows the packager to select the random source:
"openssl" or "system", by using --with-random-source option. If it's
omitted and OpenSSL is used (--with-openssl or --with-ssl=openssl),
'openssl' source is automatically chosen. The selected random source
can be shown in read-only GUC parameter random_source.

Thank you for the comments.

I think 0001 is missing logic to switch pg_strong_random.c according
to the new #defines; selecting `system` still uses OpenSSL on my
machine.

Fixed.

+  --with-random-source=NAME
+                          set random number source (system,openssl)

Bikeshedding: should we make it clear in the name that this covers
only the "strong" random implementation, for cryptography? Maybe
--with-strong-random, or --with-crypt-random, or...

Agreed, I renamed it to --with-strong-random and applied it to other
related names too .

+ AC_DEFINE([USE_RANDOM_SOURCE_OPENSSL] , 1, [Define to 1 to use OpenSSL libary for random number generation])

autoreconf 2.69 is refusing to process these AC_DEFINEs on my machine,
and I think it's because of the space between the end bracket ']' and
the comma. Removing it fixes generation for me.

Fixed.

@@ -3500,5 +3507,4 @@
options => 'io_method_options',
assign_hook => 'assign_io_method',
},
-
]

(FWIW, I prefer the extra newline there; it's easier for me to read
and it matches the spacing at the top.)

Fixed.

The 0002 patch supports getrandom() as a 'system' random source where
available while keeping the method of reading /dev/urandom as a
fallback option.

+AC_CHECK_HEADER([sys/random.h],
+ [AC_CHECK_FUNCS([getrandom],
+  [AC_DEFINE(HAVE_GETRANDOM, 1, [Define to 1 if you have getrandom])])])

AC_CHECK_FUNCS([getrandom]) by itself should let autoconf take care of
the description; I think the extra AC_DEFINE there will duplicate some
handling.

+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

Some of the more complicated prefixes use multiline literals, but for
this case I think `prefix: '#include <sys/random.h'` would be more
readable. Also, is there a way to merge this check into the
check_funcs logic later on?

Agreed with the above comments. I think we don't need a header check
for sys/random.h actually. Checking the getrandom() function present
seems to be sufficient in this case.

I've attached the updated patches.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-Add-configure-time-selection-of-strong-random-num.patchapplication/octet-stream; name=v2-0001-Add-configure-time-selection-of-strong-random-num.patchDownload
From acdc90072ac0c78fe598522bd079f4456fb1ce3f Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 21 Oct 2025 16:25:23 -0700
Subject: [PATCH v2 1/2] Add configure-time selection of strong random number
 source.

Previously, the random number source was automatically selected: OpenSSL
was the first choice, with native platform sources (Windows API or
/dev/urandom) used as fallback options.

This commit adds the ability to specify the random number source at
configure time using either the --with-strong-random option for the
configure script or the -Dstrong_random option for meson.

The selected random source can be viewed through the read-only GUC
parameter strong_random_source.

Reviewed-by:
Discussion: https://postgr.es/m/
---
 configure                                 | 82 ++++++++++++++++++-----
 configure.ac                              | 50 ++++++++++----
 doc/src/sgml/config.sgml                  | 19 ++++++
 doc/src/sgml/installation.sgml            | 40 +++++++++++
 meson.build                               | 22 ++++++
 meson_options.txt                         |  4 ++
 src/backend/utils/misc/guc_parameters.dat |  7 ++
 src/backend/utils/misc/guc_tables.c       |  7 ++
 src/include/pg_config.h.in                |  6 ++
 src/port/pg_strong_random.c               |  6 +-
 10 files changed, 213 insertions(+), 30 deletions(-)

diff --git a/configure b/configure
index f7c24c8f576..c591f8d8fbd 100755
--- a/configure
+++ b/configure
@@ -886,6 +886,7 @@ with_zstd
 with_ssl
 with_openssl
 enable_largefile
+with_strong_random
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1605,6 +1606,8 @@ Optional Packages:
   --with-zstd             build with ZSTD support
   --with-ssl=LIB          use LIB for SSL/TLS support (openssl)
   --with-openssl          obsolete spelling of --with-ssl=openssl
+  --with-strong-random=NAME
+                          set strong random number source (system,openssl)
 
 Some influential environment variables:
   PG_TEST_EXTRA
@@ -15000,8 +15003,8 @@ fi
 
 
 # Even though restrict is in C99 and should be supported by all
-# supported compilers, but this macro is useful because it will prefer
-# a spelling that also works in C++ (often __restrict).  (restrict is
+# supported compilers, this test is useful because it will prefer a
+# spelling that also works in C++ (often __restrict).  (restrict is
 # not part of the C++ standard.)
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
 $as_echo_n "checking for C/C++ restrict keyword... " >&6; }
@@ -18267,24 +18270,69 @@ $as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select strong random number source.
+#
+
+
+
+
+# Check whether --with-strong-random was given.
+if test "${with_strong_random+set}" = set; then :
+  withval=$with_strong_random;
+  case $withval in
+    yes)
+      as_fn_error $? "argument required for --with-strong-random option" "$LINENO" 5
+      ;;
+    no)
+      as_fn_error $? "argument required for --with-strong-random option" "$LINENO" 5
+      ;;
+    *)
+      strong_random=$withval
+      ;;
+  esac
+
+fi
+
+
+
+# If nothing is specified to --with-strong-random, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$strong_random" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    strong_random=openssl
+  else
+    strong_random=system
+  fi
+elif test x"$strong_random" != x"openssl" -a x"$strong_random" != x"system" ; then
+  as_fn_error $? "--with-strong-random must sepcify one of system or openssl" "$LINENO" 5
+fi
+
+if test "$strong_random" = openssl -a x"$with_ssl" != x"openssl" ; then
+  as_fn_error $? "OpenSSL library is required for random number generation" "$LINENO" 5
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking which random number source to use" >&5
 $as_echo_n "checking which random number source to use... " >&6; }
-if test x"$with_ssl" = x"openssl" ; then
+if test "$strong_random" = openssl ; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5
 $as_echo "OpenSSL" >&6; }
-elif test x"$PORTNAME" = x"win32" ; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5
+
+$as_echo "#define STRONG_RANDOM_SOURCE_OPENSSL 1" >>confdefs.h
+
+else
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  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"$cross_compiling" = x"yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5
+  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; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
 $as_echo_n "checking for /dev/urandom... " >&6; }
 if ${ac_cv_file__dev_urandom+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -18304,11 +18352,15 @@ if test "x$ac_cv_file__dev_urandom" = xyes; then :
 fi
 
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    as_fn_error $? "
+    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
+    fi
   fi
+
+$as_echo "#define STRONG_RANDOM_SOURCE_SYSTEM 1" >>confdefs.h
+
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/configure.ac b/configure.ac
index 6c802deaacb..bfdb764f059 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2289,25 +2289,51 @@ else
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select strong random number source.
+#
+
+PGAC_ARG_REQ(with, strong-random, [NAME], [set strong random number source (system,openssl)],
+             [strong_random=$withval])
+
+# If nothing is specified to --with-strong-random, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$strong_random" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    strong_random=openssl
+  else
+    strong_random=system
+  fi
+elif test x"$strong_random" != x"openssl" -a x"$strong_random" != x"system" ; then
+  AC_MSG_ERROR([--with-strong-random must sepcify one of system or openssl])
+fi
+
+if test "$strong_random" = openssl -a x"$with_ssl" != x"openssl" ; then
+  AC_MSG_ERROR([OpenSSL library is required for random number generation])
+fi
+
 AC_MSG_CHECKING([which random number source to use])
-if test x"$with_ssl" = x"openssl" ; then
+if test "$strong_random" = openssl ; then
   AC_MSG_RESULT([OpenSSL])
-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])
+  AC_DEFINE([STRONG_RANDOM_SOURCE_OPENSSL], 1, [Define to 1 to use OpenSSL libary for strong random number generation])
 else
-  AC_MSG_RESULT([/dev/urandom])
-  AC_CHECK_FILE([/dev/urandom], [], [])
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  if 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])
+  else
+    AC_MSG_RESULT([/dev/urandom])
+    AC_CHECK_FILE([/dev/urandom], [], [])
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    AC_MSG_ERROR([
+    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.])
+    fi
   fi
+  AC_DEFINE([STRONG_RANDOM_SOURCE_SYSTEM], 1, [Define to 1 to use system native source for strong random number generation])
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 06d1e4403b5..d839f78e2db 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -12047,6 +12047,25 @@ dynamic_library_path = '/usr/local/lib/postgresql:$libdir'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-strong-random-source" xreflabel="strong_random_source">
+      <term><varname>strong_random_source</varname> (<type>string</type>)
+      <indexterm>
+       <primary><varname>strong_random_source</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Reports the name of implementation used to generate cryptographically secure
+        random data: <literal>system</literal> or <literal>openssl</literal>. It
+        is determined when building the server. See more information see
+        <link linkend="configure-option-with-strong-random"><option>--with-strong-random
+        </option></link> for installation with Autoconf or
+        <link linkend="configure-strong-random-meson"><option>-Dstrong_random</option>
+        </link> for installation with Meson.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-wal-block-size" xreflabel="wal_block_size">
       <term><varname>wal_block_size</varname> (<type>integer</type>)
       <indexterm>
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 593202f4fb2..3ff2f3fb5a1 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1531,6 +1531,26 @@ build-postgresql:
        </listitem>
       </varlistentry>
 
+      <varlistentry id="configure-option-with-strong-random">
+       <term><option>--with-strong-random=<replaceable>NAME</replaceable></option></term>
+       <listitem>
+        <para>
+         Specifies the imlementation used to generate cryptographically secure random
+         data. Valid values are <literal>system</literal> and <literal>openssl</literal>.
+        </para>
+        <para>
+         <productname>PostgreSQL</productname> relies on strong random numbers in
+         security-sensitive operations. For example, random values are used when generating
+         salts for <literal>SCRAM-SHA-256</literal> password storage and when creating
+         UUIDs. By default, the implementation is chosen based on the
+         <option>--with-ssl</option> option: if <productname>PostgreSQL</productname>
+         is built with <productname>OpenSSL</productname> support,
+         <productname>OpenSSL</productname>'s random generator is used; otherwise, the
+         operating system native secure random facility is used. This option overrides
+         that behavior and forces use of the specified source.
+        </para>
+       </listitem>
+      </varlistentry>
      </variablelist>
 
    </sect3>
@@ -3054,6 +3074,26 @@ ninja install
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry id="configure-strong-random-meson">
+      <term><option>-Dstrong_random={ auto | system | openssl }</option></term>
+       <listitem>
+        <para>
+         Specifies the imlementation used to generate cryptographically secure random
+         data.
+        </para>
+        <para>
+         <productname>PostgreSQL</productname> relies on strong random numbers in
+         security-sensitive operations. For example, random values are used when generating
+         salts for <literal>SCRAM-SHA-256</literal> password storage and when creating
+         UUIDs. Default to auto and the implementation will be chosen based on the
+         <option>-Dssl</option> option: if <productname>PostgreSQL</productname>
+         is built with <productname>OpenSSL</productname> support,
+         <productname>OpenSSL</productname>'s random generator is used; otherwise, the
+         operating system native secure random facility is used.
+        </para>
+       </listitem>
+     </varlistentry>
     </variablelist>
    </sect3>
 
diff --git a/meson.build b/meson.build
index 0f61ff6a700..90918fc12da 100644
--- a/meson.build
+++ b/meson.build
@@ -2547,7 +2547,29 @@ if not have_optimized_crc
   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
 endif
 
+###############################################################
+# Select strong random number source.
+###############################################################
+rand_src_opt = get_option('strong_random')
+if rand_src_opt == 'auto'
+  if ssl.found()
+    rand_src_opt = 'openssl'
+  else
+    rand_src_opt = 'system'
+  endif
+endif
+
+if rand_src_opt == 'openssl' and not ssl.found()
+  error('OpenSSL library must be enabled for strong random number generation')
+endif
 
+if rand_src_opt == 'system'
+  cdata.set('STRONG_RANDOM_SOURCE_SYSTEM', 1,
+            description: 'Define to 1 to use system native source for strong random number generation')
+else
+  cdata.set('STRONG_RANDOM_SOURCE_OPENSSL', 1,
+            description: 'Define to 1 to use OpenSSL libary for strong random number generation')
+endif
 
 ###############################################################
 # Other CPU specific stuff
diff --git a/meson_options.txt b/meson_options.txt
index 06bf5627d3c..46850404c18 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -142,6 +142,10 @@ option('pltcl', type: 'feature', value: 'auto',
 option('tcl_version', type: 'string', value: 'tcl',
   description: 'Tcl version')
 
+option('strong_random', type: 'combo', choices: ['auto', 'system', 'openssl'],
+  value: 'auto',
+  description: 'Select strong random number source')
+
 option('readline', type: 'feature', value: 'auto',
   description: 'Use GNU Readline or BSD Libedit for editing')
 
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index d6fc8333850..b70f00cfcc1 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -3195,6 +3195,13 @@
   assign_hook => 'assign_log_connections',
 },
 
+{ name => 'strong_random_source', type => 'string', context => 'PGC_INTERNAL', group => 'PRESET_OPTIONS',
+  short_desc => 'Shows implementation used for generating strong random number.',
+  flags => 'GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE',
+  variable => 'strong_random_source',
+  boot_val => 'DEFAULT_STRONG_RANDOM_SOURCE',
+},
+
 { name => 'backslash_quote', type => 'enum', context => 'PGC_USERSET', group => 'COMPAT_OPTIONS_PREVIOUS',
   short_desc => 'Sets whether "\\\\\'" is allowed in string literals.',
   variable => 'backslash_quote',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 00c8376cf4d..1a58d0d19c1 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -620,6 +620,13 @@ static int	num_os_semaphores;
 static bool data_checksums;
 static bool integer_datetimes;
 
+#ifdef STRONG_RANDOM_SOURCE_OPENSSL
+#define DEFAULT_STRONG_RANDOM_SOURCE "openssl"
+#else
+#define DEFAULT_STRONG_RANDOM_SOURCE "system"
+#endif
+static char *strong_random_source = DEFAULT_STRONG_RANDOM_SOURCE;
+
 #ifdef USE_ASSERT_CHECKING
 #define DEFAULT_ASSERT_ENABLED true
 #else
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index f52f14cc566..4aeceb53eb4 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -666,6 +666,12 @@
 /* Define to 1 if strerror_r() returns int. */
 #undef STRERROR_R_INT
 
+/* Define to 1 to use system's native source for strong random number generation  */
+#undef STRONG_RANDOM_SOURCE_SYSTEM
+
+/* Define to 1 to use OpenSSL libary for strong random number generation */
+#undef STRONG_RANDOM_SOURCE_OPENSSL
+
 /* Define to 1 to use ARMv8 CRC Extension. */
 #undef USE_ARMV8_CRC32C
 
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index ea6780dcc9f..0d3f00f588f 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -50,7 +50,7 @@
 
 
 
-#ifdef USE_OPENSSL
+#ifdef STRONG_RANDOM_SOURCE_OPENSSL
 
 #include <openssl/rand.h>
 
@@ -92,7 +92,7 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#elif WIN32
+#elif WIN32						/* STRONG_RANDOM_SOURCE_SYSTEM and WIN32 */
 
 #include <wincrypt.h>
 /*
@@ -134,7 +134,7 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#else							/* STRONG_RANDOM_SOURCE_SYSTEM and not WIN32 */
 
 /*
  * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
-- 
2.47.3

v2-0002-Support-getrandom-as-random-source-where-availabl.patchapplication/octet-stream; name=v2-0002-Support-getrandom-as-random-source-where-availabl.patchDownload
From c30924b77c585cf5a28e4eb34924892f8e7e73b4 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
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 <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 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 <sys/random.h>
 
-/*
- * 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

#67Masahiko Sawada
sawada.mshk@gmail.com
In reply to: Masahiko Sawada (#66)
2 attachment(s)
Re: Support getrandom() for pg_strong_random() source

On Mon, Nov 3, 2025 at 11:48 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

On Fri, Oct 31, 2025 at 1:31 PM Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

On Thu, Oct 23, 2025 at 2:48 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:

I've drafted the patches for this item.

Thanks!

The 0001 patch allows the packager to select the random source:
"openssl" or "system", by using --with-random-source option. If it's
omitted and OpenSSL is used (--with-openssl or --with-ssl=openssl),
'openssl' source is automatically chosen. The selected random source
can be shown in read-only GUC parameter random_source.

Thank you for the comments.

I think 0001 is missing logic to switch pg_strong_random.c according
to the new #defines; selecting `system` still uses OpenSSL on my
machine.

Fixed.

+  --with-random-source=NAME
+                          set random number source (system,openssl)

Bikeshedding: should we make it clear in the name that this covers
only the "strong" random implementation, for cryptography? Maybe
--with-strong-random, or --with-crypt-random, or...

Agreed, I renamed it to --with-strong-random and applied it to other
related names too .

+ AC_DEFINE([USE_RANDOM_SOURCE_OPENSSL] , 1, [Define to 1 to use OpenSSL libary for random number generation])

autoreconf 2.69 is refusing to process these AC_DEFINEs on my machine,
and I think it's because of the space between the end bracket ']' and
the comma. Removing it fixes generation for me.

Fixed.

@@ -3500,5 +3507,4 @@
options => 'io_method_options',
assign_hook => 'assign_io_method',
},
-
]

(FWIW, I prefer the extra newline there; it's easier for me to read
and it matches the spacing at the top.)

Fixed.

The 0002 patch supports getrandom() as a 'system' random source where
available while keeping the method of reading /dev/urandom as a
fallback option.

+AC_CHECK_HEADER([sys/random.h],
+ [AC_CHECK_FUNCS([getrandom],
+  [AC_DEFINE(HAVE_GETRANDOM, 1, [Define to 1 if you have getrandom])])])

AC_CHECK_FUNCS([getrandom]) by itself should let autoconf take care of
the description; I think the extra AC_DEFINE there will duplicate some
handling.

+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

Some of the more complicated prefixes use multiline literals, but for
this case I think `prefix: '#include <sys/random.h'` would be more
readable. Also, is there a way to merge this check into the
check_funcs logic later on?

Agreed with the above comments. I think we don't need a header check
for sys/random.h actually. Checking the getrandom() function present
seems to be sufficient in this case.

I've attached the updated patches.

Rebased the patches.

Regards,

--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

Attachments:

v3-0001-Add-configure-time-selection-of-strong-random-num.patchapplication/octet-stream; name=v3-0001-Add-configure-time-selection-of-strong-random-num.patchDownload
From 71f650c1d87504e02309df00c138077f00e0d7bf Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 21 Oct 2025 16:25:23 -0700
Subject: [PATCH v3 1/2] Add configure-time selection of strong random number
 source.

Previously, the random number source was automatically selected: OpenSSL
was the first choice, with native platform sources (Windows API or
/dev/urandom) used as fallback options.

This commit adds the ability to specify the random number source at
configure time using either the --with-strong-random option for the
configure script or the -Dstrong_random option for meson.

The selected random source can be viewed through the read-only GUC
parameter strong_random_source.

Reviewed-by:
Discussion: https://postgr.es/m/
---
 configure                                 | 78 +++++++++++++++++++----
 configure.ac                              | 50 +++++++++++----
 doc/src/sgml/config.sgml                  | 19 ++++++
 doc/src/sgml/installation.sgml            | 40 ++++++++++++
 meson.build                               | 22 +++++++
 meson_options.txt                         |  4 ++
 src/backend/utils/misc/guc_parameters.dat |  7 ++
 src/backend/utils/misc/guc_tables.c       |  7 ++
 src/include/pg_config.h.in                |  6 ++
 src/port/pg_strong_random.c               |  6 +-
 10 files changed, 211 insertions(+), 28 deletions(-)

diff --git a/configure b/configure
index 02e4ec7890f..28df8d20139 100755
--- a/configure
+++ b/configure
@@ -887,6 +887,7 @@ with_zstd
 with_ssl
 with_openssl
 enable_largefile
+with_strong_random
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1606,6 +1607,8 @@ Optional Packages:
   --with-zstd             build with ZSTD support
   --with-ssl=LIB          use LIB for SSL/TLS support (openssl)
   --with-openssl          obsolete spelling of --with-ssl=openssl
+  --with-strong-random=NAME
+                          set strong random number source (system,openssl)
 
 Some influential environment variables:
   PG_TEST_EXTRA
@@ -18400,24 +18403,69 @@ $as_echo "#define USE_WIN32_SHARED_MEMORY 1" >>confdefs.h
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select strong random number source.
+#
+
+
+
+
+# Check whether --with-strong-random was given.
+if test "${with_strong_random+set}" = set; then :
+  withval=$with_strong_random;
+  case $withval in
+    yes)
+      as_fn_error $? "argument required for --with-strong-random option" "$LINENO" 5
+      ;;
+    no)
+      as_fn_error $? "argument required for --with-strong-random option" "$LINENO" 5
+      ;;
+    *)
+      strong_random=$withval
+      ;;
+  esac
+
+fi
+
+
+
+# If nothing is specified to --with-strong-random, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$strong_random" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    strong_random=openssl
+  else
+    strong_random=system
+  fi
+elif test x"$strong_random" != x"openssl" -a x"$strong_random" != x"system" ; then
+  as_fn_error $? "--with-strong-random must sepcify one of system or openssl" "$LINENO" 5
+fi
+
+if test "$strong_random" = openssl -a x"$with_ssl" != x"openssl" ; then
+  as_fn_error $? "OpenSSL library is required for random number generation" "$LINENO" 5
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking which random number source to use" >&5
 $as_echo_n "checking which random number source to use... " >&6; }
-if test x"$with_ssl" = x"openssl" ; then
+if test "$strong_random" = openssl ; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5
 $as_echo "OpenSSL" >&6; }
-elif test x"$PORTNAME" = x"win32" ; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Windows native" >&5
+
+$as_echo "#define STRONG_RANDOM_SOURCE_OPENSSL 1" >>confdefs.h
+
+else
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  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"$cross_compiling" = x"yes"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming /dev/urandom" >&5
+  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; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: /dev/urandom" >&5
 $as_echo "/dev/urandom" >&6; }
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /dev/urandom" >&5
 $as_echo_n "checking for /dev/urandom... " >&6; }
 if ${ac_cv_file__dev_urandom+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -18437,11 +18485,15 @@ if test "x$ac_cv_file__dev_urandom" = xyes; then :
 fi
 
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    as_fn_error $? "
+    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
+    fi
   fi
+
+$as_echo "#define STRONG_RANDOM_SOURCE_SYSTEM 1" >>confdefs.h
+
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/configure.ac b/configure.ac
index b90a220a635..c86083b2c74 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2287,25 +2287,51 @@ else
   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
 fi
 
-# Select random number source. If a TLS library is used then it will be the
-# first choice, else the native platform sources (Windows API or /dev/urandom)
-# will be used.
+#
+# Select strong random number source.
+#
+
+PGAC_ARG_REQ(with, strong-random, [NAME], [set strong random number source (system,openssl)],
+             [strong_random=$withval])
+
+# If nothing is specified to --with-strong-random, the default value is chosen depends
+# on OpenSSL availability.
+if test x"$strong_random" = x"" ; then
+  if test x"$with_ssl" = x"openssl" ; then
+    strong_random=openssl
+  else
+    strong_random=system
+  fi
+elif test x"$strong_random" != x"openssl" -a x"$strong_random" != x"system" ; then
+  AC_MSG_ERROR([--with-strong-random must sepcify one of system or openssl])
+fi
+
+if test "$strong_random" = openssl -a x"$with_ssl" != x"openssl" ; then
+  AC_MSG_ERROR([OpenSSL library is required for random number generation])
+fi
+
 AC_MSG_CHECKING([which random number source to use])
-if test x"$with_ssl" = x"openssl" ; then
+if test "$strong_random" = openssl ; then
   AC_MSG_RESULT([OpenSSL])
-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])
+  AC_DEFINE([STRONG_RANDOM_SOURCE_OPENSSL], 1, [Define to 1 to use OpenSSL libary for strong random number generation])
 else
-  AC_MSG_RESULT([/dev/urandom])
-  AC_CHECK_FILE([/dev/urandom], [], [])
+  # Select native platform source sources (Windows API or /dev/urandom) will
+  # be used.
+  if 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])
+  else
+    AC_MSG_RESULT([/dev/urandom])
+    AC_CHECK_FILE([/dev/urandom], [], [])
 
-  if test x"$ac_cv_file__dev_urandom" = x"no" ; then
-    AC_MSG_ERROR([
+    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.])
+    fi
   fi
+  AC_DEFINE([STRONG_RANDOM_SOURCE_SYSTEM], 1, [Define to 1 to use system native source for strong random number generation])
 fi
 
 # If not set in template file, set bytes to use libc memset()
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 601aa3afb8e..db8ce2b0999 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -12124,6 +12124,25 @@ dynamic_library_path = '/usr/local/lib/postgresql:$libdir'
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-strong-random-source" xreflabel="strong_random_source">
+      <term><varname>strong_random_source</varname> (<type>string</type>)
+      <indexterm>
+       <primary><varname>strong_random_source</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Reports the name of implementation used to generate cryptographically secure
+        random data: <literal>system</literal> or <literal>openssl</literal>. It
+        is determined when building the server. See more information see
+        <link linkend="configure-option-with-strong-random"><option>--with-strong-random
+        </option></link> for installation with Autoconf or
+        <link linkend="configure-strong-random-meson"><option>-Dstrong_random</option>
+        </link> for installation with Meson.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-wal-block-size" xreflabel="wal_block_size">
       <term><varname>wal_block_size</varname> (<type>integer</type>)
       <indexterm>
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fe8d73e1f8c..ce0283ddf5b 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -1531,6 +1531,26 @@ build-postgresql:
        </listitem>
       </varlistentry>
 
+      <varlistentry id="configure-option-with-strong-random">
+       <term><option>--with-strong-random=<replaceable>NAME</replaceable></option></term>
+       <listitem>
+        <para>
+         Specifies the imlementation used to generate cryptographically secure random
+         data. Valid values are <literal>system</literal> and <literal>openssl</literal>.
+        </para>
+        <para>
+         <productname>PostgreSQL</productname> relies on strong random numbers in
+         security-sensitive operations. For example, random values are used when generating
+         salts for <literal>SCRAM-SHA-256</literal> password storage and when creating
+         UUIDs. By default, the implementation is chosen based on the
+         <option>--with-ssl</option> option: if <productname>PostgreSQL</productname>
+         is built with <productname>OpenSSL</productname> support,
+         <productname>OpenSSL</productname>'s random generator is used; otherwise, the
+         operating system native secure random facility is used. This option overrides
+         that behavior and forces use of the specified source.
+        </para>
+       </listitem>
+      </varlistentry>
      </variablelist>
 
    </sect3>
@@ -3054,6 +3074,26 @@ ninja install
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry id="configure-strong-random-meson">
+      <term><option>-Dstrong_random={ auto | system | openssl }</option></term>
+       <listitem>
+        <para>
+         Specifies the imlementation used to generate cryptographically secure random
+         data.
+        </para>
+        <para>
+         <productname>PostgreSQL</productname> relies on strong random numbers in
+         security-sensitive operations. For example, random values are used when generating
+         salts for <literal>SCRAM-SHA-256</literal> password storage and when creating
+         UUIDs. Default to auto and the implementation will be chosen based on the
+         <option>-Dssl</option> option: if <productname>PostgreSQL</productname>
+         is built with <productname>OpenSSL</productname> support,
+         <productname>OpenSSL</productname>'s random generator is used; otherwise, the
+         operating system native secure random facility is used.
+        </para>
+       </listitem>
+     </varlistentry>
     </variablelist>
    </sect3>
 
diff --git a/meson.build b/meson.build
index c3834a9dc8f..ce28ac4c616 100644
--- a/meson.build
+++ b/meson.build
@@ -2576,7 +2576,29 @@ if not have_optimized_crc
   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
 endif
 
+###############################################################
+# Select strong random number source.
+###############################################################
+rand_src_opt = get_option('strong_random')
+if rand_src_opt == 'auto'
+  if ssl.found()
+    rand_src_opt = 'openssl'
+  else
+    rand_src_opt = 'system'
+  endif
+endif
+
+if rand_src_opt == 'openssl' and not ssl.found()
+  error('OpenSSL library must be enabled for strong random number generation')
+endif
 
+if rand_src_opt == 'system'
+  cdata.set('STRONG_RANDOM_SOURCE_SYSTEM', 1,
+            description: 'Define to 1 to use system native source for strong random number generation')
+else
+  cdata.set('STRONG_RANDOM_SOURCE_OPENSSL', 1,
+            description: 'Define to 1 to use OpenSSL libary for strong random number generation')
+endif
 
 ###############################################################
 # Other CPU specific stuff
diff --git a/meson_options.txt b/meson_options.txt
index 6a793f3e479..19321c53e68 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -142,6 +142,10 @@ option('pltcl', type: 'feature', value: 'auto',
 option('tcl_version', type: 'string', value: 'tcl',
   description: 'Tcl version')
 
+option('strong_random', type: 'combo', choices: ['auto', 'system', 'openssl'],
+  value: 'auto',
+  description: 'Select strong random number source')
+
 option('readline', type: 'feature', value: 'auto',
   description: 'Use GNU Readline or BSD Libedit for editing')
 
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index 7c60b125564..fad27367c26 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -2784,6 +2784,13 @@
   assign_hook => 'assign_stats_fetch_consistency',
 },
 
+{ name => 'strong_random_source', type => 'string', context => 'PGC_INTERNAL', group => 'PRESET_OPTIONS',
+  short_desc => 'Shows implementation used for generating strong random number.',
+  flags => 'GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE',
+  variable => 'strong_random_source',
+  boot_val => 'DEFAULT_STRONG_RANDOM_SOURCE',
+},
+
 { name => 'subtransaction_buffers', type => 'int', context => 'PGC_POSTMASTER', group => 'RESOURCES_MEM',
   short_desc => 'Sets the size of the dedicated buffer pool used for the subtransaction cache.',
   long_desc => '0 means use a fraction of "shared_buffers".',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 73ff6ad0a32..ec008d48138 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -621,6 +621,13 @@ static int	effective_wal_level = WAL_LEVEL_REPLICA;
 static bool data_checksums;
 static bool integer_datetimes;
 
+#ifdef STRONG_RANDOM_SOURCE_OPENSSL
+#define DEFAULT_STRONG_RANDOM_SOURCE "openssl"
+#else
+#define DEFAULT_STRONG_RANDOM_SOURCE "system"
+#endif
+static char *strong_random_source = DEFAULT_STRONG_RANDOM_SOURCE;
+
 #ifdef USE_ASSERT_CHECKING
 #define DEFAULT_ASSERT_ENABLED true
 #else
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2dd8f6b9a38..9bcc9c54ff8 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -660,6 +660,12 @@
 /* Define to 1 if strerror_r() returns int. */
 #undef STRERROR_R_INT
 
+/* Define to 1 to use system's native source for strong random number generation  */
+#undef STRONG_RANDOM_SOURCE_SYSTEM
+
+/* Define to 1 to use OpenSSL libary for strong random number generation */
+#undef STRONG_RANDOM_SOURCE_OPENSSL
+
 /* Define to 1 to use ARMv8 CRC Extension. */
 #undef USE_ARMV8_CRC32C
 
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index c8d8a70d896..cc6f598ac67 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -50,7 +50,7 @@
 
 
 
-#ifdef USE_OPENSSL
+#ifdef STRONG_RANDOM_SOURCE_OPENSSL
 
 #include <openssl/rand.h>
 
@@ -92,7 +92,7 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#elif WIN32
+#elif WIN32						/* STRONG_RANDOM_SOURCE_SYSTEM and WIN32 */
 
 #include <wincrypt.h>
 /*
@@ -134,7 +134,7 @@ pg_strong_random(void *buf, size_t len)
 	return false;
 }
 
-#else							/* not USE_OPENSSL or WIN32 */
+#else							/* STRONG_RANDOM_SOURCE_SYSTEM and not WIN32 */
 
 /*
  * Without OpenSSL or Win32 support, just read /dev/urandom ourselves.
-- 
2.47.3

v3-0002-Support-getrandom-as-random-source-where-availabl.patchapplication/octet-stream; name=v3-0002-Support-getrandom-as-random-source-where-availabl.patchDownload
From a65ac70e886bf3573483709bcb248b2328e7b32a Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 21 Oct 2025 17:35:15 -0700
Subject: [PATCH v3 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 28df8d20139..91135999d9d 100755
--- a/configure
+++ b/configure
@@ -15576,7 +15576,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"
@@ -18459,6 +18459,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; }
@@ -18488,7 +18491,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 c86083b2c74..8adc8bc0f66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1781,6 +1781,7 @@ AC_CHECK_FUNCS(m4_normalize([
 	getauxval
 	getifaddrs
 	getpeerucred
+	getrandom
 	inet_pton
 	kqueue
 	localeconv_l
@@ -2319,6 +2320,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
@@ -2328,7 +2331,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 ce28ac4c616..d835e338917 100644
--- a/meson.build
+++ b/meson.build
@@ -2911,6 +2911,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 9bcc9c54ff8..bd658364253 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -179,6 +179,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 cc6f598ac67..817ff6388bf 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 <sys/random.h>
 
-/*
- * 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