From 4fbc6fc83d91fd4cc68f87c0441ef2d9655d55b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sat, 16 Mar 2024 15:07:49 +0100 Subject: [PATCH 1/4] random: Improve the output quality of RANDOM_SEED() Previously 4 consecutive calls to `RANDOM_SEED()` each for 4 different CLI requests resulted in: $ sapi/cli/php test.php 2c13e9fde9caa 2c13e9fd1d6b0 2c13e9fd4de34 2c13e9fd1610e $ sapi/cli/php test.php 2c1436764fe07 2c14367621770 2c143676c0bf6 2c143676e02f5 $ sapi/cli/php test.php 2c144995a0626 2c14499590fe2 2c144995c65db 2c14499536833 $ sapi/cli/php test.php 2c145cb30860b 2c145cb3ec027 2c145cb33b4ca 2c145cb38ff63 Now they result in: $ sapi/cli/php test.php 6796973ace1b5f3d 1913daf5c158cb4b 255dbf24237bc8c9 7c3ba22e60f35196 $ sapi/cli/php test.php afb7cc9ba9819cd2 3e01a71b91ad020c 6b718364d3ef108 bdcd17beeb4b31d2 $ sapi/cli/php test.php 53d36eb9b83f8788 4381c85e816187aa 2e9b32ee9898e71e 31d15c946842bddb $ sapi/cli/php test.php 2037a3cba88114b4 ba0b0d93a9bb43aa e13d82d2421269e2 191de474f3292240 --- UPGRADING.INTERNALS | 5 +++ ext/random/php_random.h | 14 +++---- ext/random/random.c | 89 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 9 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index e0f0ac46f8134..6a1202a4bdc7e 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -174,6 +174,11 @@ PHP 8.4 INTERNALS UPGRADE NOTES - The CSPRNG API (php_random_(bytes|int)_*) is now provided by the new and much smaller php_random_csprng.h header. The new header is included in php_random.h for compatibility with existing users. + - A new php_random_generate_fallback_seed() function has been added as a + replacement for the generically named GENERATE_SEED(). The internal + implementation has been improved to generate better seeds, however any + users should use the opportunity to verify that seeding is first + attempted using the CSPRNG for better output size flexibility. c. ext/xsl - The function php_xsl_create_object() was removed as it was not used diff --git a/ext/random/php_random.h b/ext/random/php_random.h index 5a8df6bee2ba0..45c527a39effb 100644 --- a/ext/random/php_random.h +++ b/ext/random/php_random.h @@ -37,17 +37,11 @@ PHPAPI double php_combined_lcg(void); +PHPAPI uint64_t php_random_generate_fallback_seed(void); + static inline zend_long GENERATE_SEED(void) { - zend_ulong pid; - -# ifdef PHP_WIN32 - pid = (zend_ulong) GetCurrentProcessId(); -# else - pid = (zend_ulong) getpid(); -# endif - - return (((zend_long) ((zend_ulong) time(NULL) * pid)) ^ ((zend_long) (1000000.0 * php_combined_lcg()))); + return (zend_long)php_random_generate_fallback_seed(); } # define PHP_MT_RAND_MAX ((zend_long) (0x7FFFFFFF)) /* (1<<31) - 1 */ @@ -213,6 +207,8 @@ ZEND_BEGIN_MODULE_GLOBALS(random) int random_fd; bool combined_lcg_seeded; bool mt19937_seeded; + bool fallback_seed_initialized; + unsigned char fallback_seed[20]; php_random_status_state_combinedlcg combined_lcg; php_random_status_state_mt19937 mt19937; ZEND_END_MODULE_GLOBALS(random) diff --git a/ext/random/random.c b/ext/random/random.c index f74f760ece4ed..b1d5e596dcd48 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -12,6 +12,7 @@ +----------------------------------------------------------------------+ | Authors: Sammy Kaye Powers | | Go Kudo | + | Tim Düsterhus | +----------------------------------------------------------------------+ */ @@ -31,6 +32,7 @@ #include "php_random.h" #include "php_random_csprng.h" +#include "ext/standard/sha1.h" #if HAVE_UNISTD_H # include @@ -612,10 +614,97 @@ PHP_FUNCTION(random_int) } /* }}} */ +static void write_32(PHP_SHA1_CTX *c, uint32_t u) +{ + unsigned char buf[4]; + unsigned char *p = buf; + *(p++) = (u >> 0) & 0xff; + *(p++) = (u >> 8) & 0xff; + *(p++) = (u >> 16) & 0xff; + *(p++) = (u >> 24) & 0xff; + PHP_SHA1Update(c, buf, sizeof(buf)); +} + +static void write_64(PHP_SHA1_CTX *c, uint64_t u) +{ + write_32(c, u); + write_32(c, u >> 32); +} + +static void write_p(PHP_SHA1_CTX *c, uintptr_t p) +{ + if (sizeof(p) == 4) { + write_32(c, p); + } else { + write_64(c, p); + } +} + +uint64_t php_random_generate_fallback_seed(void) +{ + /* Mix various values using SHA-1 as a PRF to obtain as + * much entropy as possible, hopefully generating an + * unpredictable and independent uint64_t. Nevertheless + * the output of this function MUST NOT be treated as + * being cryptographically safe. + */ + PHP_SHA1_CTX c; + struct timeval tv; + char buf[64 + 1]; + + PHP_SHA1Init(&c); + if (!RANDOM_G(fallback_seed_initialized)) { + /* Current time. */ + gettimeofday(&tv, NULL); + write_32(&c, tv.tv_sec); + write_32(&c, tv.tv_usec); + /* Various PIDs. */ + write_32(&c, getpid()); + write_32(&c, getppid()); + write_32(&c, tsrm_thread_id()); + /* Pointer values to benefit from ASLR. */ + write_p(&c, (uintptr_t)&RANDOM_G(fallback_seed_initialized)); + write_p(&c, (uintptr_t)&c); + /* Updated time. */ + gettimeofday(&tv, NULL); + write_32(&c, tv.tv_usec); + /* Hostname. */ + memset(buf, 0, sizeof(buf)); + if (gethostname(buf, sizeof(buf) - 1) == 0) { + PHP_SHA1Update(&c, (unsigned char*)buf, strlen(buf)); + } + /* CSPRNG. */ + if (php_random_bytes_silent(buf, 16) == SUCCESS) { + PHP_SHA1Update(&c, (unsigned char*)buf, 16); + } + /* Updated time. */ + gettimeofday(&tv, NULL); + write_32(&c, tv.tv_usec); + } else { + /* Current time. */ + gettimeofday(&tv, NULL); + write_32(&c, tv.tv_sec); + write_32(&c, tv.tv_usec); + /* Previous state. */ + PHP_SHA1Update(&c, RANDOM_G(fallback_seed), 20); + } + PHP_SHA1Final(RANDOM_G(fallback_seed), &c); + RANDOM_G(fallback_seed_initialized) = true; + + uint64_t result = 0; + + for (int i = 0; i < sizeof(result); i++) { + result = result | (((uint64_t)RANDOM_G(fallback_seed)[i]) << (i * 8)); + } + + return result; +} + /* {{{ PHP_GINIT_FUNCTION */ static PHP_GINIT_FUNCTION(random) { random_globals->random_fd = -1; + random_globals->fallback_seed_initialized = false; } /* }}} */ From 538a0aa2c391f26cf90d8e724c4aec8f88eb7d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sat, 16 Mar 2024 16:35:36 +0100 Subject: [PATCH 2/4] tree-wide: Replace GENERATE_SEED() by php_random_generate_fallback_seed() --- ext/gmp/gmp.c | 6 +++--- ext/random/engine_mt19937.c | 2 +- ext/session/session.c | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 24defb66a7eee..7ae3de3671dca 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1734,9 +1734,9 @@ static void gmp_init_random(void) /* Initialize */ gmp_randinit_mt(GMPG(rand_state)); /* Seed */ - zend_long seed = 0; - if (php_random_bytes_silent(&seed, sizeof(zend_long)) == FAILURE) { - seed = GENERATE_SEED(); + unsigned long int seed = 0; + if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) { + seed = (unsigned long int)php_random_generate_fallback_seed(); } gmp_randseed_ui(GMPG(rand_state), seed); diff --git a/ext/random/engine_mt19937.c b/ext/random/engine_mt19937.c index 7723b5414d95f..077d3681b0ad4 100644 --- a/ext/random/engine_mt19937.c +++ b/ext/random/engine_mt19937.c @@ -242,7 +242,7 @@ PHPAPI void php_random_mt19937_seed_default(php_random_status_state_mt19937 *sta uint32_t seed = 0; if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) { - seed = GENERATE_SEED(); + seed = (uint32_t)php_random_generate_fallback_seed(); } php_random_mt19937_seed32(state, seed); diff --git a/ext/session/session.c b/ext/session/session.c index 6588ccc4da5f4..40ddc56f00fb7 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -2879,7 +2879,10 @@ static PHP_GINIT_FUNCTION(ps) /* {{{ */ }; php_random_uint128_t seed; if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) { - seed = php_random_uint128_constant(GENERATE_SEED(), GENERATE_SEED()); + seed = php_random_uint128_constant( + php_random_generate_fallback_seed(), + php_random_generate_fallback_seed() + ); } php_random_pcgoneseq128xslrr64_seed128(ps_globals->random.state, seed); } From 27d131dae67e6a7194c328013541de6bd276afd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sat, 16 Mar 2024 16:57:46 +0100 Subject: [PATCH 3/4] random: Fix NTS build --- ext/random/random.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/random/random.c b/ext/random/random.c index b1d5e596dcd48..5fabc19f04e17 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -661,7 +661,9 @@ uint64_t php_random_generate_fallback_seed(void) /* Various PIDs. */ write_32(&c, getpid()); write_32(&c, getppid()); +#ifdef ZTS write_32(&c, tsrm_thread_id()); +#endif /* Pointer values to benefit from ASLR. */ write_p(&c, (uintptr_t)&RANDOM_G(fallback_seed_initialized)); write_p(&c, (uintptr_t)&c); From 57dd92da0c8dbc745fd984f77e2754817e50ae0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Sat, 16 Mar 2024 17:08:27 +0100 Subject: [PATCH 4/4] random: Fix Windows build --- ext/random/random.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/random/random.c b/ext/random/random.c index 5fabc19f04e17..eb0c7286169c9 100644 --- a/ext/random/random.c +++ b/ext/random/random.c @@ -660,7 +660,9 @@ uint64_t php_random_generate_fallback_seed(void) write_32(&c, tv.tv_usec); /* Various PIDs. */ write_32(&c, getpid()); +#ifndef WIN32 write_32(&c, getppid()); +#endif #ifdef ZTS write_32(&c, tsrm_thread_id()); #endif