From 921c474e2c117535392b1287454bb44e9c550afb Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Tue, 9 Oct 2018 14:32:47 +1300
Subject: [PATCH] Make sure we initialize random seeds per backend.

Background workers, including parallel workers, were generating
the same sequence of numbers in various code paths that use
random().  The case noticed as DSM handle generation, where many
collisions can occur during Parallal Hash execution, but there
are probably other ways to see this.

Repair by refactoring the seed initialization code such that all
backends run it.  Use the same function for the postmaster, its
children and also standalone processes, for consistency.

Author: Thomas Munro
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/CAEepm%3D2eJj_6%3DB%2B2tEpGu2nf1BjthCf9nXXUouYvJJ4C5WSwhg%40mail.gmail.com
---
 src/backend/postmaster/postmaster.c | 43 +++++++++++++++++------------
 src/backend/utils/init/miscinit.c   |  4 ++-
 src/include/postmaster/postmaster.h |  1 +
 3 files changed, 29 insertions(+), 19 deletions(-)

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 41de140ae01..9e90306f411 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -602,10 +602,10 @@ PostmasterMain(int argc, char *argv[])
 	 *
 	 * Note: the seed is pretty predictable from externally-visible facts such
 	 * as postmaster start time, so avoid using random() for security-critical
-	 * random values during postmaster startup.  At the time of first
-	 * connection, PostmasterRandom will select a hopefully-more-random seed.
+	 * random values during postmaster startup.  InitPostmasterChild() will
+	 * do this again to set a new seed in child processes.
 	 */
-	srandom((unsigned int) (MyProcPid ^ MyStartTime));
+	InitRandomSeeds();
 
 	/*
 	 * By default, palloc() requests in the postmaster will be allocated in
@@ -2513,6 +2513,28 @@ ClosePostmasterPorts(bool am_syslogger)
 }
 
 
+/*
+ * InitRandomSeeds -- initialize seeds for random number generators
+ *
+ * Called in every backend after MyProcPid and MyStartTime have been assigned.
+ */
+void
+InitRandomSeeds(void)
+{
+	/*
+	 * Don't want backend to be able to see the postmaster random number
+	 * generator state.  We have to clobber the static random_seed.
+	 */
+#ifndef HAVE_STRONG_RANDOM
+	random_seed = 0;
+	random_start_time.tv_usec = 0;
+#endif
+
+	/* Set a different seed for random() in every backend. */
+	srandom((unsigned int) (MyProcPid ^ MyStartTime));
+}
+
+
 /*
  * reset_shared -- reset shared memory and semaphores
  */
@@ -4315,23 +4337,8 @@ BackendRun(Port *port)
 	char	  **av;
 	int			maxac;
 	int			ac;
-	long		secs;
-	int			usecs;
 	int			i;
 
-	/*
-	 * Don't want backend to be able to see the postmaster random number
-	 * generator state.  We have to clobber the static random_seed *and* start
-	 * a new random sequence in the random() library function.
-	 */
-#ifndef HAVE_STRONG_RANDOM
-	random_seed = 0;
-	random_start_time.tv_usec = 0;
-#endif
-	/* slightly hacky way to convert timestamptz into integers */
-	TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
-	srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
-
 	/*
 	 * Now, build the argv vector that will be given to PostgresMain.
 	 *
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index f590ecb25e8..f35bfe813f9 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -278,6 +278,8 @@ InitPostmasterChild(void)
 
 	MyStartTime = time(NULL);	/* set our start time in case we call elog */
 
+	InitRandomSeeds();			/* set up per-backend random seeds */
+
 	/*
 	 * make sure stderr is in binary mode before anything can possibly be
 	 * written to it, in case it's actually the syslogger pipe, so the pipe
@@ -331,7 +333,7 @@ InitStandaloneProcess(const char *argv0)
 	 * high-entropy seed before any user query.  Fewer distinct initial seeds
 	 * can occur here.
 	 */
-	srandom((unsigned int) (MyProcPid ^ MyStartTime));
+	InitRandomSeeds();
 
 	/* Initialize process-local latch support */
 	InitializeLatchSupport();
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 1877eef2391..217ef4490f4 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -48,6 +48,7 @@ extern PGDLLIMPORT const char *progname;
 
 extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
 extern void ClosePostmasterPorts(bool am_syslogger);
+extern void InitRandomSeeds(void);
 
 extern int	MaxLivePostmasterChildren(void);
 
-- 
2.17.1 (Apple Git-112)

