From 88396949018b1e66d94ec9d77f54086fb55fcaa6 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Fri, 12 Apr 2024 13:20:31 +0200
Subject: [PATCH v9 5/5] Remove pg_strong_random initialization.

The random number generator in OpenSSL 1.1.1 was redesigned to provide
fork safety by default, thus removing the need for calling RAND_poll
after forking to ensure that two processes cannot share the same state.
Since we now support 1.1.0 as the minumum version, and 1.1.1 is being
increasingly phased out from production use, remove the initialization
and only do it explicitly for anyone running 1.1.0.  This will penalize
1.1.0 installations by doing it per call to pg_strong_random, but the
number of production environments running the latest PostgreSQL combined
with a very out of date OpenSSL (which never was available as LTS/ELS)
is believed to be low.

LibreSSL changed random number generator when forking OpenSSL and has
provided fork safety since version 2.0.2.

This removes the overhead of initializing the RNG for strong random which
for the vast majority of users is no longer required.

Discussion: https://postgr.es/m/CA+hUKGKh7QrYzu=8yWEUJvXtMVm_CNWH1L_TLWCbZMwbi1XP2Q@mail.gmail.com
---
 src/backend/postmaster/fork_process.c |  3 --
 src/include/port.h                    |  1 -
 src/port/pg_strong_random.c           | 43 ++++++++++-----------------
 3 files changed, 16 insertions(+), 31 deletions(-)

diff --git a/src/backend/postmaster/fork_process.c b/src/backend/postmaster/fork_process.c
index 5e42a74ab5..bcff9ef661 100644
--- a/src/backend/postmaster/fork_process.c
+++ b/src/backend/postmaster/fork_process.c
@@ -110,9 +110,6 @@ fork_process(void)
 				close(fd);
 			}
 		}
-
-		/* do post-fork initialization for random number generation */
-		pg_strong_random_init();
 	}
 	else
 	{
diff --git a/src/include/port.h b/src/include/port.h
index ae115d2d97..2a363764f1 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -473,7 +473,6 @@ 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);
 
 /*
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index 5f2b248425..48b8671e68 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -25,14 +25,11 @@
 #include <sys/time.h>
 
 /*
- * pg_strong_random & pg_strong_random_init
+ * pg_strong_random
  *
  * Generate requested number of random bytes. The returned bytes are
  * cryptographically secure, suitable for use e.g. in authentication.
  *
- * Before pg_strong_random is called in any process, the generator must first
- * be initialized by calling pg_strong_random_init().
- *
  * We rely on system facilities for actually generating the numbers.
  * We support a number of sources:
  *
@@ -51,22 +48,26 @@
 #ifdef USE_OPENSSL
 
 #include <openssl/rand.h>
-
-void
-pg_strong_random_init(void)
-{
-	/*
-	 * Make sure processes do not share OpenSSL randomness state.  This is no
-	 * longer required in OpenSSL 1.1.1 and later versions, but until we drop
-	 * support for version < 1.1.1 we need to do this.
-	 */
-	RAND_poll();
-}
+#include <openssl/opensslv.h>
 
 bool
 pg_strong_random(void *buf, size_t len)
 {
 	int			i;
+#if (OPENSSL_VERSION_NUMBER < 0x10101000L)
+	static bool rand_initialized = false;
+
+	/*
+	 * Make sure processes do not share OpenSSL randomness state.  This is not
+	 * required on LibreSSL and no longer required in OpenSSL 1.1.1 and later
+	 * versions.
+	 */
+	if (!rand_initialized)
+	{
+		RAND_poll();
+		rand_initialized = true;
+	}
+#endif
 
 	/*
 	 * Check that OpenSSL's CSPRNG has been sufficiently seeded, and if not
@@ -104,12 +105,6 @@ pg_strong_random(void *buf, size_t len)
  */
 static HCRYPTPROV hProvider = 0;
 
-void
-pg_strong_random_init(void)
-{
-	/* No initialization needed on WIN32 */
-}
-
 bool
 pg_strong_random(void *buf, size_t len)
 {
@@ -143,12 +138,6 @@ pg_strong_random(void *buf, size_t len)
  * 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)
 {
-- 
2.39.3 (Apple Git-146)

