From 4203842a1cd06a7c30fd3eaae1c111928909e539 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 29 Dec 2018 17:56:06 -0500 Subject: [PATCH] Use pg_strong_random() to select each server process's random seed. Previously we just set the seed based on process ID and start timestamp. Both those values are directly available within the session, and can be found out or guessed by other users too, making the session's series of random(3) values fairly predictable. Up to now, our backend-internal uses of random(3) haven't seemed security-critical, but commit 88bdbd3f7 added one that potentially is: when using log_statement_sample_rate, a user might be able to predict which of his SQL statements will get logged. To improve this situation, upgrade the per-process seed initialization method to use pg_strong_random() if available, greatly reducing the predictability of the initial seed value. This adds a few tens of microseconds to process start time, but since backend startup time is at least a couple of milliseconds, that seems an acceptable price. This means that pg_strong_random() needs to be able to run without reliance on any backend infrastructure, since it will be invoked before any of that is up. It was safe for that already, but adjust comments and #include commands to make it clearer. Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us --- src/backend/postmaster/postmaster.c | 33 ++++++++++++++++++++++------- src/port/pg_strong_random.c | 12 +++++------ 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index eedc617db4c..2d5a0ac7d3b 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2520,11 +2520,13 @@ ClosePostmasterPorts(bool am_syslogger) /* * InitProcessGlobals -- set MyProcPid, MyStartTime[stamp], random seeds * - * Called early in every backend. + * Called early in the postmaster and every backend. */ void InitProcessGlobals(void) { + unsigned int rseed; + MyProcPid = getpid(); MyStartTimestamp = GetCurrentTimestamp(); MyStartTime = timestamptz_to_time_t(MyStartTimestamp); @@ -2539,15 +2541,30 @@ InitProcessGlobals(void) #endif /* - * Set a different seed for random() in every backend. Since PIDs and - * timestamps tend to change more frequently in their least significant - * bits, shift the timestamp left to allow a larger total number of seeds - * in a given time period. Since that would leave only 20 bits of the - * timestamp that cycle every ~1 second, also mix in some higher bits. + * Set a different seed for random() in every process. We want something + * unpredictable, so if possible, use high-quality random bits for the + * seed. Otherwise, fall back to a seed based on timestamp and PID. + * + * Note we can't use pg_backend_random here, since this is used in the + * postmaster, and even in a backend we might not be attached to shared + * memory yet. */ - srandom(((uint64) MyProcPid) ^ +#ifdef HAVE_STRONG_RANDOM + if (!pg_strong_random(&rseed, sizeof(rseed))) +#endif + { + /* + * Since PIDs and timestamps tend to change more frequently in their + * least significant bits, shift the timestamp left to allow a larger + * total number of seeds in a given time period. Since that would + * leave only 20 bits of the timestamp that cycle every ~1 second, + * also mix in some higher bits. + */ + rseed = ((uint64) MyProcPid) ^ ((uint64) MyStartTimestamp << 12) ^ - ((uint64) MyStartTimestamp >> 20)); + ((uint64) MyStartTimestamp >> 20); + } + srandom(rseed); } diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c index f9a06d66061..1408d3ad88e 100644 --- a/src/port/pg_strong_random.c +++ b/src/port/pg_strong_random.c @@ -6,6 +6,10 @@ * Our definition of "strong" is that it's suitable for generating random * salts and query cancellation keys, during authentication. * + * Note: this code is run quite early in postmaster and backend startup; + * therefore, even when built for backend, it cannot rely on backend + * infrastructure such as elog() or palloc(). + * * Copyright (c) 1996-2018, PostgreSQL Global Development Group * * IDENTIFICATION @@ -14,11 +18,7 @@ *------------------------------------------------------------------------- */ -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif +#include "c.h" #include #include @@ -44,7 +44,7 @@ static HCRYPTPROV hProvider = 0; * Read (random) bytes from a file. */ static bool -random_from_file(char *filename, void *buf, size_t len) +random_from_file(const char *filename, void *buf, size_t len) { int f; char *p = buf; -- 2.39.5