Skip to content

Commit 3fbbaf9

Browse files
committed
fix: seed session GC RNG lazily per worker process
1 parent ef12ecd commit 3fbbaf9

2 files changed

Lines changed: 19 additions & 9 deletions

File tree

ext/session/php_session.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,6 @@ typedef struct _php_ps_globals {
146146
zend_string *session_started_filename;
147147
uint32_t session_started_lineno;
148148
int module_number;
149-
/* Unused since the GC probability draw was made stateless; retained only
150-
* to preserve struct layout (ABI) on stable branches. */
151149
php_random_status_state_pcgoneseq128xslrr64 random_state;
152150
php_random_algo_with_state random;
153151
zend_long gc_probability;
@@ -185,6 +183,7 @@ typedef struct _php_ps_globals {
185183
bool mod_user_is_open;
186184
bool mod_user_uses_object_methods_as_handlers;
187185
bool use_trans_sid; /* contains the INI value of whether to use trans-sid */
186+
bool random_seeded;
188187
} php_ps_globals;
189188

190189
typedef php_ps_globals zend_ps_globals;

ext/session/session.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -393,14 +393,19 @@ static zend_long php_session_gc(bool immediate)
393393
/* GC must be done before reading session data. */
394394
if ((PS(mod_data) || PS(mod_user_implemented))) {
395395
if (!collect && PS(gc_probability) > 0) {
396-
/* Draw fresh entropy per request instead of using the per-process
397-
* PS(random) state. The latter is seeded once in GINIT, which runs
398-
* before SAPIs such as PHP-FPM fork their workers, so every worker
399-
* would inherit and replay the same GC-decision sequence. */
400-
uint32_t rand_val;
401-
if (php_random_bytes_silent(&rand_val, sizeof(rand_val)) == SUCCESS) {
402-
collect = (rand_val % (uint32_t) PS(gc_divisor)) < (uint32_t) PS(gc_probability);
396+
/* Seed lazily on first GC draw per process. */
397+
if (UNEXPECTED(!PS(random_seeded))) {
398+
php_random_uint128_t seed;
399+
if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) {
400+
seed = php_random_uint128_constant(
401+
php_random_generate_fallback_seed(),
402+
php_random_generate_fallback_seed()
403+
);
404+
}
405+
php_random_pcgoneseq128xslrr64_seed128(PS(random).state, seed);
406+
PS(random_seeded) = true;
403407
}
408+
collect = php_random_range(PS(random), 0, PS(gc_divisor) - 1) < PS(gc_probability);
404409
}
405410

406411
if (collect) {
@@ -2892,6 +2897,12 @@ static PHP_GINIT_FUNCTION(ps)
28922897
ZVAL_UNDEF(&ps_globals->mod_user_names.ps_validate_sid);
28932898
ZVAL_UNDEF(&ps_globals->mod_user_names.ps_update_timestamp);
28942899
ZVAL_UNDEF(&ps_globals->http_session_vars);
2900+
2901+
ps_globals->random = (php_random_algo_with_state){
2902+
.algo = &php_random_algo_pcgoneseq128xslrr64,
2903+
.state = &ps_globals->random_state,
2904+
};
2905+
ps_globals->random_seeded = false;
28952906
}
28962907

28972908
static PHP_MINIT_FUNCTION(session)

0 commit comments

Comments
 (0)