From 76efc715ade5c35e7b618d370b7a9e0045ae3dc0 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] Use different random() seeds in all backends.

Background workers, including parallel workers, were generating
the same sequence of numbers in various code paths that use
random().  This was noticed by harmless DSM handle collisions
during execution of Parallel Hash, but any code that calls
random() in background workers could be affected if it cares
about different backends generating different numbers.

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

Back-patch only to 11, because that's where Parallel Hash landed,
making this obvious to anyone tracing syscalls.

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)

