feat(rand): add DD_TRACE_SECURE_RANDOM support to span ID generation#3873
feat(rand): add DD_TRACE_SECURE_RANDOM support to span ID generation#3873litianningdatadog wants to merge 1 commit into
Conversation
When DD_TRACE_SECURE_RANDOM=true, ddtrace_generate_span_id() bypasses the MT19937-64 thread-local state and calls php_random_bytes_silent() instead, which reads from the OS entropy pool (getrandom(2)) on every invocation with no userspace PRNG state. This ensures span IDs are drawn from the kernel entropy pool on every call, making them safe in process-snapshot environments where PRNG state seeded at startup would be identical across all resumed instances. The existing MT path and ddtrace_seed_prng() RINIT seeding are unchanged; the 128-bit trace ID .time component is a Unix timestamp and requires no fix. Tests: secure_random_generates_nonzero_ids.phpt verifies non-zero distinct IDs under the CSPRNG path; secure_random_ignores_prng_seed.phpt verifies that a fixed DD_TRACE_DEBUG_PRNG_SEED does not constrain output when DD_TRACE_SECURE_RANDOM=true. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ad49f5d1d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return id; | ||
| } | ||
| } | ||
| return (uint64_t)genrand64_int64(); |
There was a problem hiding this comment.
Do not silently fall back from secure IDs
When DD_TRACE_SECURE_RANDOM=true but php_random_bytes_silent() returns FAILURE (for example, an unavailable OS entropy source), this falls back to the MT generator and reintroduces the exact duplicated-sequence risk this flag is meant to avoid in snapshot-restored processes. Because the fallback is silent, operators who enabled the secure mode will still emit MT-derived span/trace IDs without knowing the security property was lost; this path should fail closed, retry, or at least surface the failure instead of using genrand64_int64().
Useful? React with 👍 / 👎.
Tech Doc
Summary
DD_TRACE_SECURE_RANDOMboolean config option (defaultfalse) toext/configuration.hDD_TRACE_SECURE_RANDOM=true,ddtrace_generate_span_id()callsphp_random_bytes_silent()— which reads from the OS entropy pool (getrandom(2)) per call — instead of the MT19937-64 PRNGddtrace_seed_prng()RINIT seeding are fully preserved for non-secure-random deploymentsMotivation
PHP's span ID generator uses MT19937-64, a Mersenne Twister whose
312-element state array lives as a
staticC variable inddtrace.so.The state is seeded at RINIT (per PHP request) from
php_random_int_silent()which is cryptographically secure, but the derived PRNG state is
captured verbatim in any process memory snapshot.
In process-snapshot environments, instances restored from the same
snapshot have identical MT state and thus produce the same span ID
sequence. When
DD_TRACE_SECURE_RANDOM=true, the MT is bypassedentirely:
php_random_bytes_silent()callsgetrandom(2)directlyon each invocation with no userspace PRNG state, so snapshot-restored
instances draw independent entropy immediately.
This flag is intended to be injected automatically by the serverless
init container process before spawning the user application.
Test plan
tests/ext/secure_random_generates_nonzero_ids.phpt— verifies non-zero,distinct IDs under the
DD_TRACE_SECURE_RANDOM=truepathtests/ext/secure_random_ignores_prng_seed.phpt— verifies that a fixedDD_TRACE_DEBUG_PRNG_SEEDdoes not constrain output whenDD_TRACE_SECURE_RANDOM=true(proving the MT is fully bypassed)Compatibility
php_random_bytes_silentis available via existing conditional includesin
ext/random.c—ext/standard/php_random.h(PHP < 8.4) andext/random/php_random.h(PHP ≥ 8.4) — no new header dependencies.🤖 Generated with Claude Code