datadog 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -1
- data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +3 -3
- data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +57 -18
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +93 -106
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +8 -2
- data/ext/datadog_profiling_native_extension/extconf.rb +8 -8
- data/ext/datadog_profiling_native_extension/heap_recorder.c +174 -28
- data/ext/datadog_profiling_native_extension/heap_recorder.h +11 -0
- data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +1 -1
- data/ext/datadog_profiling_native_extension/private_vm_api_access.c +1 -1
- data/ext/datadog_profiling_native_extension/ruby_helpers.c +14 -11
- data/ext/datadog_profiling_native_extension/stack_recorder.c +58 -22
- data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -0
- data/ext/libdatadog_api/crashtracker.c +3 -5
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/configuration/settings.rb +8 -0
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +1 -5
- data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +7 -20
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -15
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +6 -18
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +7 -20
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +5 -18
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +3 -5
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +5 -18
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +6 -10
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +7 -20
- data/lib/datadog/appsec/event.rb +24 -0
- data/lib/datadog/appsec/ext.rb +4 -0
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +3 -5
- data/lib/datadog/appsec/monitor/reactive/set_user.rb +7 -20
- data/lib/datadog/appsec/processor/context.rb +107 -0
- data/lib/datadog/appsec/processor.rb +7 -71
- data/lib/datadog/appsec/scope.rb +1 -4
- data/lib/datadog/appsec/utils/trace_operation.rb +15 -0
- data/lib/datadog/appsec/utils.rb +2 -0
- data/lib/datadog/appsec.rb +1 -0
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +26 -25
- data/lib/datadog/core/configuration/settings.rb +12 -0
- data/lib/datadog/core/configuration.rb +1 -3
- data/lib/datadog/core/crashtracking/component.rb +8 -5
- data/lib/datadog/core/environment/yjit.rb +5 -0
- data/lib/datadog/core/remote/transport/http.rb +5 -0
- data/lib/datadog/core/remote/worker.rb +1 -1
- data/lib/datadog/core/runtime/ext.rb +1 -0
- data/lib/datadog/core/runtime/metrics.rb +4 -0
- data/lib/datadog/core/semaphore.rb +35 -0
- data/lib/datadog/core/telemetry/logging.rb +10 -10
- data/lib/datadog/core/transport/ext.rb +1 -0
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/di/code_tracker.rb +11 -13
- data/lib/datadog/di/instrumenter.rb +301 -0
- data/lib/datadog/di/probe.rb +29 -0
- data/lib/datadog/di/probe_builder.rb +7 -1
- data/lib/datadog/di/probe_notification_builder.rb +207 -0
- data/lib/datadog/di/probe_notifier_worker.rb +244 -0
- data/lib/datadog/di/serializer.rb +23 -1
- data/lib/datadog/di/transport.rb +67 -0
- data/lib/datadog/di/utils.rb +39 -0
- data/lib/datadog/di.rb +43 -0
- data/lib/datadog/profiling/collectors/thread_context.rb +9 -11
- data/lib/datadog/profiling/component.rb +1 -0
- data/lib/datadog/profiling/stack_recorder.rb +37 -9
- data/lib/datadog/tracing/component.rb +13 -0
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -0
- data/lib/datadog/tracing/contrib/excon/middleware.rb +3 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +3 -0
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -2
- data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +9 -0
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +4 -0
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +4 -0
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +4 -0
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +3 -0
- data/lib/datadog/tracing/sampling/rule_sampler.rb +6 -4
- data/lib/datadog/tracing/tracer.rb +15 -10
- data/lib/datadog/tracing/transport/http.rb +4 -0
- data/lib/datadog/tracing/workers.rb +1 -1
- data/lib/datadog/tracing/writer.rb +26 -28
- data/lib/datadog/version.rb +1 -1
- metadata +22 -14
@@ -25,30 +25,17 @@ module Datadog
|
|
25
25
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
26
26
|
arguments = values[0]
|
27
27
|
|
28
|
-
|
28
|
+
persistent_data = {
|
29
29
|
'graphql.server.all_resolvers' => arguments
|
30
30
|
}
|
31
31
|
|
32
32
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
33
|
-
result = waf_context.run(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
40
|
-
|
41
|
-
yield result
|
42
|
-
throw(:block, true) unless result.actions.empty?
|
43
|
-
when :ok
|
44
|
-
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
45
|
-
when :invalid_call
|
46
|
-
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
47
|
-
when :invalid_rule, :invalid_flow, :no_rule
|
48
|
-
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
49
|
-
else
|
50
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
51
|
-
end
|
33
|
+
result = waf_context.run(persistent_data, {}, waf_timeout)
|
34
|
+
|
35
|
+
next if result.status != :match
|
36
|
+
|
37
|
+
yield result
|
38
|
+
throw(:block, true) unless result.actions.empty?
|
52
39
|
end
|
53
40
|
end
|
54
41
|
end
|
@@ -41,11 +41,9 @@ module Datadog
|
|
41
41
|
actions: result.actions
|
42
42
|
}
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
|
44
|
+
# We want to keep the trace in case of security event
|
45
|
+
scope.trace.keep! if scope.trace
|
46
|
+
Datadog::AppSec::Event.tag_and_keep!(scope, result)
|
49
47
|
scope.processor_context.events << event
|
50
48
|
end
|
51
49
|
end
|
@@ -85,11 +83,9 @@ module Datadog
|
|
85
83
|
actions: result.actions
|
86
84
|
}
|
87
85
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
-
|
86
|
+
# We want to keep the trace in case of security event
|
87
|
+
scope.trace.keep! if scope.trace
|
88
|
+
Datadog::AppSec::Event.tag_and_keep!(scope, result)
|
93
89
|
scope.processor_context.events << event
|
94
90
|
end
|
95
91
|
end
|
@@ -129,11 +125,9 @@ module Datadog
|
|
129
125
|
actions: result.actions
|
130
126
|
}
|
131
127
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
end
|
136
|
-
|
128
|
+
# We want to keep the trace in case of security event
|
129
|
+
scope.trace.keep! if scope.trace
|
130
|
+
Datadog::AppSec::Event.tag_and_keep!(scope, result)
|
137
131
|
scope.processor_context.events << event
|
138
132
|
end
|
139
133
|
end
|
@@ -33,6 +33,7 @@ module Datadog
|
|
33
33
|
def self.subscribe(op, waf_context)
|
34
34
|
op.subscribe(*ADDRESSES) do |*values|
|
35
35
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
36
|
+
|
36
37
|
headers = values[0]
|
37
38
|
headers_no_cookies = headers.dup.tap { |h| h.delete('cookie') }
|
38
39
|
uri_raw = values[1]
|
@@ -41,7 +42,7 @@ module Datadog
|
|
41
42
|
client_ip = values[4]
|
42
43
|
request_method = values[5]
|
43
44
|
|
44
|
-
|
45
|
+
persistent_data = {
|
45
46
|
'server.request.cookies' => cookies,
|
46
47
|
'server.request.query' => query,
|
47
48
|
'server.request.uri.raw' => uri_raw,
|
@@ -52,25 +53,12 @@ module Datadog
|
|
52
53
|
}
|
53
54
|
|
54
55
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
55
|
-
result = waf_context.run(
|
56
|
-
|
57
|
-
Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
|
56
|
+
result = waf_context.run(persistent_data, {}, waf_timeout)
|
58
57
|
|
59
|
-
|
60
|
-
when :match
|
61
|
-
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
58
|
+
next if result.status != :match
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
when :ok
|
66
|
-
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
67
|
-
when :invalid_call
|
68
|
-
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
69
|
-
when :invalid_rule, :invalid_flow, :no_rule
|
70
|
-
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
71
|
-
else
|
72
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
73
|
-
end
|
60
|
+
yield result
|
61
|
+
throw(:block, true) unless result.actions.empty?
|
74
62
|
end
|
75
63
|
end
|
76
64
|
end
|
@@ -26,30 +26,17 @@ module Datadog
|
|
26
26
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
27
27
|
body = values[0]
|
28
28
|
|
29
|
-
|
29
|
+
persistent_data = {
|
30
30
|
'server.request.body' => body,
|
31
31
|
}
|
32
32
|
|
33
33
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
34
|
-
result = waf_context.run(
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
41
|
-
|
42
|
-
yield result
|
43
|
-
throw(:block, true) unless result.actions.empty?
|
44
|
-
when :ok
|
45
|
-
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
46
|
-
when :invalid_call
|
47
|
-
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
48
|
-
when :invalid_rule, :invalid_flow, :no_rule
|
49
|
-
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
50
|
-
else
|
51
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
52
|
-
end
|
34
|
+
result = waf_context.run(persistent_data, {}, waf_timeout)
|
35
|
+
|
36
|
+
next if result.status != :match
|
37
|
+
|
38
|
+
yield result
|
39
|
+
throw(:block, true) unless result.actions.empty?
|
53
40
|
end
|
54
41
|
end
|
55
42
|
end
|
@@ -30,32 +30,19 @@ module Datadog
|
|
30
30
|
response_headers = values[1]
|
31
31
|
response_headers_no_cookies = response_headers.dup.tap { |h| h.delete('set-cookie') }
|
32
32
|
|
33
|
-
|
33
|
+
persistent_data = {
|
34
34
|
'server.response.status' => response_status.to_s,
|
35
35
|
'server.response.headers' => response_headers,
|
36
36
|
'server.response.headers.no_cookies' => response_headers_no_cookies,
|
37
37
|
}
|
38
38
|
|
39
39
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
40
|
-
result = waf_context.run(
|
40
|
+
result = waf_context.run(persistent_data, {}, waf_timeout)
|
41
41
|
|
42
|
-
|
42
|
+
next if result.status != :match
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
47
|
-
|
48
|
-
yield result
|
49
|
-
throw(:block, true) unless result.actions.empty?
|
50
|
-
when :ok
|
51
|
-
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
52
|
-
when :invalid_call
|
53
|
-
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
54
|
-
when :invalid_rule, :invalid_flow, :no_rule
|
55
|
-
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
56
|
-
else
|
57
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
58
|
-
end
|
44
|
+
yield result
|
45
|
+
throw(:block, true) unless result.actions.empty?
|
59
46
|
end
|
60
47
|
end
|
61
48
|
end
|
@@ -150,7 +150,9 @@ module Datadog
|
|
150
150
|
|
151
151
|
return unless trace && span
|
152
152
|
|
153
|
-
span.
|
153
|
+
span.set_metric(Datadog::AppSec::Ext::TAG_APPSEC_ENABLED, 1)
|
154
|
+
# We add this tag when ASM standalone is enabled to make sure we don't bill APM
|
155
|
+
span.set_metric(Datadog::AppSec::Ext::TAG_APM_ENABLED, 0) if Datadog.configuration.appsec.standalone.enabled
|
154
156
|
span.set_tag('_dd.runtime_family', 'ruby')
|
155
157
|
span.set_tag('_dd.appsec.waf.version', Datadog::AppSec::WAF::VERSION::BASE_STRING)
|
156
158
|
|
@@ -38,11 +38,9 @@ module Datadog
|
|
38
38
|
actions: result.actions
|
39
39
|
}
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
|
41
|
+
# We want to keep the trace in case of security event
|
42
|
+
scope.trace.keep! if scope.trace
|
43
|
+
Datadog::AppSec::Event.tag_and_keep!(scope, result)
|
46
44
|
scope.processor_context.events << event
|
47
45
|
end
|
48
46
|
end
|
@@ -31,31 +31,18 @@ module Datadog
|
|
31
31
|
body = values[0]
|
32
32
|
path_params = values[1]
|
33
33
|
|
34
|
-
|
34
|
+
persistent_data = {
|
35
35
|
'server.request.body' => body,
|
36
36
|
'server.request.path_params' => path_params,
|
37
37
|
}
|
38
38
|
|
39
39
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
40
|
-
result = waf_context.run(
|
40
|
+
result = waf_context.run(persistent_data, {}, waf_timeout)
|
41
41
|
|
42
|
-
|
42
|
+
next if result.status != :match
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
47
|
-
|
48
|
-
yield result
|
49
|
-
throw(:block, true) unless result.actions.empty?
|
50
|
-
when :ok
|
51
|
-
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
52
|
-
when :invalid_call
|
53
|
-
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
54
|
-
when :invalid_rule, :invalid_flow, :no_rule
|
55
|
-
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
56
|
-
else
|
57
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
58
|
-
end
|
44
|
+
yield result
|
45
|
+
throw(:block, true) unless result.actions.empty?
|
59
46
|
end
|
60
47
|
end
|
61
48
|
end
|
@@ -40,11 +40,9 @@ module Datadog
|
|
40
40
|
actions: result.actions
|
41
41
|
}
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
43
|
+
# We want to keep the trace in case of security event
|
44
|
+
scope.trace.keep! if scope.trace
|
45
|
+
Datadog::AppSec::Event.tag_and_keep!(scope, result)
|
48
46
|
scope.processor_context.events << event
|
49
47
|
end
|
50
48
|
end
|
@@ -84,11 +82,9 @@ module Datadog
|
|
84
82
|
actions: result.actions
|
85
83
|
}
|
86
84
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
|
85
|
+
# We want to keep the trace in case of security event
|
86
|
+
scope.trace.keep! if scope.trace
|
87
|
+
Datadog::AppSec::Event.tag_and_keep!(scope, result)
|
92
88
|
scope.processor_context.events << event
|
93
89
|
end
|
94
90
|
end
|
@@ -27,30 +27,17 @@ module Datadog
|
|
27
27
|
Datadog.logger.debug { "reacted to #{ADDRESSES.inspect}: #{values.inspect}" }
|
28
28
|
path_params = values[0]
|
29
29
|
|
30
|
-
|
30
|
+
persistent_data = {
|
31
31
|
'server.request.path_params' => path_params,
|
32
32
|
}
|
33
33
|
|
34
34
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
35
|
-
result = waf_context.run(
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
42
|
-
|
43
|
-
yield result
|
44
|
-
throw(:block, true) unless result.actions.empty?
|
45
|
-
when :ok
|
46
|
-
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
47
|
-
when :invalid_call
|
48
|
-
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
49
|
-
when :invalid_rule, :invalid_flow, :no_rule
|
50
|
-
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
51
|
-
else
|
52
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
53
|
-
end
|
35
|
+
result = waf_context.run(persistent_data, {}, waf_timeout)
|
36
|
+
|
37
|
+
next if result.status != :match
|
38
|
+
|
39
|
+
yield result
|
40
|
+
throw(:block, true) unless result.actions.empty?
|
54
41
|
end
|
55
42
|
end
|
56
43
|
end
|
data/lib/datadog/appsec/event.rb
CHANGED
@@ -137,6 +137,18 @@ module Datadog
|
|
137
137
|
end
|
138
138
|
# rubocop:enable Metrics/MethodLength
|
139
139
|
|
140
|
+
def tag_and_keep!(scope, waf_result)
|
141
|
+
# We want to keep the trace in case of security event
|
142
|
+
scope.trace.keep! if scope.trace
|
143
|
+
|
144
|
+
if scope.service_entry_span
|
145
|
+
scope.service_entry_span.set_tag('appsec.blocked', 'true') if waf_result.actions.include?('block')
|
146
|
+
scope.service_entry_span.set_tag('appsec.event', 'true')
|
147
|
+
end
|
148
|
+
|
149
|
+
add_distributed_tags(scope.trace)
|
150
|
+
end
|
151
|
+
|
140
152
|
private
|
141
153
|
|
142
154
|
def compressed_and_base64_encoded(value)
|
@@ -165,6 +177,18 @@ module Datadog
|
|
165
177
|
gz.close
|
166
178
|
sio.string
|
167
179
|
end
|
180
|
+
|
181
|
+
# Propagate to downstream services the information that the current distributed trace is
|
182
|
+
# containing at least one ASM security event.
|
183
|
+
def add_distributed_tags(trace)
|
184
|
+
return unless trace
|
185
|
+
|
186
|
+
trace.set_tag(
|
187
|
+
Datadog::Tracing::Metadata::Ext::Distributed::TAG_DECISION_MAKER,
|
188
|
+
Datadog::Tracing::Sampling::Ext::Decision::ASM
|
189
|
+
)
|
190
|
+
trace.set_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT, '1')
|
191
|
+
end
|
168
192
|
end
|
169
193
|
end
|
170
194
|
end
|
data/lib/datadog/appsec/ext.rb
CHANGED
@@ -35,11 +35,9 @@ module Datadog
|
|
35
35
|
actions: result.actions
|
36
36
|
}
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
|
38
|
+
# We want to keep the trace in case of security event
|
39
|
+
scope.trace.keep! if scope.trace
|
40
|
+
Datadog::AppSec::Event.tag_and_keep!(scope, result)
|
43
41
|
scope.processor_context.events << event
|
44
42
|
end
|
45
43
|
end
|
@@ -25,30 +25,17 @@ module Datadog
|
|
25
25
|
|
26
26
|
user_id = values[0]
|
27
27
|
|
28
|
-
|
28
|
+
persistent_data = {
|
29
29
|
'usr.id' => user_id,
|
30
30
|
}
|
31
31
|
|
32
32
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
33
|
-
result = waf_context.run(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
Datadog.logger.debug { "WAF: #{result.inspect}" }
|
40
|
-
|
41
|
-
yield result
|
42
|
-
throw(:block, true) unless result.actions.empty?
|
43
|
-
when :ok
|
44
|
-
Datadog.logger.debug { "WAF OK: #{result.inspect}" }
|
45
|
-
when :invalid_call
|
46
|
-
Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
|
47
|
-
when :invalid_rule, :invalid_flow, :no_rule
|
48
|
-
Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
|
49
|
-
else
|
50
|
-
Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
|
51
|
-
end
|
33
|
+
result = waf_context.run(persistent_data, {}, waf_timeout)
|
34
|
+
|
35
|
+
next if result.status != :match
|
36
|
+
|
37
|
+
yield result
|
38
|
+
throw(:block, true) unless result.actions.empty?
|
52
39
|
end
|
53
40
|
end
|
54
41
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module AppSec
|
5
|
+
class Processor
|
6
|
+
# Context manages a sequence of runs
|
7
|
+
class Context
|
8
|
+
LIBDDWAF_SUCCESSFUL_EXECUTION_CODES = [:ok, :match].freeze
|
9
|
+
|
10
|
+
attr_reader :time_ns, :time_ext_ns, :timeouts, :events
|
11
|
+
|
12
|
+
def initialize(handle, telemetry:)
|
13
|
+
@context = WAF::Context.new(handle)
|
14
|
+
@telemetry = telemetry
|
15
|
+
|
16
|
+
@time_ns = 0.0
|
17
|
+
@time_ext_ns = 0.0
|
18
|
+
@timeouts = 0
|
19
|
+
@events = []
|
20
|
+
@run_mutex = Mutex.new
|
21
|
+
|
22
|
+
@libddwaf_debug_tag = "libddwaf:#{WAF::VERSION::STRING}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def run(persistent_data, ephemeral_data, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
26
|
+
@run_mutex.lock
|
27
|
+
|
28
|
+
start_ns = Core::Utils::Time.get_time(:nanosecond)
|
29
|
+
|
30
|
+
persistent_data.reject! do |_, v|
|
31
|
+
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
32
|
+
|
33
|
+
v.nil? ? true : v.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
ephemeral_data.reject! do |_, v|
|
37
|
+
next false if v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
38
|
+
|
39
|
+
v.nil? ? true : v.empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
_code, result = try_run(persistent_data, ephemeral_data, timeout)
|
43
|
+
|
44
|
+
stop_ns = Core::Utils::Time.get_time(:nanosecond)
|
45
|
+
|
46
|
+
# these updates are not thread safe and should be protected
|
47
|
+
@time_ns += result.total_runtime
|
48
|
+
@time_ext_ns += (stop_ns - start_ns)
|
49
|
+
@timeouts += 1 if result.timeout
|
50
|
+
|
51
|
+
report_execution(result)
|
52
|
+
result
|
53
|
+
ensure
|
54
|
+
@run_mutex.unlock
|
55
|
+
end
|
56
|
+
|
57
|
+
def extract_schema
|
58
|
+
return unless extract_schema?
|
59
|
+
|
60
|
+
input = {
|
61
|
+
'waf.context.processor' => {
|
62
|
+
'extract-schema' => true
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
_code, result = try_run(input, {}, WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
67
|
+
|
68
|
+
report_execution(result)
|
69
|
+
result
|
70
|
+
end
|
71
|
+
|
72
|
+
def finalize
|
73
|
+
@context.finalize
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def try_run(persistent_data, ephemeral_data, timeout)
|
79
|
+
@context.run(persistent_data, ephemeral_data, timeout)
|
80
|
+
rescue WAF::LibDDWAF::Error => e
|
81
|
+
Datadog.logger.debug { "#{@libddwaf_debug_tag} execution error: #{e} backtrace: #{e.backtrace&.first(3)}" }
|
82
|
+
@telemetry.report(e, description: 'libddwaf internal low-level error')
|
83
|
+
|
84
|
+
[:err_internal, WAF::Result.new(:err_internal, [], 0.0, false, [], [])]
|
85
|
+
end
|
86
|
+
|
87
|
+
def report_execution(result)
|
88
|
+
Datadog.logger.debug { "#{@libddwaf_debug_tag} execution timed out: #{result.inspect}" } if result.timeout
|
89
|
+
|
90
|
+
if LIBDDWAF_SUCCESSFUL_EXECUTION_CODES.include?(result.status)
|
91
|
+
Datadog.logger.debug { "#{@libddwaf_debug_tag} execution result: #{result.inspect}" }
|
92
|
+
else
|
93
|
+
message = "#{@libddwaf_debug_tag} execution error: #{result.status.inspect}"
|
94
|
+
|
95
|
+
Datadog.logger.debug { message }
|
96
|
+
@telemetry.error(message)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def extract_schema?
|
101
|
+
Datadog.configuration.appsec.api_security.enabled &&
|
102
|
+
Datadog.configuration.appsec.api_security.sample_rate.sample?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -1,83 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'processor/context'
|
4
|
+
|
3
5
|
module Datadog
|
4
6
|
module AppSec
|
5
7
|
# Processor integrates libddwaf into datadog/appsec
|
6
8
|
class Processor
|
7
|
-
# Context manages a sequence of runs
|
8
|
-
class Context
|
9
|
-
attr_reader :time_ns, :time_ext_ns, :timeouts, :events
|
10
|
-
|
11
|
-
def initialize(processor)
|
12
|
-
@context = Datadog::AppSec::WAF::Context.new(processor.send(:handle))
|
13
|
-
@time_ns = 0.0
|
14
|
-
@time_ext_ns = 0.0
|
15
|
-
@timeouts = 0
|
16
|
-
@events = []
|
17
|
-
@run_mutex = Mutex.new
|
18
|
-
end
|
19
|
-
|
20
|
-
def run(input, timeout = WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
21
|
-
@run_mutex.lock
|
22
|
-
|
23
|
-
start_ns = Core::Utils::Time.get_time(:nanosecond)
|
24
|
-
|
25
|
-
input.reject! do |_, v|
|
26
|
-
case v
|
27
|
-
when TrueClass, FalseClass
|
28
|
-
false
|
29
|
-
else
|
30
|
-
v.nil? ? true : v.empty?
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
_code, res = @context.run(input, timeout)
|
35
|
-
|
36
|
-
stop_ns = Core::Utils::Time.get_time(:nanosecond)
|
37
|
-
|
38
|
-
# these updates are not thread safe and should be protected
|
39
|
-
@time_ns += res.total_runtime
|
40
|
-
@time_ext_ns += (stop_ns - start_ns)
|
41
|
-
@timeouts += 1 if res.timeout
|
42
|
-
|
43
|
-
res
|
44
|
-
ensure
|
45
|
-
@run_mutex.unlock
|
46
|
-
end
|
47
|
-
|
48
|
-
def extract_schema
|
49
|
-
return unless extract_schema?
|
50
|
-
|
51
|
-
input = {
|
52
|
-
'waf.context.processor' => {
|
53
|
-
'extract-schema' => true
|
54
|
-
}
|
55
|
-
}
|
56
|
-
|
57
|
-
_code, res = @context.run(input, WAF::LibDDWAF::DDWAF_RUN_TIMEOUT)
|
58
|
-
|
59
|
-
res
|
60
|
-
end
|
61
|
-
|
62
|
-
def finalize
|
63
|
-
@context.finalize
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def extract_schema?
|
69
|
-
Datadog.configuration.appsec.api_security.enabled &&
|
70
|
-
Datadog.configuration.appsec.api_security.sample_rate.sample?
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
9
|
attr_reader :diagnostics, :addresses
|
75
10
|
|
76
11
|
def initialize(ruleset:, telemetry:)
|
12
|
+
@telemetry = telemetry
|
77
13
|
@diagnostics = nil
|
78
14
|
@addresses = []
|
15
|
+
|
79
16
|
settings = Datadog.configuration.appsec
|
80
|
-
@telemetry = telemetry
|
81
17
|
|
82
18
|
# TODO: Refactor to make it easier to test
|
83
19
|
unless require_libddwaf && libddwaf_provides_waf? && create_waf_handle(settings, ruleset)
|
@@ -93,9 +29,9 @@ module Datadog
|
|
93
29
|
@handle.finalize
|
94
30
|
end
|
95
31
|
|
96
|
-
|
97
|
-
|
98
|
-
|
32
|
+
def new_context
|
33
|
+
Context.new(@handle, telemetry: @telemetry)
|
34
|
+
end
|
99
35
|
|
100
36
|
private
|
101
37
|
|