diff --git a/.gitlab/generate-shared.php b/.gitlab/generate-shared.php index 3bde0add92..31ea745343 100644 --- a/.gitlab/generate-shared.php +++ b/.gitlab/generate-shared.php @@ -135,6 +135,7 @@ trap 'rm -f "$BASELINE_CONFIG"' EXIT cp metadata/supported-configurations.json "$BASELINE_CONFIG" + bash tooling/generate-supported-configurations.sh --self-test bash tooling/generate-supported-configurations.sh if ! cmp -s "$BASELINE_CONFIG" metadata/supported-configurations.json; then diff --git a/ext/configuration.h b/ext/configuration.h index 6e9c4f8c2e..667c9c4976 100644 --- a/ext/configuration.h +++ b/ext/configuration.h @@ -45,7 +45,7 @@ enum datadog_sidecar_connection_mode { CONFIG(STRING, DD_AGENT_HOST, "localhost", .ini_change = zai_config_system_ini_change) \ CONFIG(STRING, DD_DOGSTATSD_URL, "http://localhost:8125") \ CONFIG(STRING, DD_DOGSTATSD_HOST, "localhost") \ - CONFIG(STRING, DD_API_KEY, "", .ini_change = zai_config_system_ini_change) \ + CONFIG(STRING, DD_API_KEY, "", .ini_change = zai_config_system_ini_change, .sensitive = true) \ CONFIG(INT, DD_DOGSTATSD_PORT, "8125") \ CONFIG(STRING, DD_ENV, "", .ini_change = datadog_alter_dd_env, \ .env_config_fallback = ddtrace_conf_otel_resource_attributes_env) \ diff --git a/ext/telemetry.c b/ext/telemetry.c index 90623a017d..0525e42538 100644 --- a/ext/telemetry.c +++ b/ext/telemetry.c @@ -98,8 +98,9 @@ void datadog_telemetry_finalize() { #if ZTS ini = zend_hash_find_ptr(EG(ini_directives), ini->name); #endif - if (cfg->names[0].len != sizeof("DD_TRACE_ENABLED") - 1 - || memcmp(cfg->names[0].ptr, "DD_TRACE_ENABLED", sizeof("DD_TRACE_ENABLED") - 1) != 0) { // DD_TRACE_ENABLED is meaningless: always off at rshutdown + if (!cfg->sensitive + && (cfg->names[0].len != sizeof("DD_TRACE_ENABLED") - 1 + || memcmp(cfg->names[0].ptr, "DD_TRACE_ENABLED", sizeof("DD_TRACE_ENABLED") - 1) != 0)) { ddog_ConfigurationOrigin origin = DDOG_CONFIGURATION_ORIGIN_ENV_VAR; switch (cfg->name_index) { case ZAI_CONFIG_ORIGIN_DEFAULT: diff --git a/loader/tests/functional/test_configuration_telemetry.php b/loader/tests/functional/test_configuration_telemetry.php index 565e667a9c..6bb249752e 100644 --- a/loader/tests/functional/test_configuration_telemetry.php +++ b/loader/tests/functional/test_configuration_telemetry.php @@ -11,6 +11,8 @@ 'DD_INJECT_FORCE=true', 'DD_INJECTION_ENABLED=tracer', // Normally set by the injector 'DD_SERVICE=loader', + 'DD_API_KEY=SENTINEL_DD_API_KEY', + 'DD_VERSION=1.2.3-loader-test', ]); assertMatchesFormat($output, '%A"loaded_by_ssi":true%s%A'); @@ -22,3 +24,9 @@ assertContains($content, '{"name":"instrumentation_source","value":"ssi","origin":"default","config_id":null,"seq_id":null}'); assertContains($content, '{"name":"ssi_injection_enabled","value":"tracer","origin":"env_var","config_id":null,"seq_id":null}'); assertContains($content, '{"name":"ssi_forced_injection_enabled","value":"True","origin":"env_var","config_id":null,"seq_id":null}'); + +assertNotContains($content, 'SENTINEL_DD_API_KEY'); +assertNotContains($content, '"name":"DD_API_KEY"'); +assertNotContains($content, '"name":"DD_TRACE_ENABLED"'); + +assertContains($content, '{"name":"DD_VERSION","value":"1.2.3-loader-test","origin":"env_var","config_id":null,"seq_id":null}'); diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index c0ac06c138..e8dfeae807 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -12,7 +12,8 @@ { "implementation": "C", "type": "string", - "default": "" + "default": "", + "sensitive": true } ], "DD_API_SECURITY_ENABLED": [ @@ -2721,7 +2722,8 @@ { "implementation": "A", "type": "map", - "default": "" + "default": "", + "sensitive": true } ], "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT": [ @@ -2735,7 +2737,8 @@ { "implementation": "B", "type": "map", - "default": null + "default": null, + "sensitive": true } ], "OTEL_EXPORTER_OTLP_LOGS_PROTOCOL": [ @@ -2763,7 +2766,8 @@ { "implementation": "A", "type": "map", - "default": null + "default": null, + "sensitive": true } ], "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL": [ diff --git a/profiling/src/bindings/mod.rs b/profiling/src/bindings/mod.rs index 220be2cd12..807ef30a79 100644 --- a/profiling/src/bindings/mod.rs +++ b/profiling/src/bindings/mod.rs @@ -701,6 +701,7 @@ pub struct ZaiConfigEntry { pub parser: zai_custom_parse, pub displayer: zai_custom_display, pub env_config_fallback: zai_env_config_fallback, + pub sensitive: bool, } #[repr(C)] @@ -717,6 +718,7 @@ pub struct ZaiConfigMemoizedEntry { pub parser: zai_custom_parse, pub displayer: zai_custom_display, pub env_config_fallback: zai_env_config_fallback, + pub sensitive: bool, pub original_on_modify: Option< unsafe extern "C" fn( entry: *mut zend_ini_entry, diff --git a/profiling/src/config.rs b/profiling/src/config.rs index 6485554d27..44cb7b3927 100644 --- a/profiling/src/config.rs +++ b/profiling/src/config.rs @@ -1021,6 +1021,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_profiling_enabled), displayer: Some(display_profiling_enabled), env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingExperimentalFeaturesEnabled), @@ -1033,6 +1034,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingEndpointCollectionEnabled), @@ -1045,6 +1047,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingExperimentalCpuTimeEnabled), @@ -1057,6 +1060,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingAllocationEnabled), @@ -1069,6 +1073,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingAllocationSamplingDistance), @@ -1081,6 +1086,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_sampling_distance_filter), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingExperimentalHeapLiveEnabled), @@ -1093,6 +1099,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingTimelineEnabled), @@ -1105,6 +1112,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingExceptionEnabled), @@ -1117,6 +1125,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingExceptionMessageEnabled), @@ -1129,6 +1138,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingExceptionSamplingDistance), @@ -1141,6 +1151,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_sampling_distance_filter), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingExperimentalIOEnabled), @@ -1153,6 +1164,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingLogLevel), @@ -1165,6 +1177,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_level_filter), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(ProfilingOutputPprof), @@ -1177,6 +1190,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, // At the moment, wall-time cannot be fully disabled. This only // controls automatic collection (manual collection is still @@ -1192,6 +1206,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(AgentHost), @@ -1204,6 +1219,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(Env), @@ -1216,6 +1232,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(Service), @@ -1228,6 +1245,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(Tags), @@ -1244,6 +1262,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: None, displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(TraceAgentPort), @@ -1256,6 +1275,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(TraceAgentUrl), @@ -1268,6 +1288,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(Version), @@ -1280,6 +1301,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(GitCommitSha), @@ -1292,6 +1314,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, zai_config_entry { id: transmute::(GitRepositoryUrl), @@ -1304,6 +1327,7 @@ pub(crate) fn minit(module_number: libc::c_int) { parser: Some(parse_utf8_string), displayer: None, env_config_fallback: None, + sensitive: false, }, ] }; diff --git a/src/DDTrace/OpenTelemetry/Configuration.php b/src/DDTrace/OpenTelemetry/Configuration.php index 26f0d8ae9e..5b3537eb47 100644 --- a/src/DDTrace/OpenTelemetry/Configuration.php +++ b/src/DDTrace/OpenTelemetry/Configuration.php @@ -23,19 +23,23 @@ 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', 'OTEL_EXPORTER_OTLP_LOGS_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', - 'OTEL_EXPORTER_OTLP_METRICS_HEADERS', - 'OTEL_EXPORTER_OTLP_LOGS_HEADERS', - 'OTEL_EXPORTER_OTLP_HEADERS', 'OTEL_EXPORTER_OTLP_METRICS_TIMEOUT', 'OTEL_EXPORTER_OTLP_LOGS_TIMEOUT', 'OTEL_EXPORTER_OTLP_TIMEOUT', 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE', ]; +const OTEL_SENSITIVE_CONFIGURATIONS = [ + 'OTEL_EXPORTER_OTLP_HEADERS', + 'OTEL_EXPORTER_OTLP_METRICS_HEADERS', + 'OTEL_EXPORTER_OTLP_LOGS_HEADERS', +]; + // Helper function to track config access function track_otel_config_if_whitelisted(string $name, $value): void { - if (in_array($name, OTEL_CONFIG_WHITELIST, true)) { + if (in_array($name, OTEL_CONFIG_WHITELIST, true) + && !in_array($name, OTEL_SENSITIVE_CONFIGURATIONS, true)) { // Convert value to string for telemetry if (is_bool($value)) { $value_str = $value ? 'true' : 'false'; diff --git a/tests/ext/telemetry/sensitive_config.phpt b/tests/ext/telemetry/sensitive_config.phpt new file mode 100644 index 0000000000..26cd7101ee --- /dev/null +++ b/tests/ext/telemetry/sensitive_config.phpt @@ -0,0 +1,133 @@ +--TEST-- +Sensitive configurations are excluded from configuration telemetry +--SKIPIF-- + +--ENV-- +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_AUTOFINISH_SPANS=1 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=1 +DD_AGENT_HOST= +DD_AUTOLOAD_NO_COMPILE= +DD_TRACE_GIT_METADATA_ENABLED=0 +DD_API_KEY=SENTINEL_DD_API_KEY +DD_VERSION=1.2.3-sensitive-test +--INI-- +datadog.trace.agent_url="file://{PWD}/sensitive-config-telemetry.out" +--FILE-- + +--EXPECTF-- +Included +sentinel values in telemetry: array(0) { +} +DD_API_KEY reported: bool(false) +DD_TRACE_ENABLED reported: bool(false) +OTEL_EXPORTER_OTLP_HEADERS reported: bool(false) +OTEL_EXPORTER_OTLP_METRICS_HEADERS reported: bool(false) +OTEL_EXPORTER_OTLP_LOGS_HEADERS reported: bool(false) +OTEL_EXPORTER_OTLP_TRACES_HEADERS reported: bool(false) +OTEL_EXPORTER_OTLP_ENDPOINT reported: bool(true) +DD_VERSION reported: bool(true) +--CLEAN-- +&2 +SELF_TEST=0 +if [[ $# -gt 1 ]]; then + echo "Usage: $0 [--print-input-files|--self-test]" >&2 exit 1 fi +case "${1:-}" in + --print-input-files) + printf '%s\n' "${CONFIG_GENERATION_INPUT_FILES[@]}" + exit 0 + ;; + --self-test) + SELF_TEST=1 + ;; + "") + ;; + *) + echo "Usage: $0 [--print-input-files|--self-test]" >&2 + exit 1 + ;; +esac # Maps C config type to JSON schema type. PHP_CODE_FILE=$(mktemp "${TMPDIR:-/tmp}/ddtrace-supported-configurations.XXXXXX.php") @@ -114,10 +127,129 @@ function normalize_supported_entries($entries, $canonical) { return $normalized; } +$SENSITIVE_CONFIGURATIONS = []; + +function mask_c_non_code($source) { + $source = str_replace(["\\\r\n", "\\\n", "\\\r"], '', $source); + $quote = null; + $lineComment = false; + $blockComment = false; + $escaped = false; + $length = strlen($source); + for ($i = 0; $i < $length; $i++) { + $char = $source[$i]; + $next = $i + 1 < $length ? $source[$i + 1] : ''; + if ($lineComment) { + if ($char === "\n") { + $lineComment = false; + } else { + $source[$i] = ' '; + } + continue; + } + if ($blockComment) { + if ($char === '*' && $next === '/') { + $source[$i] = ' '; + $source[$i + 1] = ' '; + $blockComment = false; + $i++; + } elseif ($char !== "\n") { + $source[$i] = ' '; + } + continue; + } + if ($quote !== null) { + if ($escaped) { + $escaped = false; + } elseif ($char === '\\') { + $escaped = true; + } elseif ($char === $quote) { + $quote = null; + } + if ($char !== "\n") { + $source[$i] = ' '; + } + continue; + } + if ($char === '/' && $next === '/') { + $source[$i] = ' '; + $source[$i + 1] = ' '; + $lineComment = true; + $i++; + continue; + } + if ($char === '/' && $next === '*') { + $source[$i] = ' '; + $source[$i + 1] = ' '; + $blockComment = true; + $i++; + continue; + } + if ($char === '"' || $char === "'") { + $quote = $char; + $source[$i] = ' '; + } + } + return $source; +} + +function config_macro_arglist($source, $openParen) { + $depth = 0; + $length = strlen($source); + for ($i = $openParen; $i < $length; $i++) { + if ($source[$i] === '(') { + $depth++; + } elseif ($source[$i] === ')' && --$depth === 0) { + return substr($source, $openParen + 1, $i - $openParen - 1); + } + } + return substr($source, $openParen + 1); +} + +function extract_sensitive_config_names_from_source($source) { + $sensitive = []; + $source = mask_c_non_code($source); + preg_match_all('/\b(?:CONFIG|SYSCFG|CALIAS)\s*\(/', $source, $matches, PREG_OFFSET_CAPTURE); + foreach ($matches[0] as [$macro, $offset]) { + $openParen = $offset + strrpos($macro, '('); + $argList = config_macro_arglist($source, $openParen); + if (preg_match('/^\s*[^,]+,\s*([A-Z][A-Z0-9_]+)/', $argList, $nameMatch) + && preg_match('/\.sensitive\s*=\s*true\b/', $argList)) { + $sensitive[$nameMatch[1]] = true; + } + } + return $sensitive; +} + +function extract_sensitive_config_names($paths) { + $sensitive = []; + foreach ($paths as $path) { + if (!file_exists($path)) { + continue; + } + $source = file_get_contents($path); + if ($source === false || $source === '') { + continue; + } + foreach (extract_sensitive_config_names_from_source($source) as $name => $_) { + $sensitive[$name] = true; + } + } + return $sensitive; +} + +function mark_sensitive($entry, $name) { + global $SENSITIVE_CONFIGURATIONS; + if (isset($SENSITIVE_CONFIGURATIONS[$name])) { + $entry["sensitive"] = true; + } + return $entry; +} + function add_supported_entry(&$supported, $name, $entry) { // Keep the first-seen source as canonical for duplicate names. if (!isset($supported[$name])) { - $supported[$name] = [$entry]; + $supported[$name] = [mark_sensitive($entry, $name)]; } } @@ -131,7 +263,8 @@ function add_otel_entries(&$supported, $names, $metadata) { // OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) so the published default is the // SDK's rather than the extension's runtime resolution. [$type, $default] = $metadata[$name]; - $supported[$name] = [["implementation" => "A", "type" => $type, "default" => $default]]; + $entry = ["implementation" => "A", "type" => $type, "default" => $default]; + $supported[$name] = [mark_sensitive($entry, $name)]; } else { // Not in the table: an OTEL var resolved by the SDK that we don't model. add_supported_entry($supported, $name, ["implementation" => "A", "type" => "string", "default" => ""]); @@ -139,6 +272,121 @@ function add_otel_entries(&$supported, $names, $metadata) { } } +function php_token_is_ignored($token) { + return is_array($token) && in_array($token[0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], true); +} + +function php_next_significant_token($tokens, $index, $direction) { + $tokenCount = count($tokens); + for ($i = $index + $direction; $i >= 0 && $i < $tokenCount; $i += $direction) { + if (!php_token_is_ignored($tokens[$i])) { + return $i; + } + } + return null; +} + +function extract_otel_config_names($source, $constant) { + $tokens = token_get_all($source); + $tokenCount = count($tokens); + for ($i = 0; $i < $tokenCount; $i++) { + if (!is_array($tokens[$i]) || $tokens[$i][0] !== T_CONST) { + continue; + } + $nameIndex = php_next_significant_token($tokens, $i, 1); + if ($nameIndex === null || !is_array($tokens[$nameIndex]) + || $tokens[$nameIndex][0] !== T_STRING || $tokens[$nameIndex][1] !== $constant) { + continue; + } + $equalsIndex = php_next_significant_token($tokens, $nameIndex, 1); + if ($equalsIndex === null || $tokens[$equalsIndex] !== '=') { + continue; + } + $arrayIndex = php_next_significant_token($tokens, $equalsIndex, 1); + if ($arrayIndex === null || $tokens[$arrayIndex] !== '[') { + continue; + } + $names = []; + for ($j = $arrayIndex + 1; $j < $tokenCount; $j++) { + $token = $tokens[$j]; + if (php_token_is_ignored($token) || $token === ',') { + continue; + } + if ($token === ']') { + return $names; + } + if (is_array($token) && $token[0] === T_CONSTANT_ENCAPSED_STRING) { + $nextIndex = php_next_significant_token($tokens, $j, 1); + if ($nextIndex !== null && ($tokens[$nextIndex] === ',' || $tokens[$nextIndex] === ']')) { + $value = eval('return ' . $token[1] . ';'); + if (preg_match('/^OTEL_[A-Z0-9_]+$/D', $value)) { + $names[] = $value; + } + continue; + } + } + throw new RuntimeException("Unsupported entry in $constant; use direct string literals"); + } + throw new RuntimeException("Unterminated array for $constant"); + } + return []; +} + +if (getenv('DDTRACE_CONFIG_GENERATOR_SELF_TEST')) { + $cSource = <<<'C' +// CONFIG(STRING, DD_FALSE_LINE, "", .sensitive = true) \ +CONFIG(STRING, DD_FALSE_SPLICED_LINE, "", .sensitive = true) +/* CONFIG(STRING, DD_FALSE_BLOCK, "", .sensitive = true) */ +const char *false_string = "CONFIG(STRING, DD_FALSE_STRING, \"\", .sensitive = true)"; +CONFIG(CUSTOM(MAP), DD_REAL_NESTED, "escaped quote: \" and )", .sensitive = true) +CONFIG(STRING, DD_REAL_EVEN_ESCAPE, "escaped slash: \\", .sensitive = true) +C; + $sensitive = extract_sensitive_config_names_from_source($cSource); + $expectedSensitive = ['DD_REAL_EVEN_ESCAPE', 'DD_REAL_NESTED']; + $actualSensitive = array_keys($sensitive); + sort($actualSensitive); + if ($actualSensitive !== $expectedSensitive) { + throw new RuntimeException('C sensitive configuration parser self-test failed: ' . json_encode($actualSensitive)); + } + + $phpSource = <<<'PHP' + false", + "7 => 'OTEL_KEYED_VALUE'", + "'OTEL_CONCAT' . '_VALUE'", + "('OTEL_PAREN')", + "OTEL_CONSTANT_REFERENCE", + ]; + foreach ($unsupportedEntries as $entry) { + $unsupportedSource = "../ext/version.h #ifndef PHP_DDTRACE_VERSION #define PHP_DDTRACE_VERSION "$(cat "../VERSION")" diff --git a/tracer/functions.c b/tracer/functions.c index c5a6936220..247d974bf6 100644 --- a/tracer/functions.c +++ b/tracer/functions.c @@ -1957,6 +1957,21 @@ PHP_FUNCTION(dd_trace_coms_trigger_writer_flush) { #define FUNCTION_NAME_MATCHES(function) zend_string_equals_literal(function_val, function) +static bool ddtrace_otel_config_is_reportable(zend_string *name) { + static const char otel_prefix[] = "OTEL_"; + static const char otlp_prefix[] = "OTEL_EXPORTER_OTLP"; + static const char headers_suffix[] = "_HEADERS"; + size_t name_len = ZSTR_LEN(name); + if (name_len < sizeof(otel_prefix) - 1 + || memcmp(ZSTR_VAL(name), otel_prefix, sizeof(otel_prefix) - 1) != 0) { + return false; + } + return name_len < sizeof(otlp_prefix) + sizeof(headers_suffix) - 2 + || memcmp(ZSTR_VAL(name), otlp_prefix, sizeof(otlp_prefix) - 1) != 0 + || memcmp(ZSTR_VAL(name) + name_len - sizeof(headers_suffix) + 1, + headers_suffix, sizeof(headers_suffix) - 1) != 0; +} + PHP_FUNCTION(dd_trace_internal_fn) { UNUSED(execute_data); zval ***params = NULL; @@ -2002,7 +2017,7 @@ PHP_FUNCTION(dd_trace_internal_fn) { } else if (params_count == 2 && FUNCTION_NAME_MATCHES("track_otel_config")) { zval *config_name = ZVAL_VARARG_PARAM(params, 0); zval *config_value = ZVAL_VARARG_PARAM(params, 1); - if (Z_TYPE_P(config_name) == IS_STRING) { + if (Z_TYPE_P(config_name) == IS_STRING && ddtrace_otel_config_is_reportable(Z_STR_P(config_name))) { // Store the config name and value in the HashTable zval value_copy; ZVAL_COPY(&value_copy, config_value); diff --git a/zend_abstract_interface/config/config.c b/zend_abstract_interface/config/config.c index 6fdabfe907..95b763ad15 100644 --- a/zend_abstract_interface/config/config.c +++ b/zend_abstract_interface/config/config.c @@ -162,6 +162,7 @@ static zai_config_memoized_entry *zai_config_memoize_entry(zai_config_entry *ent memoized->original_on_modify = NULL; memoized->env_config_fallback = entry->env_config_fallback; memoized->ini_change = entry->ini_change; + memoized->sensitive = entry->sensitive; return memoized; } diff --git a/zend_abstract_interface/config/config.h b/zend_abstract_interface/config/config.h index 3a9c8d34f5..41ea02e2fb 100644 --- a/zend_abstract_interface/config/config.h +++ b/zend_abstract_interface/config/config.h @@ -45,6 +45,7 @@ struct zai_config_entry_s { zai_custom_parse parser; zai_custom_display displayer; zai_env_config_fallback env_config_fallback; + bool sensitive; }; struct zai_config_name_s { @@ -76,6 +77,7 @@ struct zai_config_memoized_entry_s { zai_custom_parse parser; zai_custom_display displayer; zai_env_config_fallback env_config_fallback; + bool sensitive; ZEND_INI_MH((*original_on_modify)); // when some other extension has registered that INI };