From 0926c77c3b8e0d41dd79774f89cd5f3dbbf2a03c Mon Sep 17 00:00:00 2001 From: Alejandro Estringana Ruiz Date: Mon, 16 Dec 2024 11:59:53 +0100 Subject: [PATCH] ASM Standalone (#2903) There is a new configuration called `DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED`(default: `false`) which disable APM. When `DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED` is enabled, traces will be only sent under the following conditions: - There is an ASM event - One APM trace will be sent as a heartbeat at least once a minute in the absence of ASM events. This is done to keep the service alive on the backend and avoid it gets into degraded mode. Since the tracing engine is coupled to the tracer extension, it will be required that `DD_TRACE_ENABLED` is set to `true`. However `DD_TRACE_ENABLED` being enabled does not mean APM is. --- appsec/recommended.json | 512 ++++++++++++------ appsec/src/extension/commands_helpers.c | 1 + appsec/src/extension/configuration.h | 1 + appsec/src/extension/ddtrace.c | 37 ++ appsec/src/extension/ddtrace.h | 4 + appsec/src/extension/tags.c | 25 +- .../client_init_record_span_tags.phpt | 6 +- appsec/tests/extension/inc/mock_helper.php | 16 + .../rinit_asm_events_propagate_tags.phpt | 66 +++ .../extension/rinit_record_span_tags.phpt | 6 +- config.m4 | 2 + config.w32 | 2 + ddtrace.sym | 2 + ext/asm_event.c | 36 ++ ext/asm_event.h | 11 + ext/auto_flush.c | 49 +- ext/coms.c | 1 + ext/configuration.h | 1 + ext/ddtrace.c | 6 + ext/ddtrace.h | 2 + ext/ddtrace.stub.php | 4 + ext/ddtrace_arginfo.h | 6 +- ext/handlers_http.h | 10 + ext/limiter/limiter.c | 3 + ext/priority_sampling/priority_sampling.c | 50 +- ext/priority_sampling/priority_sampling.h | 1 + ext/serializer.c | 16 +- ext/standalone_limiter.c | 61 +++ ext/standalone_limiter.h | 11 + .../tracer_tag_propagation.c | 57 +- .../tracer_tag_propagation.h | 5 + .../agent_sampling-standalone-asm_01.phpt | 53 ++ .../agent_sampling-standalone-asm_02.phpt | 55 ++ .../agent_sampling-standalone-asm_03.phpt | 58 ++ .../distributed_trace_asm_standalone_01.phpt | 105 ++++ .../distributed_trace_asm_standalone_02.phpt | 101 ++++ ...uted_tracing_curl_propagate_asm_event.phpt | 40 ++ .../003-limiter-with-asm-standalone.phpt | 43 ++ .../ext/priority_sampling/asm-standalone.phpt | 18 + 39 files changed, 1278 insertions(+), 205 deletions(-) create mode 100644 appsec/tests/extension/rinit_asm_events_propagate_tags.phpt create mode 100644 ext/asm_event.c create mode 100644 ext/asm_event.h create mode 100644 ext/standalone_limiter.c create mode 100644 ext/standalone_limiter.h create mode 100644 tests/ext/background-sender/agent_sampling-standalone-asm_01.phpt create mode 100644 tests/ext/background-sender/agent_sampling-standalone-asm_02.phpt create mode 100644 tests/ext/background-sender/agent_sampling-standalone-asm_03.phpt create mode 100644 tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt create mode 100644 tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt create mode 100644 tests/ext/integrations/curl/distributed_tracing_curl_propagate_asm_event.phpt create mode 100644 tests/ext/limiter/003-limiter-with-asm-standalone.phpt create mode 100644 tests/ext/priority_sampling/asm-standalone.phpt diff --git a/appsec/recommended.json b/appsec/recommended.json index 01156e6f20..1e2263ad9f 100644 --- a/appsec/recommended.json +++ b/appsec/recommended.json @@ -1,7 +1,7 @@ { "version": "2.2", "metadata": { - "rules_version": "1.13.2" + "rules_version": "1.13.3" }, "rules": [ { @@ -9,7 +9,8 @@ "name": "Block IP Addresses", "tags": { "type": "block_ip", - "category": "security_response" + "category": "security_response", + "module": "network-acl" }, "conditions": [ { @@ -34,7 +35,8 @@ "name": "Block User Addresses", "tags": { "type": "block_user", - "category": "security_response" + "category": "security_response", + "module": "authentication-acl" }, "conditions": [ { @@ -64,7 +66,8 @@ "tool_name": "Acunetix", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -98,7 +101,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -162,7 +166,8 @@ "category": "attack_attempt", "cwe": "176", "capec": "1000/255/153/267/71", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -191,7 +196,8 @@ "crs_id": "921110", "category": "attack_attempt", "cwe": "444", - "capec": "1000/210/272/220/33" + "capec": "1000/210/272/220/33", + "module": "waf" }, "conditions": [ { @@ -228,7 +234,8 @@ "crs_id": "921160", "category": "attack_attempt", "cwe": "113", - "capec": "1000/210/272/220/105" + "capec": "1000/210/272/220/105", + "module": "waf" }, "conditions": [ { @@ -263,7 +270,8 @@ "category": "attack_attempt", "cwe": "22", "capec": "1000/255/153/126", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -297,7 +305,8 @@ "category": "attack_attempt", "cwe": "22", "capec": "1000/255/153/126", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -1803,7 +1812,8 @@ "category": "attack_attempt", "cwe": "98", "capec": "1000/152/175/253/193", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -1831,7 +1841,8 @@ "crs_id": "931120", "category": "attack_attempt", "cwe": "98", - "capec": "1000/152/175/253/193" + "capec": "1000/152/175/253/193", + "module": "waf" }, "conditions": [ { @@ -1876,7 +1887,8 @@ "category": "attack_attempt", "cwe": "77", "capec": "1000/152/248/88", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2388,7 +2400,8 @@ "category": "attack_attempt", "cwe": "77", "capec": "1000/152/248/88", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2436,7 +2449,8 @@ "category": "attack_attempt", "cwe": "706", "capec": "1000/225/122/17/177", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2500,7 +2514,8 @@ "category": "attack_attempt", "cwe": "434", "capec": "1000/225/122/17/650", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2553,7 +2568,8 @@ "category": "attack_attempt", "cwe": "94", "capec": "1000/225/122/17/650", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2620,7 +2636,8 @@ "crs_id": "933131", "category": "attack_attempt", "cwe": "94", - "capec": "1000/225/122/17/650" + "capec": "1000/225/122/17/650", + "module": "waf" }, "conditions": [ { @@ -2665,7 +2682,8 @@ "category": "attack_attempt", "cwe": "94", "capec": "1000/225/122/17/650", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2709,7 +2727,8 @@ "category": "attack_attempt", "cwe": "94", "capec": "1000/225/122/17/650", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2799,7 +2818,8 @@ "crs_id": "933160", "category": "attack_attempt", "cwe": "94", - "capec": "1000/225/122/17/650" + "capec": "1000/225/122/17/650", + "module": "waf" }, "conditions": [ { @@ -2824,7 +2844,7 @@ "address": "graphql.server.resolver" } ], - "regex": "\\b(?:s(?:e(?:t(?:_(?:e(?:xception|rror)_handler|magic_quotes_runtime|include_path)|defaultstub)|ssion_s(?:et_save_handler|tart))|qlite_(?:(?:(?:unbuffered|single|array)_)?query|create_(?:aggregate|function)|p?open|exec)|tr(?:eam_(?:context_create|socket_client)|ipc?slashes|rev)|implexml_load_(?:string|file)|ocket_c(?:onnect|reate)|h(?:ow_sourc|a1_fil)e|pl_autoload_register|ystem)|p(?:r(?:eg_(?:replace(?:_callback(?:_array)?)?|match(?:_all)?|split)|oc_(?:(?:terminat|clos|nic)e|get_status|open)|int_r)|o(?:six_(?:get(?:(?:e[gu]|g)id|login|pwnam)|mk(?:fifo|nod)|ttyname|kill)|pen)|hp(?:_(?:strip_whitespac|unam)e|version|info)|g_(?:(?:execut|prepar)e|connect|query)|a(?:rse_(?:ini_file|str)|ssthru)|utenv)|r(?:unkit_(?:function_(?:re(?:defin|nam)e|copy|add)|method_(?:re(?:defin|nam)e|copy|add)|constant_(?:redefine|add))|e(?:(?:gister_(?:shutdown|tick)|name)_function|ad(?:(?:gz)?file|_exif_data|dir))|awurl(?:de|en)code)|i(?:mage(?:createfrom(?:(?:jpe|pn)g|x[bp]m|wbmp|gif)|(?:jpe|pn)g|g(?:d2?|if)|2?wbmp|xbm)|s_(?:(?:(?:execut|write?|read)ab|fi)le|dir)|ni_(?:get(?:_all)?|set)|terator_apply|ptcembed)|g(?:et(?:_(?:c(?:urrent_use|fg_va)r|meta_tags)|my(?:[gpu]id|inode)|(?:lastmo|cw)d|imagesize|env)|z(?:(?:(?:defla|wri)t|encod|fil)e|compress|open|read)|lob)|a(?:rray_(?:u(?:intersect(?:_u?assoc)?|diff(?:_u?assoc)?)|intersect_u(?:assoc|key)|diff_u(?:assoc|key)|filter|reduce|map)|ssert(?:_options)?|tob)|h(?:tml(?:specialchars(?:_decode)?|_entity_decode|entities)|(?:ash(?:_(?:update|hmac))?|ighlight)_file|e(?:ader_register_callback|x2bin))|f(?:i(?:le(?:(?:[acm]tim|inod)e|(?:_exist|perm)s|group)?|nfo_open)|tp_(?:nb_(?:ge|pu)|connec|ge|pu)t|(?:unction_exis|pu)ts|write|open)|o(?:b_(?:get_(?:c(?:ontents|lean)|flush)|end_(?:clean|flush)|clean|flush|start)|dbc_(?:result(?:_all)?|exec(?:ute)?|connect)|pendir)|m(?:b_(?:ereg(?:_(?:replace(?:_callback)?|match)|i(?:_replace)?)?|parse_str)|(?:ove_uploaded|d5)_file|ethod_exists|ysql_query|kdir)|e(?:x(?:if_(?:t(?:humbnail|agname)|imagetype|read_data)|ec)|scapeshell(?:arg|cmd)|rror_reporting|val)|c(?:url_(?:file_create|exec|init)|onvert_uuencode|reate_function|hr)|u(?:n(?:serialize|pack)|rl(?:de|en)code|[ak]?sort)|b(?:(?:son_(?:de|en)|ase64_en)code|zopen|toa)|(?:json_(?:de|en)cod|debug_backtrac|tmpfil)e|var_dump)(?:\\s|/\\*.*\\*/|//.*|#.*|\\\"|')*\\((?:(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:\\$\\w+|[A-Z\\d]\\w*|\\w+\\(.*\\)|\\\\?\"(?:[^\"]|\\\\\"|\"\"|\"\\+\")*\\\\?\"|\\\\?'(?:[^']|''|'\\+')*\\\\?')(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:(?:::|\\.|->)(?:\\s|/\\*.*\\*/|//.*|#.*)*\\w+(?:\\(.*\\))?)?,)*(?:(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:\\$\\w+|[A-Z\\d]\\w*|\\w+\\(.*\\)|\\\\?\"(?:[^\"]|\\\\\"|\"\"|\"\\+\")*\\\\?\"|\\\\?'(?:[^']|''|'\\+')*\\\\?')(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:(?:::|\\.|->)(?:\\s|/\\*.*\\*/|//.*|#.*)*\\w+(?:\\(.*\\))?)?)?\\)", + "regex": "\\b(?:s(?:e(?:t(?:_(?:e(?:xception|rror)_handler|magic_quotes_runtime|include_path)|defaultstub)|ssion_s(?:et_save_handler|tart))|qlite_(?:(?:(?:unbuffered|single|array)_)?query|create_(?:aggregate|function)|p?open|exec)|tr(?:eam_(?:context_create|socket_client)|ipc?slashes|rev)|implexml_load_(?:string|file)|ocket_c(?:onnect|reate)|h(?:ow_sourc|a1_fil)e|pl_autoload_register|ystem)|p(?:r(?:eg_(?:replace(?:_callback(?:_array)?)?|match(?:_all)?|split)|oc_(?:(?:terminat|clos|nic)e|get_status|open)|int_r)|o(?:six_(?:get(?:(?:e[gu]|g)id|login|pwnam)|mk(?:fifo|nod)|ttyname|kill)|pen)|hp(?:_(?:strip_whitespac|unam)e|version|info)|g_(?:(?:execut|prepar)e|connect|query)|a(?:rse_(?:ini_file|str)|ssthru)|utenv)|r(?:unkit_(?:function_(?:re(?:defin|nam)e|copy|add)|method_(?:re(?:defin|nam)e|copy|add)|constant_(?:redefine|add))|e(?:(?:gister_(?:shutdown|tick)|name)_function|ad(?:(?:gz)?file|_exif_data|dir))|awurl(?:de|en)code)|i(?:mage(?:createfrom(?:(?:jpe|pn)g|x[bp]m|wbmp|gif)|(?:jpe|pn)g|g(?:d2?|if)|2?wbmp|xbm)|s_(?:(?:(?:execut|write?|read)ab|fi)le|dir)|ni_(?:get(?:_all)?|set)|terator_apply|ptcembed)|g(?:et(?:_(?:c(?:urrent_use|fg_va)r|meta_tags)|my(?:[gpu]id|inode)|(?:lastmo|cw)d|imagesize|env)|z(?:(?:(?:defla|wri)t|encod|fil)e|compress|open|read)|lob)|a(?:rray_(?:u(?:intersect(?:_u?assoc)?|diff(?:_u?assoc)?)|intersect_u(?:assoc|key)|diff_u(?:assoc|key)|filter|reduce|map)|ssert(?:_options)?|tob)|h(?:tml(?:specialchars(?:_decode)?|_entity_decode|entities)|(?:ash(?:_(?:update|hmac))?|ighlight)_file|e(?:ader_register_callback|x2bin))|f(?:i(?:le(?:(?:[acm]tim|inod)e|(?:_exist|perm)s|group)?|nfo_open)|tp_(?:nb_(?:ge|pu)|connec|ge|pu)t|(?:unction_exis|pu)ts|write|open)|o(?:b_(?:get_(?:c(?:ontents|lean)|flush)|end_(?:clean|flush)|clean|flush|start)|dbc_(?:result(?:_all)?|exec(?:ute)?|connect)|pendir)|m(?:b_(?:ereg(?:_(?:replace(?:_callback)?|match)|i(?:_replace)?)?|parse_str)|(?:ove_uploaded|d5)_file|ethod_exists|ysql_query|kdir)|e(?:x(?:if_(?:t(?:humbnail|agname)|imagetype|read_data)|ec)|scapeshell(?:arg|cmd)|rror_reporting|val)|c(?:url_(?:file_create|exec|init)|onvert_uuencode|reate_function|hr)|u(?:n(?:serialize|pack)|rl(?:de|en)code|[ak]?sort)|b(?:(?:son_(?:de|en)|ase64_en)code|zopen|toa)|(?:json_(?:de|en)cod|debug_backtrac|tmpfil)e|var_dump)(?:\\s|/\\*.*\\*/|//.*|#.*|\\\"|')*\\((?:(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:\\$\\w+|[A-Z\\d]\\w*|\\w+\\(.*\\)|\\\\?\"(?:[^\"]|\\\\\"|\"\"|\"\\+\")*\\\\?\"|\\\\?'(?:[^']|''|'\\+')*\\\\?')(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:(?:::|\\.|->)(?:\\s|/\\*.*\\*/|//.*|#.*)*\\w+(?:\\(.*\\))?)?,)*(?:(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:\\$\\w+|[A-Z\\d]\\w*|\\w+\\(.*\\)|\\\\?\"(?:[^\"]|\\\\\"|\"\"|\"\\+\")*\\\\?\"|\\\\?'(?:[^']|''|'\\+')*\\\\?')(?:\\s|/\\*.*\\*/|//.*|#.*)*(?:(?:::|\\.|->)(?:\\s|/\\*.*\\*/|//.*|#.*)*\\w+(?:\\(.*\\))?)?)?\\)\\s*(?:[;\\.)}\\]|\\\\]|\\?>|%>|$)", "options": { "case_sensitive": true, "min_length": 5 @@ -2844,7 +2864,8 @@ "category": "attack_attempt", "cwe": "502", "capec": "1000/152/586", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -2891,7 +2912,8 @@ "crs_id": "933200", "category": "attack_attempt", "cwe": "502", - "capec": "1000/152/586" + "capec": "1000/152/586", + "module": "waf" }, "conditions": [ { @@ -2937,7 +2959,8 @@ "crs_id": "934100", "category": "attack_attempt", "cwe": "94", - "capec": "1000/152/242" + "capec": "1000/152/242", + "module": "waf" }, "conditions": [ { @@ -2982,7 +3005,8 @@ "category": "attack_attempt", "confidence": "1", "cwe": "94", - "capec": "1000/152/242" + "capec": "1000/152/242", + "module": "waf" }, "conditions": [ { @@ -3024,7 +3048,8 @@ "category": "attack_attempt", "cwe": "80", "capec": "1000/152/242/63/591", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3081,7 +3106,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3140,7 +3166,8 @@ "category": "attack_attempt", "cwe": "84", "capec": "1000/152/242/63/591/244", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3199,7 +3226,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3257,7 +3285,8 @@ "crs_id": "941180", "category": "attack_attempt", "cwe": "79", - "capec": "1000/152/242/63/591" + "capec": "1000/152/242/63/591", + "module": "waf" }, "conditions": [ { @@ -3311,7 +3340,8 @@ "category": "attack_attempt", "cwe": "80", "capec": "1000/152/242/63/591", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3358,7 +3388,8 @@ "category": "attack_attempt", "cwe": "80", "capec": "1000/152/242/63/591", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3405,7 +3436,8 @@ "category": "attack_attempt", "cwe": "80", "capec": "1000/152/242/63/591", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3452,7 +3484,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3498,7 +3531,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3545,7 +3579,8 @@ "crs_id": "941270", "category": "attack_attempt", "cwe": "83", - "capec": "1000/152/242/63/591/243" + "capec": "1000/152/242/63/591/243", + "module": "waf" }, "conditions": [ { @@ -3588,7 +3623,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3634,7 +3670,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3680,7 +3717,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3726,7 +3764,8 @@ "category": "attack_attempt", "cwe": "87", "capec": "1000/152/242/63/591/199", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3770,7 +3809,8 @@ "crs_id": "941360", "category": "attack_attempt", "cwe": "87", - "capec": "1000/152/242/63/591/199" + "capec": "1000/152/242/63/591/199", + "module": "waf" }, "conditions": [ { @@ -3815,7 +3855,8 @@ "category": "attack_attempt", "confidence": "1", "cwe": "79", - "capec": "1000/152/242/63/591" + "capec": "1000/152/242/63/591", + "module": "waf" }, "conditions": [ { @@ -3859,7 +3900,8 @@ "crs_id": "942100", "category": "attack_attempt", "cwe": "89", - "capec": "1000/152/248/66" + "capec": "1000/152/248/66", + "module": "waf" }, "conditions": [ { @@ -3898,7 +3940,8 @@ "category": "attack_attempt", "cwe": "89", "capec": "1000/152/248/66/7", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3943,7 +3986,8 @@ "category": "attack_attempt", "cwe": "89", "capec": "1000/152/248/66/7", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -3986,7 +4030,8 @@ "crs_id": "942250", "category": "attack_attempt", "cwe": "89", - "capec": "1000/152/248/66" + "capec": "1000/152/248/66", + "module": "waf" }, "conditions": [ { @@ -4030,7 +4075,8 @@ "crs_id": "942270", "category": "attack_attempt", "cwe": "89", - "capec": "1000/152/248/66" + "capec": "1000/152/248/66", + "module": "waf" }, "conditions": [ { @@ -4074,7 +4120,8 @@ "category": "attack_attempt", "cwe": "89", "capec": "1000/152/248/66/7", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4117,7 +4164,8 @@ "crs_id": "942290", "category": "attack_attempt", "cwe": "943", - "capec": "1000/152/248/676" + "capec": "1000/152/248/676", + "module": "waf" }, "conditions": [ { @@ -4163,7 +4211,8 @@ "crs_id": "942360", "category": "attack_attempt", "cwe": "89", - "capec": "1000/152/248/66/470" + "capec": "1000/152/248/66/470", + "module": "waf" }, "conditions": [ { @@ -4206,7 +4255,8 @@ "crs_id": "942500", "category": "attack_attempt", "cwe": "89", - "capec": "1000/152/248/66" + "capec": "1000/152/248/66", + "module": "waf" }, "conditions": [ { @@ -4251,7 +4301,8 @@ "category": "attack_attempt", "cwe": "384", "capec": "1000/225/21/593/61", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4296,7 +4347,8 @@ "category": "attack_attempt", "cwe": "94", "capec": "1000/152/242", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4344,7 +4396,8 @@ "type": "java_code_injection", "category": "attack_attempt", "cwe": "94", - "capec": "1000/152/242" + "capec": "1000/152/242", + "module": "waf" }, "conditions": [ { @@ -4391,7 +4444,8 @@ "crs_id": "944130", "category": "attack_attempt", "cwe": "94", - "capec": "1000/152/242" + "capec": "1000/152/242", + "module": "waf" }, "conditions": [ { @@ -4529,7 +4583,8 @@ "type": "nosql_injection", "category": "attack_attempt", "cwe": "943", - "capec": "1000/152/248/676" + "capec": "1000/152/248/676", + "module": "waf" }, "conditions": [ { @@ -4573,7 +4628,8 @@ "type": "java_code_injection", "category": "attack_attempt", "cwe": "94", - "capec": "1000/152/242" + "capec": "1000/152/242", + "module": "waf" }, "conditions": [ { @@ -4619,7 +4675,8 @@ "category": "attack_attempt", "cwe": "94", "capec": "1000/152/242", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4695,7 +4752,8 @@ "category": "attack_attempt", "cwe": "1321", "capec": "1000/152/242", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4725,7 +4783,8 @@ "category": "attack_attempt", "cwe": "1321", "capec": "1000/152/242", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4769,7 +4828,8 @@ "category": "attack_attempt", "cwe": "1336", "capec": "1000/152/242/19", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4813,7 +4873,8 @@ "tool_name": "BurpCollaborator", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4857,7 +4918,8 @@ "tool_name": "Qualys", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -4901,7 +4963,8 @@ "tool_name": "Probely", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -4944,7 +5007,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -4987,7 +5051,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5031,7 +5096,8 @@ "tool_name": "Rapid7", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5075,7 +5141,8 @@ "tool_name": "interact.sh", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5119,7 +5186,8 @@ "tool_name": "Netsparker", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5167,7 +5235,8 @@ "tool_name": "WhiteHatSecurity", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5215,7 +5284,8 @@ "tool_name": "Nessus", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5263,7 +5333,8 @@ "tool_name": "Watchtowr", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5311,7 +5382,8 @@ "tool_name": "AppCheckNG", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5358,7 +5430,8 @@ "category": "attack_attempt", "cwe": "287", "capec": "1000/225/115", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5392,7 +5465,8 @@ "category": "attack_attempt", "cwe": "98", "capec": "1000/152/175/253/193", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5436,7 +5510,8 @@ "category": "attack_attempt", "cwe": "77", "capec": "1000/152/248/88", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -5483,7 +5558,8 @@ "category": "attack_attempt", "cwe": "91", "capec": "1000/152/248/250", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5521,7 +5597,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5579,7 +5656,8 @@ "category": "attack_attempt", "cwe": "83", "capec": "1000/152/242/63/591/243", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5866,7 +5944,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5908,7 +5987,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5950,7 +6030,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -5992,7 +6073,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6034,7 +6116,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6059,7 +6142,7 @@ "address": "server.request.uri.raw" } ], - "regex": "\\.(cgi|bat|dll|exe|key|cert|crt|pem|der|pkcs|pkcs|pkcs[0-9]*|nsf|jsa|war|java|class|vb|vba|so|git|svn|hg|cvs)([^a-zA-Z0-9_]|$)", + "regex": "\\.(cgi|bat|dll|exe|key|cert|crt|pem|der|pkcs|pkcs|pkcs[0-9]*|nsf|jsa|war|java|class|vb|vba|so|git|svn|hg|cvs)([?#&/]|$)", "options": { "case_sensitive": false } @@ -6076,7 +6159,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6118,7 +6202,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6160,7 +6245,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6202,7 +6288,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -6276,7 +6363,7 @@ } ] }, - "operator": "lfi_detector" + "operator": "lfi_detector@v2" } ], "transformers": [], @@ -6286,7 +6373,7 @@ }, { "id": "rasp-932-100", - "name": "Command injection exploit", + "name": "Shell command injection exploit", "tags": { "type": "command_injection", "category": "vulnerability_trigger", @@ -6332,6 +6419,54 @@ "stack_trace" ] }, + { + "id": "rasp-932-110", + "name": "OS command injection exploit", + "tags": { + "type": "command_injection", + "category": "vulnerability_trigger", + "cwe": "77", + "capec": "1000/152/248/88", + "confidence": "0", + "module": "rasp" + }, + "conditions": [ + { + "parameters": { + "resource": [ + { + "address": "server.sys.exec.cmd" + } + ], + "params": [ + { + "address": "server.request.query" + }, + { + "address": "server.request.body" + }, + { + "address": "server.request.path_params" + }, + { + "address": "grpc.server.request.message" + }, + { + "address": "graphql.server.all_resolvers" + }, + { + "address": "graphql.server.resolver" + } + ] + }, + "operator": "cmdi_detector" + } + ], + "transformers": [], + "on_match": [ + "stack_trace" + ] + }, { "id": "rasp-934-100", "name": "Server-side request forgery exploit", @@ -6438,7 +6573,8 @@ "category": "attack_attempt", "cwe": "918", "capec": "1000/225/115/664", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6482,7 +6618,8 @@ "type": "js_code_injection", "category": "attack_attempt", "cwe": "94", - "capec": "1000/152/242" + "capec": "1000/152/242", + "module": "waf" }, "conditions": [ { @@ -6527,7 +6664,8 @@ "category": "attack_attempt", "cwe": "78", "capec": "1000/152/248/88", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6570,7 +6708,8 @@ "category": "attack_attempt", "cwe": "78", "capec": "1000/152/248/88", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6615,7 +6754,8 @@ "category": "attack_attempt", "cwe": "78", "capec": "1000/152/248/88", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6658,7 +6798,8 @@ "category": "attack_attempt", "cwe": "918", "capec": "1000/225/115/664", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6701,7 +6842,8 @@ "category": "attack_attempt", "cwe": "918", "capec": "1000/225/115/664", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -6743,7 +6885,8 @@ "category": "attack_attempt", "cwe": "918", "capec": "1000/225/115/664", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -6785,7 +6928,8 @@ "category": "attack_attempt", "cwe": "918", "capec": "1000/225/115/664", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6828,7 +6972,8 @@ "category": "attack_attempt", "cwe": "918", "capec": "1000/225/115/664", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -6870,7 +7015,8 @@ "category": "attack_attempt", "cwe": "94", "capec": "1000/152/242", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6916,7 +7062,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Joomla exploitation tool", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6945,7 +7092,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Nessus", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -6974,7 +7122,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Arachni", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7003,7 +7152,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Jorgee", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7032,7 +7182,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Probely", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -7061,7 +7212,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Metis", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7090,7 +7242,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "SQLPowerInjector", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7119,7 +7272,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "N-Stealth", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7148,7 +7302,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Brutus", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7176,7 +7331,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7205,7 +7361,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Netsparker", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -7234,7 +7391,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "JAASCois", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7263,7 +7421,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Nsauditor", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7292,7 +7451,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Paros", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7321,7 +7481,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "DirBuster", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7350,7 +7511,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Pangolin", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7379,7 +7541,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Qualys", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -7408,7 +7571,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "SQLNinja", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7437,7 +7601,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Nikto", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7466,7 +7631,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "BlackWidow", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7495,7 +7661,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Grendel-Scan", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7524,7 +7691,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Havij", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7553,7 +7721,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "w3af", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7582,7 +7751,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Nmap", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7595,7 +7765,7 @@ ] } ], - "regex": "nmap (nse|scripting engine)" + "regex": "nmap (nse|scripting engine|icap-client/)" }, "operator": "match_regex" } @@ -7611,7 +7781,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Nessus", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7640,7 +7811,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "EvilScanner", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7669,7 +7841,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "WebFuck", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7698,7 +7871,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "OpenVAS", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7727,7 +7901,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Spider-Pig", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7756,7 +7931,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Zgrab", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7785,7 +7961,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Zmeu", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7814,7 +7991,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "GoogleSecurityScanner", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -7843,7 +8021,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Commix", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7872,7 +8051,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Gobuster", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7901,7 +8081,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "CGIchk", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7930,7 +8111,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "FFUF", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7959,7 +8141,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Nuclei", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -7988,7 +8171,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Tsunami", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8017,7 +8201,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Nimbostratus", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8046,7 +8231,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Datadog Canary Test", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8081,7 +8267,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Datadog Canary Test", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8119,7 +8306,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "AlertLogic", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -8148,7 +8336,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "wfuzz", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8177,7 +8366,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Detectify", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -8206,7 +8396,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "BSQLBF", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8235,7 +8426,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "masscan", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8264,7 +8456,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "WPScan", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8293,7 +8486,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Aon", - "confidence": "0" + "confidence": "0", + "module": "waf" }, "conditions": [ { @@ -8322,7 +8516,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "feroxbuster", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8350,7 +8545,8 @@ "category": "attack_attempt", "cwe": "200", "capec": "1000/118/169", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8382,7 +8578,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "SQLmap", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -8411,7 +8608,8 @@ "cwe": "200", "capec": "1000/118/169", "tool_name": "Skipfish", - "confidence": "1" + "confidence": "1", + "module": "waf" }, "conditions": [ { @@ -9776,4 +9974,4 @@ } } ] -} +} \ No newline at end of file diff --git a/appsec/src/extension/commands_helpers.c b/appsec/src/extension/commands_helpers.c index c63f5d97dc..9cbd505121 100644 --- a/appsec/src/extension/commands_helpers.c +++ b/appsec/src/extension/commands_helpers.c @@ -473,6 +473,7 @@ dd_result dd_command_proc_resp_verd_span_data( if (res == dd_should_block || res == dd_should_redirect || res == dd_should_record) { + dd_trace_emit_asm_event(); _set_appsec_span_data( mpack_node_array_at(root, RESP_INDEX_APPSEC_SPAN_DATA)); } diff --git a/appsec/src/extension/configuration.h b/appsec/src/extension/configuration.h index aca5465349..7bd4e478d8 100644 --- a/appsec/src/extension/configuration.h +++ b/appsec/src/extension/configuration.h @@ -69,6 +69,7 @@ extern bool runtime_config_first_init; CONFIG(STRING, DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML, "") \ CONFIG(STRING, DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON, "") \ CONFIG(DOUBLE, DD_API_SECURITY_REQUEST_SAMPLE_RATE, "0.1", .ini_change = zai_config_system_ini_change) \ + CONFIG(BOOL, DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED, "false") \ CONFIG(BOOL, DD_API_SECURITY_ENABLED, "true", .ini_change = zai_config_system_ini_change) // clang-format on diff --git a/appsec/src/extension/ddtrace.c b/appsec/src/extension/ddtrace.c index f2993af4fd..04ba09a97e 100644 --- a/appsec/src/extension/ddtrace.c +++ b/appsec/src/extension/ddtrace.c @@ -46,6 +46,8 @@ static void (*nullable _ddtrace_close_all_spans_and_flush)(void); static void (*nullable _ddtrace_set_priority_sampling_on_span_zobj)( zend_object *nonnull zobj, zend_long priority, enum dd_sampling_mechanism mechanism); +static void (*nullable _ddtrace_add_propagated_tag_on_span_zobj)( + zend_string *nonnull key, zval *nonnull value); static bool (*nullable _ddtrace_user_req_add_listeners)( ddtrace_user_req_listeners *listeners); @@ -53,6 +55,7 @@ static bool (*nullable _ddtrace_user_req_add_listeners)( static zend_string *(*_ddtrace_ip_extraction_find)(zval *server); static const char *nullable (*_ddtrace_remote_config_get_path)(void); +static void *(*nullable _ddtrace_emit_asm_event)(void); static void _test_ddtrace_metric_register_buffer( zend_string *nonnull name, ddtrace_metric_type type, ddtrace_metric_ns ns); @@ -99,6 +102,14 @@ static void dd_trace_load_symbols(void) dlerror()); // NOLINT(concurrency-mt-unsafe) } + _ddtrace_add_propagated_tag_on_span_zobj = + dlsym(handle, "ddtrace_add_propagated_tag_on_span_zobj"); + if (_ddtrace_add_propagated_tag_on_span_zobj == NULL) { + mlog(dd_log_error, + "Failed to load ddtrace_add_propagated_tag_on_span_zobj: %s", + dlerror()); // NOLINT(concurrency-mt-unsafe) + } + _ddtrace_user_req_add_listeners = dlsym(handle, "ddtrace_user_req_add_listeners"); if (_ddtrace_user_req_add_listeners == NULL) { @@ -133,6 +144,13 @@ static void dd_trace_load_symbols(void) dlerror()); // NOLINT(concurrency-mt-unsafe) } + _ddtrace_emit_asm_event = dlsym(handle, "ddtrace_emit_asm_event"); + if (_ddtrace_emit_asm_event == NULL) { + mlog(dd_log_error, + // NOLINTNEXTLINE(concurrency-mt-unsafe) + "Failed to load ddtrace_emit_asm_event: %s", dlerror()); + } + dlclose(handle); } @@ -414,6 +432,25 @@ const char *nullable dd_trace_remote_config_get_path() return path; } +void dd_trace_span_add_propagated_tags( + zend_string *nonnull key, zval *nonnull value) +{ + if (UNEXPECTED(_ddtrace_add_propagated_tag_on_span_zobj == NULL)) { + return; + } + + _ddtrace_add_propagated_tag_on_span_zobj(key, value); +} + +void dd_trace_emit_asm_event(void) +{ + if (UNEXPECTED(_ddtrace_emit_asm_event == NULL)) { + return; + } + + _ddtrace_emit_asm_event(); +} + static PHP_FUNCTION(datadog_appsec_testing_ddtrace_rshutdown) { if (zend_parse_parameters_none() == FAILURE) { diff --git a/appsec/src/extension/ddtrace.h b/appsec/src/extension/ddtrace.h index 79d6f430b9..5636b049ec 100644 --- a/appsec/src/extension/ddtrace.h +++ b/appsec/src/extension/ddtrace.h @@ -20,6 +20,7 @@ enum dd_sampling_mechanism { DD_MECHANISM_REMOTE_RATE = 2, DD_MECHANISM_RULE = 3, DD_MECHANISM_MANUAL = 4, + DD_MECHANISM_ASM = 5, }; typedef zend_object root_span_t; @@ -48,11 +49,14 @@ bool dd_trace_span_add_tag_str(zend_object *nonnull zobj, // Flush the tracer spans, can be used on RINIT void dd_trace_close_all_spans_and_flush(void); +void dd_trace_emit_asm_event(void); + // Provides the array zval representing $root_span->meta, if any. // It is ready for modification, with refcount == 1 zval *nullable dd_trace_span_get_meta(zend_object *nonnull); zval *nullable dd_trace_span_get_metrics(zend_object *nonnull); zval *nullable dd_trace_span_get_meta_struct(zend_object *nonnull); +void dd_trace_span_add_propagated_tags(zend_string *nonnull key, zval *nonnull value); zend_string *nullable dd_trace_get_formatted_runtime_id(bool persistent); // Set sampling priority on root span diff --git a/appsec/src/extension/tags.c b/appsec/src/extension/tags.c index f472559beb..086c8e45c2 100644 --- a/appsec/src/extension/tags.c +++ b/appsec/src/extension/tags.c @@ -27,6 +27,7 @@ #endif #define DD_TAG_DATA "_dd.appsec.json" +#define DD_TAG_P_APPSEC "_dd.p.appsec" #define DD_TAG_EVENT "appsec.event" #define DD_TAG_BLOCKED "appsec.blocked" #define DD_TAG_RUNTIME_FAMILY "_dd.runtime_family" @@ -65,6 +66,7 @@ static zend_string *_dd_tag_data_zstr; static zend_string *_dd_tag_event_zstr; static zend_string *_dd_tag_blocked_zstr; +static zend_string *_dd_tag_p_appsec_zstr; static zend_string *_dd_tag_http_method_zstr; static zend_string *_dd_tag_http_user_agent_zstr; static zend_string *_dd_tag_http_status_code_zstr; @@ -96,6 +98,7 @@ static zend_string *_key_server_name_zstr; static zend_string *_key_http_user_agent_zstr; static zend_string *_key_https_zstr; static zend_string *_key_remote_addr_zstr; +static zend_string *_1_zstr; static zend_string *_true_zstr; static zend_string *_false_zstr; static zend_string *_track_zstr; @@ -130,9 +133,12 @@ void dd_tags_startup() zend_string_init_interned(LSTRARG(DD_TAG_EVENT), 1 /* permanent */); _dd_tag_blocked_zstr = zend_string_init_interned(LSTRARG(DD_TAG_BLOCKED), 1 /* permanent */); + _1_zstr = zend_string_init_interned(LSTRARG("1"), 1 /* permanent */); _true_zstr = zend_string_init_interned(LSTRARG("true"), 1 /* permanent */); _false_zstr = zend_string_init_interned(LSTRARG("false"), 1 /* permanent */); + _dd_tag_p_appsec_zstr = + zend_string_init_interned(LSTRARG(DD_TAG_P_APPSEC), 1 /* permanent */); _dd_tag_http_method_zstr = zend_string_init_interned(LSTRARG(DD_TAG_HTTP_METHOD), 1); @@ -345,8 +351,11 @@ void dd_tags_add_tags( _set_runtime_family(span); if (_force_keep) { - dd_trace_set_priority_sampling_on_span_zobj( - span, PRIORITY_SAMPLING_USER_KEEP, DD_MECHANISM_MANUAL); + dd_trace_set_priority_sampling_on_span_zobj(span, + PRIORITY_SAMPLING_USER_KEEP, + get_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED() + ? DD_MECHANISM_ASM + : DD_MECHANISM_MANUAL); mlog(dd_log_debug, "Updated sampling priority to user_keep"); } @@ -361,6 +370,12 @@ void dd_tags_add_tags( return; } + // If we reach this point, there are asm events + zval _1_zval; + ZVAL_STR(&_1_zval, _1_zstr); + + dd_trace_span_add_propagated_tags(_dd_tag_p_appsec_zstr, &_1_zval); + zend_string *tag_value = _concat_json_fragments(); zval tag_value_zv; @@ -374,9 +389,9 @@ void dd_tags_add_tags( } // tag appsec.event - zval true_zv; - ZVAL_STR_COPY(&true_zv, _true_zstr); - res = dd_trace_span_add_tag(span, _dd_tag_event_zstr, &true_zv); + zval _true_zval; + ZVAL_STR(&_true_zval, _true_zstr); + res = dd_trace_span_add_tag(span, _dd_tag_event_zstr, &_true_zval); if (!res) { mlog(dd_log_info, "Failed adding tag " DD_TAG_EVENT " to root span"); return; diff --git a/appsec/tests/extension/client_init_record_span_tags.phpt b/appsec/tests/extension/client_init_record_span_tags.phpt index 5455aeafd6..60f08e21ce 100644 --- a/appsec/tests/extension/client_init_record_span_tags.phpt +++ b/appsec/tests/extension/client_init_record_span_tags.phpt @@ -85,7 +85,8 @@ tags: Array ( [_dd.appsec.json] => {"triggers":[{"found":"attack"},{"another":"attack"},{"yet another":"attack"}]} - [_dd.p.dm] => -0 + [_dd.p.appsec] => 1 + [_dd.p.dm] => -5 [_dd.p.tid] => %s [_dd.runtime_family] => php [appsec.event] => true @@ -106,8 +107,7 @@ Array [metric_1] => 2 [metric_2] => 10 [_dd.appsec.enabled] => 1 - [_dd.agent_psr] => 1 - [_sampling_priority_v1] => 1 + [_sampling_priority_v1] => 2 [php.compilation.total_time_ms] => %f [php.memory.peak_usage_bytes] => %f [php.memory.peak_real_usage_bytes] => %f diff --git a/appsec/tests/extension/inc/mock_helper.php b/appsec/tests/extension/inc/mock_helper.php index 7a9a75594a..7a5b7212dd 100644 --- a/appsec/tests/extension/inc/mock_helper.php +++ b/appsec/tests/extension/inc/mock_helper.php @@ -293,6 +293,22 @@ function response_config_sync() { return response("config_sync", []); } +function request_without_events() +{ + return [ + response_list(response_request_init([[['ok', []]], [], true])), + response_list(response_request_shutdown([[['ok', []]], [], true])), + ]; +} + +function request_with_events() +{ + return [ + response_list(response_request_init([[['record', []]],['{"found":"attack"}','{"another":"attack"}'],true])), + response_list(response_request_shutdown([[['record', []]], ['{"yet another":"attack"}'], true])) + ]; +} + // vim: set et sw=4 ts=4: ?> diff --git a/appsec/tests/extension/rinit_asm_events_propagate_tags.phpt b/appsec/tests/extension/rinit_asm_events_propagate_tags.phpt new file mode 100644 index 0000000000..636023e055 --- /dev/null +++ b/appsec/tests/extension/rinit_asm_events_propagate_tags.phpt @@ -0,0 +1,66 @@ +--TEST-- +Asm events are added as meta tags and also as propagated tags +--INI-- +extension=ddtrace.so +datadog.appsec.log_file=/tmp/php_appsec_test.log +datadog.appsec.log_level=debug +datadog.appsec.enabled=1 +--ENV-- +HTTP_X_DATADOG_TRACE_ID=42 +HTTP_X_DATADOG_PARENT_ID=10 +HTTP_X_DATADOG_ORIGIN=datadog +HTTP_X_DATADOG_TAGS=_dd.p.custom_tag=inherited,_dd.p.second_tag=bar +--FILE-- + "rshutdown_value"], ["rshutdown_metric" => 2.1]] + ) + ), +], ['continuous' => true]); + +echo "rinit\n"; +var_dump(rinit()); +$helper->get_commands(); //ignore + +$context = DDTrace\current_context(); +echo "_dd.p.appsec on distributed propagated tags? "; +echo isset($context['distributed_tracing_propagated_tags']['_dd.p.appsec']) && $context['distributed_tracing_propagated_tags']['_dd.p.appsec'] == 1 ? "Yes": "No"; +echo PHP_EOL; + +echo "rshutdown\n"; +var_dump(rshutdown()); +$helper->get_commands(); //ignore + +echo "ddtrace_rshutdown\n"; +var_dump(ddtrace_rshutdown()); +dd_trace_internal_fn('synchronous_flush'); + +$commands = $helper->get_commands(); +$tags = $commands[0]['payload'][0][0]['meta']; + +echo "_dd.p.appsec? "; +echo isset($tags['_dd.p.appsec']) && $tags['_dd.p.appsec'] === "1" ? "Yes": "No"; +echo PHP_EOL; + +$helper->finished_with_commands(); + +?> +--EXPECTF-- +rinit +bool(true) +_dd.p.appsec on distributed propagated tags? Yes +rshutdown +bool(true) +ddtrace_rshutdown +bool(true) +_dd.p.appsec? Yes diff --git a/appsec/tests/extension/rinit_record_span_tags.phpt b/appsec/tests/extension/rinit_record_span_tags.phpt index 3ffe1d1f79..44826d6f8c 100644 --- a/appsec/tests/extension/rinit_record_span_tags.phpt +++ b/appsec/tests/extension/rinit_record_span_tags.phpt @@ -80,7 +80,8 @@ tags: Array ( [_dd.appsec.json] => {"triggers":[{"found":"attack"},{"another":"attack"},{"yet another":"attack"}]} - [_dd.p.dm] => -0 + [_dd.p.appsec] => 1 + [_dd.p.dm] => -5 [_dd.p.tid] => %s [_dd.runtime_family] => php [appsec.event] => true @@ -99,8 +100,7 @@ Array [%s] => %d [rshutdown_metric] => 2.1 [_dd.appsec.enabled] => 1 - [_dd.agent_psr] => 1 - [_sampling_priority_v1] => 1 + [_sampling_priority_v1] => 2 [php.compilation.total_time_ms] => %f [php.memory.peak_usage_bytes] => %f [php.memory.peak_real_usage_bytes] => %f diff --git a/config.m4 b/config.m4 index 3e13ce17ce..8e35b07846 100644 --- a/config.m4 +++ b/config.m4 @@ -163,6 +163,7 @@ if test "$PHP_DDTRACE" != "no"; then DD_TRACE_PHP_SOURCES="$EXTRA_PHP_SOURCES \ ext/ddtrace.c \ ext/agent_info.c \ + ext/asm_event.c \ ext/arrays.c \ ext/auto_flush.c \ ext/autoload_php_files.c \ @@ -188,6 +189,7 @@ if test "$PHP_DDTRACE" != "no"; then ext/integrations/exec_integration.c \ ext/integrations/integrations.c \ ext/ip_extraction.c \ + ext/standalone_limiter.c \ ext/live_debugger.c \ ext/logging.c \ ext/limiter/limiter.c \ diff --git a/config.w32 b/config.w32 index 5c00f88e32..fadb21e51f 100644 --- a/config.w32 +++ b/config.w32 @@ -17,6 +17,7 @@ if (PHP_DDTRACE != 'no') { var DDTRACE_EXT_SOURCES = "agent_info.c"; DDTRACE_EXT_SOURCES += " arrays.c"; + DDTRACE_EXT_SOURCES += " asm_event.c"; DDTRACE_EXT_SOURCES += " auto_flush.c"; DDTRACE_EXT_SOURCES += " autoload_php_files.c"; DDTRACE_EXT_SOURCES += " collect_backtrace.c"; @@ -36,6 +37,7 @@ if (PHP_DDTRACE != 'no') { DDTRACE_EXT_SOURCES += " handlers_internal.c"; DDTRACE_EXT_SOURCES += " handlers_pcntl.c"; DDTRACE_EXT_SOURCES += " ip_extraction.c"; + DDTRACE_EXT_SOURCES += " standalone_limiter.c"; DDTRACE_EXT_SOURCES += " live_debugger.c"; DDTRACE_EXT_SOURCES += " logging.c"; DDTRACE_EXT_SOURCES += " memory_limit.c"; diff --git a/ddtrace.sym b/ddtrace.sym index f0493dd9d5..290629f8a3 100644 --- a/ddtrace.sym +++ b/ddtrace.sym @@ -2,6 +2,7 @@ ddtrace_close_all_spans_and_flush ddtrace_get_profiling_context ddtrace_get_root_span ddtrace_set_priority_sampling_on_span_zobj +ddtrace_add_propagated_tag_on_span_zobj ddtrace_runtime_id ddtrace_user_req_add_listeners ddtrace_ip_extraction_find @@ -9,6 +10,7 @@ ddtrace_set_all_thread_vm_interrupt ddtrace_remote_config_get_path ddtrace_metric_register_buffer ddtrace_metric_add_point +ddtrace_emit_asm_event ddog_remote_config_reader_for_path ddog_remote_config_read ddog_remote_config_reader_drop diff --git a/ext/asm_event.c b/ext/asm_event.c new file mode 100644 index 0000000000..d729a285b5 --- /dev/null +++ b/ext/asm_event.c @@ -0,0 +1,36 @@ +#include "asm_event.h" +#include "ddtrace.h" +#include "priority_sampling/priority_sampling.h" +#include "tracer_tag_propagation/tracer_tag_propagation.h" + +ZEND_EXTERN_MODULE_GLOBALS(ddtrace); + +static zend_string *_dd_tag_p_appsec_zstr; +static zend_string *_1_zstr; + +void ddtrace_appsec_minit() { + _1_zstr = zend_string_init_interned(ZEND_STRL("1"), 1 /* permanent */); + _dd_tag_p_appsec_zstr = zend_string_init_interned(ZEND_STRL(DD_TAG_P_APPSEC), 1 /* permanent */); +} + +DDTRACE_PUBLIC void ddtrace_emit_asm_event() { + if (!DDTRACE_G(active_stack)) { + return; + } + + DDTRACE_G(asm_event_emitted) = true; + + zval _1_zval; + ZVAL_STR(&_1_zval, _1_zstr); + ddtrace_add_propagated_tag(_dd_tag_p_appsec_zstr, &_1_zval); + + ddtrace_set_priority_sampling_on_root(PRIORITY_SAMPLING_USER_KEEP, DD_MECHANISM_ASM); +} + +PHP_FUNCTION(DDTrace_Testing_emit_asm_event) { + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + + ddtrace_emit_asm_event(); +} \ No newline at end of file diff --git a/ext/asm_event.h b/ext/asm_event.h new file mode 100644 index 0000000000..171054b27e --- /dev/null +++ b/ext/asm_event.h @@ -0,0 +1,11 @@ +#ifndef ASM_EVENT_H +#define ASM_EVENT_H + +#include "ddtrace_export.h" + +#define DD_TAG_P_APPSEC "_dd.p.appsec" + +void ddtrace_appsec_minit(); +DDTRACE_PUBLIC void ddtrace_emit_asm_event(); + +#endif // ASM_EVENT_H diff --git a/ext/auto_flush.c b/ext/auto_flush.c index a35a1f56d8..2a90cfe8cd 100644 --- a/ext/auto_flush.c +++ b/ext/auto_flush.c @@ -1,5 +1,6 @@ #include "auto_flush.h" +#include "asm_event.h" #ifndef _WIN32 #include "comms_php.h" #include "coms.h" @@ -11,8 +12,29 @@ #include "span.h" #include "sidecar.h" #include "ddshared.h" +#include "standalone_limiter.h" #include
+ZEND_EXTERN_MODULE_GLOBALS(ddtrace); + +static bool trace_contains_appsec_event(zval *trace) { + if (!trace || Z_TYPE_P(trace) != IS_ARRAY) { + return false; + } + + zval *root_span = zend_hash_index_find(Z_ARR_P(trace), 0); + if (!root_span || Z_TYPE_P(root_span) != IS_ARRAY) { + return false; + } + + zval *meta = zend_hash_str_find(Z_ARR_P(root_span), ZEND_STRL("meta")); + if (!meta || Z_TYPE_P(meta) != IS_ARRAY) { + return false; + } + + return zend_hash_str_exists(Z_ARR_P(meta), DD_TAG_P_APPSEC, strlen(DD_TAG_P_APPSEC)); +} + ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles) { bool success = true; @@ -38,6 +60,31 @@ ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles return SUCCESS; } + if (get_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED()) { + if (!DDTRACE_G(asm_event_emitted) && !trace_contains_appsec_event(&trace) && !ddtrace_standalone_limiter_allow()) { + zval *root_span = zend_hash_index_find(Z_ARR(trace), 0); + if (!root_span || Z_TYPE_P(root_span) != IS_ARRAY) { + LOG(ERROR, "Root span not found. Dropping trace"); + return SUCCESS; + } + + zval *metrics = zend_hash_str_find(Z_ARR_P(root_span), ZEND_STRL("metrics")); + if (!metrics || Z_TYPE_P(metrics) != IS_ARRAY) { + LOG(ERROR, "Metrics not found. Dropping trace"); + return SUCCESS; + } + + zval *sampling_priority = zend_hash_str_find(Z_ARR_P(metrics), ZEND_STRL("_sampling_priority_v1")); + if (!sampling_priority || (Z_TYPE_P(sampling_priority) != IS_DOUBLE && Z_TYPE_P(sampling_priority) != IS_LONG)) { + LOG(ERROR, "Invalid sampling priority. Dropping trace"); + return SUCCESS; + } + ZVAL_LONG(sampling_priority, PRIORITY_SAMPLING_AUTO_REJECT); + } else { + ddtrace_standalone_limiter_hit(); + } + } + // background sender only wants a singular trace array_init(&traces); zend_hash_index_add(Z_ARR(traces), 0, &trace); @@ -64,7 +111,7 @@ ZEND_RESULT_CODE ddtrace_flush_tracer(bool force_on_startup, bool collect_cycles .tracer_version = DDOG_CHARSLICE_C_BARE(PHP_DDTRACE_VERSION), .lang_version = dd_zend_string_to_CharSlice(ddtrace_php_version), .client_computed_top_level = false, - .client_computed_stats = false, + .client_computed_stats = get_global_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED(), }; size_t size_hint = written; zend_long n_requests = get_global_DD_TRACE_AGENT_FLUSH_AFTER_N_REQUESTS(); diff --git a/ext/coms.c b/ext/coms.c index 7a8e33c8ec..ce3512c901 100644 --- a/ext/coms.c +++ b/ext/coms.c @@ -695,6 +695,7 @@ static struct curl_slist *dd_agent_headers_alloc(void) { dd_append_header(&list, "Datadog-Meta-Lang-Interpreter", sapi_module.name); dd_append_header(&list, "Datadog-Meta-Lang-Version", ZSTR_VAL(ddtrace_php_version)); dd_append_header(&list, "Datadog-Meta-Tracer-Version", PHP_DDTRACE_VERSION); + dd_append_header(&list, "Datadog-Client-Computed-Stats", get_global_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED() ? "true" : "false"); ddog_CharSlice id = ddtrace_get_container_id(); if (id.len) { diff --git a/ext/configuration.h b/ext/configuration.h index c14a3df913..30ac815eb7 100644 --- a/ext/configuration.h +++ b/ext/configuration.h @@ -235,6 +235,7 @@ enum ddtrace_sampling_rules_format { CONFIG(BOOL, DD_REMOTE_CONFIG_ENABLED, "true", .ini_change = zai_config_system_ini_change) \ CONFIG(BOOL, DD_DYNAMIC_INSTRUMENTATION_ENABLED, "false", .ini_change = zai_config_system_ini_change) \ CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_IDENTIFIERS, "", .ini_change = zai_config_system_ini_change) \ + CONFIG(BOOL, DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED, "false") \ CONFIG(SET, DD_DYNAMIC_INSTRUMENTATION_REDACTED_TYPES, "", .ini_change = zai_config_system_ini_change) \ DD_INTEGRATIONS diff --git a/ext/ddtrace.c b/ext/ddtrace.c index 6fe166d009..f4b6d32a5e 100644 --- a/ext/ddtrace.c +++ b/ext/ddtrace.c @@ -37,6 +37,7 @@ #include #include +#include "asm_event.h" #include "auto_flush.h" #include "compatibility.h" #ifndef _WIN32 @@ -60,6 +61,7 @@ #include "logging.h" #include "memory_limit.h" #include "limiter/limiter.h" +#include "standalone_limiter.h" #include "priority_sampling/priority_sampling.h" #include "random.h" #include "autoload_php_files.h" @@ -1423,6 +1425,7 @@ static PHP_MINIT_FUNCTION(ddtrace) { ddtrace_initialize_span_sampling_limiter(); ddtrace_limiter_create(); + ddtrace_standalone_limiter_create(); ddtrace_log_minit(); @@ -1452,6 +1455,7 @@ static PHP_MINIT_FUNCTION(ddtrace) { ddtrace_live_debugger_minit(); ddtrace_minit_remote_config(); + ddtrace_appsec_minit(); return SUCCESS; } @@ -1496,6 +1500,7 @@ static PHP_MSHUTDOWN_FUNCTION(ddtrace) { ddtrace_shutdown_span_sampling_limiter(); ddtrace_limiter_destroy(); + ddtrace_standalone_limiter_destroy(); zai_config_mshutdown(); zai_json_shutdown_bindings(); @@ -1543,6 +1548,7 @@ static void dd_initialize_request(void) { DDTRACE_G(additional_global_tags) = zend_new_array(0); DDTRACE_G(default_priority_sampling) = DDTRACE_PRIORITY_SAMPLING_UNKNOWN; DDTRACE_G(propagated_priority_sampling) = DDTRACE_PRIORITY_SAMPLING_UNSET; + DDTRACE_G(asm_event_emitted) = false; zend_hash_init(&DDTRACE_G(root_span_tags_preset), 8, unused, ZVAL_PTR_DTOR, 0); zend_hash_init(&DDTRACE_G(propagated_root_span_tags), 8, unused, ZVAL_PTR_DTOR, 0); zend_hash_init(&DDTRACE_G(tracestate_unknown_dd_keys), 8, unused, ZVAL_PTR_DTOR, 0); diff --git a/ext/ddtrace.h b/ext/ddtrace.h index 481acc43ba..19fde78a08 100644 --- a/ext/ddtrace.h +++ b/ext/ddtrace.h @@ -146,6 +146,8 @@ ZEND_BEGIN_MODULE_GLOBALS(ddtrace) HashTable telemetry_spans_created_per_integration; ddog_SidecarActionsBuffer *telemetry_buffer; + bool asm_event_emitted; + #if PHP_VERSION_ID >= 80000 HashTable curl_headers; // Multi-handle API: curl_multi_*() diff --git a/ext/ddtrace.stub.php b/ext/ddtrace.stub.php index 8facdd633f..066b759dc5 100644 --- a/ext/ddtrace.stub.php +++ b/ext/ddtrace.stub.php @@ -830,6 +830,10 @@ function set_blocking_function(\DDTrace\RootSpanData $span, callable $blockingFu * E_DEPRECATED, E_USER_DEPRECATED */ function trigger_error(string $message, int $errorType): void {} + /** + * Emits an asm event + */ + function emit_asm_event(): void {} } namespace DDTrace\Internal { diff --git a/ext/ddtrace_arginfo.h b/ext/ddtrace_arginfo.h index 8766e5292e..d616d445e9 100644 --- a/ext/ddtrace_arginfo.h +++ b/ext/ddtrace_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 5eb7dd922aab52cab793bd947871d8ee8ee0c284 */ + * Stub hash: 5edec61a2b1ae22c8473ffbd3c509df6196abbae */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_trace_method, 0, 3, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, className, IS_STRING, 0) @@ -183,6 +183,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Testing_trigger_error, 0 ZEND_ARG_TYPE_INFO(0, errorType, IS_LONG, 0) ZEND_END_ARG_INFO() +#define arginfo_DDTrace_Testing_emit_asm_event arginfo_DDTrace_flush + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_DDTrace_Internal_add_span_flag, 0, 2, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, span, DDTrace\\SpanData, 0) ZEND_ARG_TYPE_INFO(0, flag, IS_LONG, 0) @@ -346,6 +348,7 @@ ZEND_FUNCTION(DDTrace_UserRequest_notify_start); ZEND_FUNCTION(DDTrace_UserRequest_notify_commit); ZEND_FUNCTION(DDTrace_UserRequest_set_blocking_function); ZEND_FUNCTION(DDTrace_Testing_trigger_error); +ZEND_FUNCTION(DDTrace_Testing_emit_asm_event); ZEND_FUNCTION(DDTrace_Internal_add_span_flag); ZEND_FUNCTION(DDTrace_Internal_handle_fork); ZEND_FUNCTION(dd_trace_env_config); @@ -429,6 +432,7 @@ static const zend_function_entry ext_functions[] = { ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\UserRequest", "notify_commit"), zif_DDTrace_UserRequest_notify_commit, arginfo_DDTrace_UserRequest_notify_commit, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\UserRequest", "set_blocking_function"), zif_DDTrace_UserRequest_set_blocking_function, arginfo_DDTrace_UserRequest_set_blocking_function, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\Testing", "trigger_error"), zif_DDTrace_Testing_trigger_error, arginfo_DDTrace_Testing_trigger_error, 0, NULL, NULL) + ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\Testing", "emit_asm_event"), zif_DDTrace_Testing_emit_asm_event, arginfo_DDTrace_Testing_emit_asm_event, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\Internal", "add_span_flag"), zif_DDTrace_Internal_add_span_flag, arginfo_DDTrace_Internal_add_span_flag, 0, NULL, NULL) ZEND_RAW_FENTRY(ZEND_NS_NAME("DDTrace\\Internal", "handle_fork"), zif_DDTrace_Internal_handle_fork, arginfo_DDTrace_Internal_handle_fork, 0, NULL, NULL) ZEND_FE(dd_trace_env_config, arginfo_dd_trace_env_config) diff --git a/ext/handlers_http.h b/ext/handlers_http.h index ba380c0783..2cdbec083e 100644 --- a/ext/handlers_http.h +++ b/ext/handlers_http.h @@ -1,3 +1,4 @@ +#include "asm_event.h" #include "configuration.h" #include "ddtrace.h" #include "priority_sampling/priority_sampling.h" @@ -135,6 +136,15 @@ static inline void ddtrace_inject_distributed_headers_config(zend_array *array, bool send_b3single = zend_hash_str_exists(inject, ZEND_STRL("b3 single header")); zend_long sampling_priority = ddtrace_fetch_priority_sampling_from_root(); + if (get_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED() && DDTRACE_G(asm_event_emitted) == true) { + sampling_priority = PRIORITY_SAMPLING_USER_KEEP; + } + + if (get_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED() && DDTRACE_G(asm_event_emitted) == false && + ddtrace_propagated_tags_get_tag(DD_TAG_P_APPSEC) == NULL) { + return; + } + if (sampling_priority != DDTRACE_PRIORITY_SAMPLING_UNKNOWN) { if (send_datadog) { ADD_HEADER("x-datadog-sampling-priority", ZEND_LONG_FMT, sampling_priority); diff --git a/ext/limiter/limiter.c b/ext/limiter/limiter.c index cc6db08a1c..a658a62c23 100644 --- a/ext/limiter/limiter.c +++ b/ext/limiter/limiter.c @@ -61,6 +61,9 @@ bool ddtrace_limiter_active() { } bool ddtrace_limiter_allow() { + if (get_global_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED()) { + return true; + } ZEND_ASSERT(dd_limiter); uint64_t timeval = zend_hrtime(); diff --git a/ext/priority_sampling/priority_sampling.c b/ext/priority_sampling/priority_sampling.c index efff1f4800..967113f984 100644 --- a/ext/priority_sampling/priority_sampling.c +++ b/ext/priority_sampling/priority_sampling.c @@ -124,36 +124,38 @@ static ddtrace_rule_result dd_match_rules(ddtrace_span_data *span, bool eval_roo } zval *rule; - ZEND_HASH_FOREACH_VAL(get_DD_TRACE_SAMPLING_RULES(), rule) { - if (++index >= skip_at) { - break; - } - - if (Z_TYPE_P(rule) != IS_ARRAY) { - continue; - } + if (!get_global_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED()) { // APPSEC_STANDALONE enabled, override sampling rules to be empty + ZEND_HASH_FOREACH_VAL(get_DD_TRACE_SAMPLING_RULES(), rule) { + if (++index >= skip_at) { + break; + } - if (!eval_root) { - zval *applies = zend_hash_str_find(Z_ARR_P(rule), ZEND_STRL("target_span")); - if (!applies || Z_TYPE_P(applies) != IS_STRING || !zend_string_equals_literal(Z_STR_P(applies), "any")) { + if (Z_TYPE_P(rule) != IS_ARRAY) { continue; } - } - if (dd_check_sampling_rule(Z_ARR_P(rule), span)) { - zval *sample_rate_zv = zend_hash_str_find(Z_ARR_P(rule), ZEND_STRL("sample_rate")); - zval *provenance_zv = zend_hash_str_find(Z_ARR_P(rule), ZEND_STRL("_provenance")); - enum dd_sampling_mechanism mechanism = DD_MECHANISM_RULE; - if (provenance_zv && Z_TYPE_P(provenance_zv) == IS_STRING) { - if (zend_string_equals_literal(Z_STR_P(provenance_zv), "customer")) { - mechanism = DD_MECHANISM_REMOTE_USER_RULE; - } else if (zend_string_equals_literal(Z_STR_P(provenance_zv), "dynamic")) { - mechanism = DD_MECHANISM_REMOTE_DYNAMIC_RULE; + if (!eval_root) { + zval *applies = zend_hash_str_find(Z_ARR_P(rule), ZEND_STRL("target_span")); + if (!applies || Z_TYPE_P(applies) != IS_STRING || !zend_string_equals_literal(Z_STR_P(applies), "any")) { + continue; } } - return (ddtrace_rule_result){ .sampling_rate = sample_rate_zv ? zval_get_double(sample_rate_zv) : 1, .rule = index, .mechanism = mechanism }; - } - } ZEND_HASH_FOREACH_END(); + + if (dd_check_sampling_rule(Z_ARR_P(rule), span)) { + zval *sample_rate_zv = zend_hash_str_find(Z_ARR_P(rule), ZEND_STRL("sample_rate")); + zval *provenance_zv = zend_hash_str_find(Z_ARR_P(rule), ZEND_STRL("_provenance")); + enum dd_sampling_mechanism mechanism = DD_MECHANISM_RULE; + if (provenance_zv && Z_TYPE_P(provenance_zv) == IS_STRING) { + if (zend_string_equals_literal(Z_STR_P(provenance_zv), "customer")) { + mechanism = DD_MECHANISM_REMOTE_USER_RULE; + } else if (zend_string_equals_literal(Z_STR_P(provenance_zv), "dynamic")) { + mechanism = DD_MECHANISM_REMOTE_DYNAMIC_RULE; + } + } + return (ddtrace_rule_result){ .sampling_rate = sample_rate_zv ? zval_get_double(sample_rate_zv) : 1, .rule = index, .mechanism = mechanism }; + } + } ZEND_HASH_FOREACH_END(); + } return (ddtrace_rule_result){ .sampling_rate = 0, .rule = INT32_MAX, .mechanism = DD_MECHANISM_RULE }; } diff --git a/ext/priority_sampling/priority_sampling.h b/ext/priority_sampling/priority_sampling.h index eb38913239..64ad669f91 100644 --- a/ext/priority_sampling/priority_sampling.h +++ b/ext/priority_sampling/priority_sampling.h @@ -18,6 +18,7 @@ enum dd_sampling_mechanism { DD_MECHANISM_REMOTE_RATE = 2, DD_MECHANISM_RULE = 3, DD_MECHANISM_MANUAL = 4, + DD_MECHANISM_ASM = 5, DD_MECHANISM_REMOTE_USER_RULE = 11, DD_MECHANISM_REMOTE_DYNAMIC_RULE = 12, }; diff --git a/ext/serializer.c b/ext/serializer.c index b4cdac6cdf..3cf9175f08 100644 --- a/ext/serializer.c +++ b/ext/serializer.c @@ -28,6 +28,7 @@ #include #include "arrays.h" +#include "asm_event.h" #include "compat_string.h" #include "ddtrace.h" #include "engine_api.h" @@ -1698,6 +1699,12 @@ void ddtrace_serialize_span_to_array(ddtrace_span_data *span, zval *array) { zend_hash_str_del(meta, ZEND_STRL("operation.name")); } + zval *asm_event = NULL; + if (get_global_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED()) { + asm_event = zend_hash_str_find(meta, ZEND_STRL(DD_TAG_P_APPSEC)); + } + bool is_standalone_appsec_span = asm_event ? Z_TYPE_P(asm_event) == IS_STRING && strncmp(Z_STRVAL_P(asm_event), "1", sizeof("1") - 1) == 0 : 0; + _serialize_meta(el, span, Z_TYPE_P(prop_service) > IS_NULL ? Z_STR(prop_service_as_string) : ZSTR_EMPTY_ALLOC()); zval metrics_zv; @@ -1712,7 +1719,14 @@ void ddtrace_serialize_span_to_array(ddtrace_span_data *span, zval *array) { if (is_root_span) { if (Z_TYPE_P(&span->root->property_sampling_priority) != IS_UNDEF) { - add_assoc_double(&metrics_zv, "_sampling_priority_v1", zval_get_long(&span->root->property_sampling_priority)); + long sampling_priority = zval_get_long(&span->root->property_sampling_priority); + if (get_global_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED() && !is_standalone_appsec_span) { + sampling_priority = MIN(PRIORITY_SAMPLING_AUTO_KEEP, sampling_priority); + } + add_assoc_double(&metrics_zv, "_sampling_priority_v1", sampling_priority); + } + if(get_global_DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED()) { + add_assoc_long(&metrics_zv, "_dd.apm.enabled", 0); } } diff --git a/ext/standalone_limiter.c b/ext/standalone_limiter.c new file mode 100644 index 0000000000..c3aebc3480 --- /dev/null +++ b/ext/standalone_limiter.c @@ -0,0 +1,61 @@ +#include "standalone_limiter.h" + +#ifndef _WIN32 +#include +#else +#include +#endif + +#include + +#include "ddtrace.h" +#include "sidecar.h" +#include "zend_hrtime.h" + +typedef struct { + /* limit from configuration DD_TRACE_RATE_LIMIT */ + uint32_t limit; + struct { + _Atomic(uint64_t) last_hit; + } window; +} ddtrace_standalone_limiter; + +static ddog_MappedMem_ShmHandle *dd_limiter_mapped_shm; +static ddtrace_standalone_limiter *dd_limiter; + +void ddtrace_standalone_limiter_create() { + uint32_t limit = 1; + + ddog_ShmHandle *shm; + if (!ddtrace_ffi_try("Failed allocating shared memory", ddog_alloc_anon_shm_handle(limit, &shm))) { + return; + } + size_t _size; + if (!ddtrace_ffi_try("Failed mapping shared memory", ddog_map_shm(shm, &dd_limiter_mapped_shm, (void **)&dd_limiter, &_size))) { + ddog_drop_anon_shm_handle(shm); + return; + } + + dd_limiter->limit = limit; + memset(&dd_limiter->window, 0, sizeof(dd_limiter->window)); +} + +static bool tick() { + ZEND_ASSERT(dd_limiter); + + uint64_t timeval = zend_hrtime() / 60000000000; + uint64_t old_time = atomic_exchange(&dd_limiter->window.last_hit, timeval); + + return timeval != old_time; +} + +void ddtrace_standalone_limiter_hit() { tick(); } + +bool ddtrace_standalone_limiter_allow() { return tick(); } + +void ddtrace_standalone_limiter_destroy() { + if (dd_limiter_mapped_shm) { + ddog_drop_anon_shm_handle(ddog_unmap_shm(dd_limiter_mapped_shm)); + dd_limiter = NULL; + } +} \ No newline at end of file diff --git a/ext/standalone_limiter.h b/ext/standalone_limiter.h new file mode 100644 index 0000000000..b51aa2b459 --- /dev/null +++ b/ext/standalone_limiter.h @@ -0,0 +1,11 @@ +#ifndef DDTRACE_STANDALONE_LIMITER_H +#define DDTRACE_STANDALONE_LIMITER_H + +#include + +void ddtrace_standalone_limiter_create(void); +void ddtrace_standalone_limiter_destroy(void); +void ddtrace_standalone_limiter_hit(void); +bool ddtrace_standalone_limiter_allow(void); + +#endif // DDTRACE_STANDALONE_LIMITER_H diff --git a/ext/tracer_tag_propagation/tracer_tag_propagation.c b/ext/tracer_tag_propagation/tracer_tag_propagation.c index d872ce55ff..c88cac765e 100644 --- a/ext/tracer_tag_propagation/tracer_tag_propagation.c +++ b/ext/tracer_tag_propagation/tracer_tag_propagation.c @@ -79,15 +79,45 @@ void ddtrace_add_tracer_tags_from_array(zend_array *array, zend_array *root_meta ZEND_HASH_FOREACH_END(); } -void ddtrace_get_propagated_tags(zend_array *tags) { +static zend_array *ddtrace_get_propagated() { zend_array *propagated = &DDTRACE_G(propagated_root_span_tags); + ddtrace_root_span_data *root_span = DDTRACE_G(active_stack)->root_span; + if (root_span) { + propagated = ddtrace_property_array(&root_span->property_propagated_tags); + } + + return propagated; +} + +static zend_array *ddtrace_get_root_meta() { zend_array *root_meta = &DDTRACE_G(root_span_tags_preset); ddtrace_root_span_data *root_span = DDTRACE_G(active_stack)->root_span; if (root_span) { root_meta = ddtrace_property_array(&root_span->property_meta); - propagated = ddtrace_property_array(&root_span->property_propagated_tags); } + return root_meta; +} + +zval *ddtrace_propagated_tags_get_tag(const char *tag) { + if (!tag) { + return NULL; + } + zend_array *propagated = ddtrace_get_propagated(); + zend_array *root_meta = ddtrace_get_root_meta(); + size_t tag_len = strlen(tag); + + if (!zend_hash_str_find(propagated, tag, tag_len)) { + return NULL; + } + + return zend_hash_str_find(root_meta, tag, tag_len); +} + +void ddtrace_get_propagated_tags(zend_array *tags) { + zend_array *propagated = ddtrace_get_propagated(); + zend_array *root_meta = ddtrace_get_root_meta(); + zend_string *tagname; ZEND_HASH_FOREACH_STR_KEY(propagated, tagname) { zval *tag; @@ -100,15 +130,10 @@ void ddtrace_get_propagated_tags(zend_array *tags) { } zend_string *ddtrace_format_root_propagated_tags(void) { - zend_array *propagated = &DDTRACE_G(propagated_root_span_tags); - zend_array *tags = &DDTRACE_G(root_span_tags_preset); - ddtrace_root_span_data *span = DDTRACE_G(active_stack)->root_span; - if (span) { - tags = ddtrace_property_array(&span->property_meta); - propagated = ddtrace_property_array(&span->property_propagated_tags); - } + zend_array *propagated = ddtrace_get_propagated(); + zend_array *root_meta = ddtrace_get_root_meta(); - return ddtrace_format_propagated_tags(propagated, tags); + return ddtrace_format_propagated_tags(propagated, root_meta); } zend_string *ddtrace_format_propagated_tags(zend_array *propagated, zend_array *tags) { @@ -182,3 +207,15 @@ zend_string *ddtrace_format_propagated_tags(zend_array *propagated, zend_array * smart_str_0(&taglist); return taglist.s; } + +void ddtrace_add_propagated_tag(zend_string *key, zval *value) { + zend_array *propagated = ddtrace_get_propagated(); + zend_array *root_meta = ddtrace_get_root_meta(); + + zval tagstr; + ddtrace_convert_to_string(&tagstr, value); + zend_hash_update(root_meta, key, &tagstr); + zend_hash_add_empty_element(propagated, key); +} + +DDTRACE_PUBLIC void ddtrace_add_propagated_tag_on_span_zobj(zend_string *key, zval *value) { ddtrace_add_propagated_tag(key, value); } diff --git a/ext/tracer_tag_propagation/tracer_tag_propagation.h b/ext/tracer_tag_propagation/tracer_tag_propagation.h index 657b764fe9..7af7c58e0c 100644 --- a/ext/tracer_tag_propagation/tracer_tag_propagation.h +++ b/ext/tracer_tag_propagation/tracer_tag_propagation.h @@ -3,10 +3,15 @@ #include +#include "../ddtrace_export.h" + void ddtrace_clean_tracer_tags(zend_array *root_meta, zend_array *propagated_tags); void ddtrace_add_tracer_tags_from_header(zend_string *headerstr, zend_array *root_meta, zend_array *propagated_tags); void ddtrace_add_tracer_tags_from_array(zend_array *array, zend_array *root_meta, zend_array *propagated_tags); +DDTRACE_PUBLIC void ddtrace_add_propagated_tag_on_span_zobj(zend_string *key, zval *value); +void ddtrace_add_propagated_tag(zend_string *key, zval *value); +zval *ddtrace_propagated_tags_get_tag(const char *tag); void ddtrace_get_propagated_tags(zend_array *tags); zend_string *ddtrace_format_root_propagated_tags(void); zend_string *ddtrace_format_propagated_tags(zend_array *propagated, zend_array *tags); diff --git a/tests/ext/background-sender/agent_sampling-standalone-asm_01.phpt b/tests/ext/background-sender/agent_sampling-standalone-asm_01.phpt new file mode 100644 index 0000000000..c1f1cd2c32 --- /dev/null +++ b/tests/ext/background-sender/agent_sampling-standalone-asm_01.phpt @@ -0,0 +1,53 @@ +--TEST-- +Sample rate is changed to 0 after first call during a minute when STANDALONE ASM is enabled and no asm events +--SKIPIF-- + +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 +--INI-- +datadog.trace.agent_test_session_token=background-sender/agent_samplingc +--FILE-- +waitForDataAndReplay()["body"], true); + $spans = $root["chunks"][0]["spans"] ?? $root[0]; + return $spans[0]["metrics"]["_sampling_priority_v1"]; +}; + +\DDTrace\start_span(); +\DDTrace\close_span(); +echo "First call it is used as heartbeat: {$get_sampling()}\n"; + +dd_trace_internal_fn("synchronous_flush"); + +\DDTrace\start_span(); +\DDTrace\close_span(); +echo "Any other call in a minute is set to auto reject: {$get_sampling()}\n"; + +// reset it for other tests +dd_trace_internal_fn("synchronous_flush"); + +\DDTrace\start_span(); +\DDTrace\close_span(); +echo "This one is also set to auto reject: {$get_sampling()}\n"; + +?> +--EXPECTF-- +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +First call it is used as heartbeat: 1 +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +Any other call in a minute is set to auto reject: 0 +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +This one is also set to auto reject: 0 +[ddtrace] [info] No finished traces to be sent to the agent diff --git a/tests/ext/background-sender/agent_sampling-standalone-asm_02.phpt b/tests/ext/background-sender/agent_sampling-standalone-asm_02.phpt new file mode 100644 index 0000000000..7fb1273e27 --- /dev/null +++ b/tests/ext/background-sender/agent_sampling-standalone-asm_02.phpt @@ -0,0 +1,55 @@ +--TEST-- +Sample rate is not changed to 0 after first call during a minute when STANDALONE ASM is enabled and there is asm events +--SKIPIF-- + +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 +--INI-- +datadog.trace.agent_test_session_token=background-sender/agent_samplingb +--FILE-- +waitForDataAndReplay()["body"], true); + $spans = $root["chunks"][0]["spans"] ?? $root[0]; + return $spans[0]["metrics"]["_sampling_priority_v1"]; +}; + +\DDTrace\start_span(); +\DDTrace\close_span(); +echo "First call it is used as heartbeat: {$get_sampling()}\n"; + +dd_trace_internal_fn("synchronous_flush"); + +\DDTrace\start_span(); +DDTrace\Testing\emit_asm_event(); +\DDTrace\close_span(); +echo "This call has the same sample rate: {$get_sampling()}\n"; + +// reset it for other tests +dd_trace_internal_fn("synchronous_flush"); + +\DDTrace\start_span(); +DDTrace\Testing\emit_asm_event(); +\DDTrace\close_span(); +echo "This call also has the same sample rate: {$get_sampling()}\n"; + +?> +--EXPECTF-- +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +First call it is used as heartbeat: 1 +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +This call has the same sample rate: 2 +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +This call also has the same sample rate: 2 +[ddtrace] [info] No finished traces to be sent to the agent diff --git a/tests/ext/background-sender/agent_sampling-standalone-asm_03.phpt b/tests/ext/background-sender/agent_sampling-standalone-asm_03.phpt new file mode 100644 index 0000000000..2aceb7cd46 --- /dev/null +++ b/tests/ext/background-sender/agent_sampling-standalone-asm_03.phpt @@ -0,0 +1,58 @@ +--TEST-- +Sample rate is not changed to 0 after first call during a minute when there is appsec upstream +--SKIPIF-- + +--ENV-- +DD_TRACE_LOG_LEVEL=info,startup=off +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_AGENT_FLUSH_INTERVAL=333 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_INSTRUMENTATION_TELEMETRY_ENABLED=0 +DD_TRACE_SIDECAR_TRACE_SENDER=0 +DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 +HTTP_X_DATADOG_TRACE_ID=42 +HTTP_X_DATADOG_PARENT_ID=10 +HTTP_X_DATADOG_ORIGIN=datadog +HTTP_X_DATADOG_SAMPLING_PRIORITY=3 +HTTP_X_DATADOG_TAGS=_dd.p.appsec=1 +--INI-- +datadog.trace.agent_test_session_token=background-sender/agent_samplinga +--FILE-- +waitForDataAndReplay()["body"], true); + $spans = $root["chunks"][0]["spans"] ?? $root[0]; + return $spans[0]["metrics"]["_sampling_priority_v1"]; +}; + +\DDTrace\start_span(); +\DDTrace\close_span(); +echo "First call it is used as heartbeat: {$get_sampling()}\n"; + +dd_trace_internal_fn("synchronous_flush"); + +\DDTrace\start_span(); +\DDTrace\close_span(); +echo "This call has the same sample rate: {$get_sampling()}\n"; + +// reset it for other tests +dd_trace_internal_fn("synchronous_flush"); + +\DDTrace\start_span(); +\DDTrace\close_span(); +echo "This call also has the same sample rate: {$get_sampling()}\n"; + +?> +--EXPECTF-- +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +First call it is used as heartbeat: 3 +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +This call has the same sample rate: 3 +[ddtrace] [info] Flushing trace of size 1 to send-queue for http://request-replayer:80 +This call also has the same sample rate: 3 +[ddtrace] [info] No finished traces to be sent to the agent diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt new file mode 100644 index 0000000000..7b0dcdea60 --- /dev/null +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_01.phpt @@ -0,0 +1,105 @@ +--TEST-- +Sampling priority is changed to user keep if no asm upstream and asm standalone enabled. Also apm disabled tag is added +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +HTTP_X_DATADOG_TRACE_ID=42 +HTTP_X_DATADOG_PARENT_ID=10 +HTTP_X_DATADOG_ORIGIN=datadog +HTTP_X_DATADOG_SAMPLING_PRIORITY=3 +HTTP_X_DATADOG_TAGS=_dd.p.custom_tag=inherited,_dd.p.dropped,_dd.p.other_tag=also,_dd.p.drop +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 +--FILE-- +name = 'outer'; +$inner = DDTrace\start_span(); +$inner->name = 'inner'; + +DDTrace\close_span(); +DDTrace\close_span(); + +var_dump(dd_trace_serialize_closed_spans()); + +?> +--EXPECTF-- +array(2) { + [0]=> + array(11) { + ["trace_id"]=> + string(2) "42" + ["span_id"]=> + string(%d) "%d" + ["parent_id"]=> + string(2) "10" + ["start"]=> + int(%d) + ["duration"]=> + int(%d) + ["name"]=> + string(5) "outer" + ["resource"]=> + string(5) "outer" + ["service"]=> + string(39) "distributed_trace_asm_standalone_01.php" + ["type"]=> + string(3) "cli" + ["meta"]=> + array(6) { + ["_dd.p.custom_tag"]=> + string(9) "inherited" + ["_dd.propagation_error"]=> + string(14) "decoding_error" + ["_dd.p.other_tag"]=> + string(4) "also" + ["_dd.p.dm"]=> + string(2) "-0" + ["runtime-id"]=> + string(36) "%s" + ["_dd.origin"]=> + string(7) "datadog" + } + ["metrics"]=> + array(6) { + ["process_id"]=> + float(%f) + ["_sampling_priority_v1"]=> + float(1) + ["_dd.apm.enabled"]=> + int(0) + ["php.compilation.total_time_ms"]=> + float(%f) + ["php.memory.peak_usage_bytes"]=> + float(%f) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) + } + } + [1]=> + array(10) { + ["trace_id"]=> + string(2) "42" + ["span_id"]=> + string(%d) "%d" + ["parent_id"]=> + string(%d) "%d" + ["start"]=> + int(%d) + ["duration"]=> + int(%d) + ["name"]=> + string(5) "inner" + ["resource"]=> + string(5) "inner" + ["service"]=> + string(39) "distributed_trace_asm_standalone_01.php" + ["type"]=> + string(3) "cli" + ["meta"]=> + array(1) { + ["_dd.origin"]=> + string(7) "datadog" + } + } +} diff --git a/tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt new file mode 100644 index 0000000000..4d9230ec44 --- /dev/null +++ b/tests/ext/distributed_tracing/distributed_trace_asm_standalone_02.phpt @@ -0,0 +1,101 @@ +--TEST-- +Sampling priority is kept from distributed when asm upstream and asm standalone enabled +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +HTTP_X_DATADOG_TRACE_ID=42 +HTTP_X_DATADOG_PARENT_ID=10 +HTTP_X_DATADOG_ORIGIN=datadog +HTTP_X_DATADOG_SAMPLING_PRIORITY=3 +HTTP_X_DATADOG_TAGS=_dd.p.appsec=1 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 +--FILE-- +name = 'outer'; +$inner = DDTrace\start_span(); +$inner->name = 'inner'; + +DDTrace\close_span(); +DDTrace\close_span(); + +var_dump(dd_trace_serialize_closed_spans()); + +?> +--EXPECTF-- +array(2) { + [0]=> + array(11) { + ["trace_id"]=> + string(2) "42" + ["span_id"]=> + string(%d) "%d" + ["parent_id"]=> + string(2) "10" + ["start"]=> + int(%d) + ["duration"]=> + int(%d) + ["name"]=> + string(5) "outer" + ["resource"]=> + string(5) "outer" + ["service"]=> + string(39) "distributed_trace_asm_standalone_02.php" + ["type"]=> + string(3) "cli" + ["meta"]=> + array(4) { + ["_dd.p.appsec"]=> + string(1) "1" + ["_dd.p.dm"]=> + string(2) "-0" + ["runtime-id"]=> + string(36) "%s" + ["_dd.origin"]=> + string(7) "datadog" + } + ["metrics"]=> + array(6) { + ["process_id"]=> + float(%f) + ["_sampling_priority_v1"]=> + float(3) + ["_dd.apm.enabled"]=> + int(0) + ["php.compilation.total_time_ms"]=> + float(%f) + ["php.memory.peak_usage_bytes"]=> + float(%f) + ["php.memory.peak_real_usage_bytes"]=> + float(%f) + } + } + [1]=> + array(10) { + ["trace_id"]=> + string(2) "42" + ["span_id"]=> + string(%d) "%d" + ["parent_id"]=> + string(%d) "%d" + ["start"]=> + int(%d) + ["duration"]=> + int(%d) + ["name"]=> + string(5) "inner" + ["resource"]=> + string(5) "inner" + ["service"]=> + string(39) "distributed_trace_asm_standalone_02.php" + ["type"]=> + string(3) "cli" + ["meta"]=> + array(1) { + ["_dd.origin"]=> + string(7) "datadog" + } + } +} diff --git a/tests/ext/integrations/curl/distributed_tracing_curl_propagate_asm_event.phpt b/tests/ext/integrations/curl/distributed_tracing_curl_propagate_asm_event.phpt new file mode 100644 index 0000000000..b354b00185 --- /dev/null +++ b/tests/ext/integrations/curl/distributed_tracing_curl_propagate_asm_event.phpt @@ -0,0 +1,40 @@ +--TEST-- +Distributed tracing header tags propagate asm events with curl_exec() +--SKIPIF-- + + +--ENV-- +DD_TRACE_TRACED_INTERNAL_FUNCTIONS=curl_exec +HTTP_X_DATADOG_TRACE_ID=42 +--FILE-- +meta; +unset($meta["to_remove"]); +$meta["foo"] = "buzz"; + +$span = DDTrace\start_span(); +$span->service = "dd"; + +DDTrace\set_priority_sampling(DD_TRACE_PRIORITY_SAMPLING_USER_KEEP); + + +DDTrace\Testing\emit_asm_event(); +dt_dump_headers_from_httpbin(query_headers(), ['x-datadog-tags']); + +?> +--EXPECT-- +x-datadog-tags: _dd.p.appsec=1,_dd.p.dm=-5 diff --git a/tests/ext/limiter/003-limiter-with-asm-standalone.phpt b/tests/ext/limiter/003-limiter-with-asm-standalone.phpt new file mode 100644 index 0000000000..b3f3296700 --- /dev/null +++ b/tests/ext/limiter/003-limiter-with-asm-standalone.phpt @@ -0,0 +1,43 @@ +--TEST-- +rate limiter always allow when DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED enabled +--SKIPIF-- + +--ENV-- +DD_TRACE_AUTO_FLUSH_ENABLED=0 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_TRACE_RATE_LIMIT=10 +DD_TRACE_SAMPLE_RATE=1 +DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 +--FILE-- + 20) { + break; + } + + if (--$loopBreak < 0) { + echo "No 20 spans were sampled.\n"; + break; # avoid infinite loop with DD_TRACE_ENABLED=0 + } +} + +var_dump(count($spans)); +?> +--EXPECT-- +int(21) diff --git a/tests/ext/priority_sampling/asm-standalone.phpt b/tests/ext/priority_sampling/asm-standalone.phpt new file mode 100644 index 0000000000..665b5ee8b8 --- /dev/null +++ b/tests/ext/priority_sampling/asm-standalone.phpt @@ -0,0 +1,18 @@ +--TEST-- +priority_sampling is ignored when asm standalone is enabled +--ENV-- +DD_TRACE_SAMPLING_RULES=[{"sample_rate": 0.3}] +DD_TRACE_GENERATE_ROOT_SPAN=1 +DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED=1 +--FILE-- +metrics["_dd.rule_psr"]) ? "This should not be present": "Missing"); +echo "_dd.p.dm = ", isset($root->meta["_dd.p.dm"]) ? $root->meta["_dd.p.dm"] : "-", "\n"; +?> +--EXPECT-- +string(7) "Missing" +_dd.p.dm = -0