diff --git a/ext/configuration.h b/ext/configuration.h index c5f271b1ef..1e1920f85f 100644 --- a/ext/configuration.h +++ b/ext/configuration.h @@ -191,6 +191,7 @@ enum ddtrace_sidecar_connection_mode { CONFIG(INT, DD_TRACE_AGENT_CONNECT_TIMEOUT, DD_CFG_EXPSTR(DD_TRACE_AGENT_CONNECT_TIMEOUT_VAL), \ .ini_change = zai_config_system_ini_change) \ CONFIG(INT, DD_TRACE_DEBUG_PRNG_SEED, "-1", .ini_change = ddtrace_reseed_seed_change) \ + CONFIG(BOOL, DD_TRACE_SECURE_RANDOM, "false") \ CONFIG(BOOL, DD_LOG_BACKTRACE, "false") \ CONFIG(BOOL, DD_CRASHTRACKING_ENABLED, DD_CRASHTRACKING_ENABLED_DEFAULT) \ CONFIG(BOOL, DD_TRACE_GENERATE_ROOT_SPAN, "true", .ini_change = ddtrace_span_alter_root_span_config) \ diff --git a/ext/random.c b/ext/random.c index 9ddbdcd096..cd15c22b1b 100644 --- a/ext/random.c +++ b/ext/random.c @@ -106,7 +106,15 @@ uint64_t ddtrace_parse_hex_span_id(zval *zid) { return ddtrace_parse_hex_span_id_str(Z_STRVAL_P(zid), Z_STRLEN_P(zid)); } -uint64_t ddtrace_generate_span_id(void) { return (uint64_t)genrand64_int64(); } +uint64_t ddtrace_generate_span_id(void) { + if (get_DD_TRACE_SECURE_RANDOM()) { + uint64_t id; + if (php_random_bytes_silent(&id, sizeof(id)) == SUCCESS) { + return id; + } + } + return (uint64_t)genrand64_int64(); +} uint64_t ddtrace_peek_span_id(void) { ddtrace_span_properties *pspan = DDTRACE_G(active_stack) ? DDTRACE_G(active_stack)->active : NULL; diff --git a/tests/ext/secure_random_generates_nonzero_ids.phpt b/tests/ext/secure_random_generates_nonzero_ids.phpt new file mode 100644 index 0000000000..010c5745c7 --- /dev/null +++ b/tests/ext/secure_random_generates_nonzero_ids.phpt @@ -0,0 +1,29 @@ +--TEST-- +DD_TRACE_SECURE_RANDOM generates valid non-zero span IDs +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=false +DD_TRACE_DEBUG=false +DD_TRACE_SECURE_RANDOM=true +--FILE-- +id; +DDTrace\close_span(); + +DDTrace\start_span(); +$id2 = DDTrace\active_span()->id; +DDTrace\close_span(); + +// Both IDs must be non-empty numeric strings representing non-zero values. +var_dump(ctype_digit($id1) && $id1 !== '0'); +var_dump(ctype_digit($id2) && $id2 !== '0'); + +// Two consecutive IDs drawn from a CSPRNG must differ. +var_dump($id1 !== $id2); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) diff --git a/tests/ext/secure_random_ignores_prng_seed.phpt b/tests/ext/secure_random_ignores_prng_seed.phpt new file mode 100644 index 0000000000..5f5420b8b7 --- /dev/null +++ b/tests/ext/secure_random_ignores_prng_seed.phpt @@ -0,0 +1,38 @@ +--TEST-- +DD_TRACE_SECURE_RANDOM bypasses the deterministic PRNG seed +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=false +DD_TRACE_DEBUG=false +DD_TRACE_SECURE_RANDOM=true +DD_TRACE_DEBUG_PRNG_SEED=42 +--FILE-- +id; +DDTrace\close_span(); + +DDTrace\start_span(); +$id2 = DDTrace\active_span()->id; +DDTrace\close_span(); + +// IDs must be valid non-zero numeric strings. +var_dump(ctype_digit($id1) && $id1 !== '0'); +var_dump(ctype_digit($id2) && $id2 !== '0'); + +// CSPRNG output must not be equal across calls; this fails deterministically +// under the MT because seed 42 would produce the same first two values every run. +var_dump($id1 !== $id2); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true)