contrast-agent 4.9.1 → 4.10.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/.rspec +0 -1
- data/.rspec_parallel +6 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.c +0 -1
- data/ext/cs__contrast_patch/cs__contrast_patch.h +0 -2
- data/lib/contrast/agent/assess/contrast_event.rb +0 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +0 -1
- data/lib/contrast/agent/assess/policy/patcher.rb +0 -1
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +0 -2
- data/lib/contrast/agent/assess/policy/preshift.rb +8 -5
- data/lib/contrast/agent/assess/policy/propagation_method.rb +100 -57
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +0 -2
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +31 -11
- data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -2
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +1 -0
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +0 -1
- data/lib/contrast/agent/assess/policy/source_method.rb +13 -17
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +0 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +59 -83
- data/lib/contrast/agent/assess/property/evented.rb +2 -1
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +0 -1
- data/lib/contrast/agent/disable_reaction.rb +1 -1
- data/lib/contrast/agent/exclusion_matcher.rb +0 -4
- data/lib/contrast/agent/inventory/database_config.rb +117 -0
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +5 -4
- data/lib/contrast/agent/inventory/policy/datastores.rb +2 -2
- data/lib/contrast/agent/middleware.rb +1 -0
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +3 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +18 -12
- data/lib/contrast/agent/patching/policy/module_policy.rb +2 -4
- data/lib/contrast/agent/patching/policy/patch.rb +5 -0
- data/lib/contrast/agent/patching/policy/patch_status.rb +3 -7
- data/lib/contrast/agent/patching/policy/patcher.rb +8 -8
- data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -53
- data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +137 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +7 -70
- data/lib/contrast/agent/reaction_processor.rb +1 -1
- data/lib/contrast/agent/request.rb +5 -2
- data/lib/contrast/agent/request_context.rb +19 -22
- data/lib/contrast/agent/static_analysis.rb +1 -1
- data/lib/contrast/agent/tracepoint_hook.rb +6 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +12 -6
- data/lib/contrast/api/communication/service_lifecycle.rb +4 -1
- data/lib/contrast/api/communication/socket_client.rb +4 -4
- data/lib/contrast/api/decorators/agent_startup.rb +4 -4
- data/lib/contrast/api/decorators/application_startup.rb +6 -5
- data/lib/contrast/api/decorators/route_coverage.rb +24 -1
- data/lib/contrast/components/agent.rb +5 -2
- data/lib/contrast/components/assess.rb +6 -3
- data/lib/contrast/components/base.rb +2 -2
- data/lib/contrast/components/config.rb +1 -0
- data/lib/contrast/components/contrast_service.rb +4 -2
- data/lib/contrast/components/logger.rb +13 -8
- data/lib/contrast/components/scope.rb +9 -28
- data/lib/contrast/config/base_configuration.rb +14 -6
- data/lib/contrast/configuration.rb +19 -15
- data/lib/contrast/extension/assess/array.rb +1 -11
- data/lib/contrast/extension/assess/eval_trigger.rb +0 -20
- data/lib/contrast/extension/assess/fiber.rb +0 -11
- data/lib/contrast/extension/assess/hash.rb +0 -10
- data/lib/contrast/extension/assess/kernel.rb +1 -10
- data/lib/contrast/extension/assess/marshal.rb +3 -11
- data/lib/contrast/extension/assess/regexp.rb +0 -11
- data/lib/contrast/extension/assess/string.rb +1 -26
- data/lib/contrast/extension/extension.rb +61 -0
- data/lib/contrast/extension/protect/kernel.rb +0 -10
- data/lib/contrast/framework/grape/support.rb +174 -0
- data/lib/contrast/framework/manager.rb +42 -6
- data/lib/contrast/framework/rack/support.rb +1 -1
- data/lib/contrast/framework/rails/patch/assess_configuration.rb +0 -1
- data/lib/contrast/framework/rails/patch/support.rb +6 -3
- data/lib/contrast/framework/rails/railtie.rb +1 -1
- data/lib/contrast/framework/rails/rewrite/active_record_named.rb +1 -0
- data/lib/contrast/framework/rails/support.rb +60 -13
- data/lib/contrast/framework/sinatra/support.rb +1 -1
- data/lib/contrast/logger/log.rb +89 -15
- data/lib/contrast/utils/io_util.rb +1 -1
- data/lib/contrast/utils/ruby_ast_rewriter.rb +16 -13
- data/lib/contrast/utils/tag_util.rb +2 -1
- data/resources/assess/policy.json +197 -2
- data/resources/deadzone/policy.json +10 -0
- data/ruby-agent.gemspec +10 -1
- metadata +78 -12
- data/lib/contrast/utils/inventory_util.rb +0 -113
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab65fd574ef84fbe339e4f4d4bf340623235a442ecc11d7ba28c6af3c6f04d4d
|
4
|
+
data.tar.gz: 0fa9cc44fe85713ee924101139e615d361de6d906c8f5ff4fdd345a930eee9d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb21ebcad0e772649d16a25d2f00cc057ee10df71638b7bd7cc6a4710a1ded28ce4dca749fa040ba2fb78e992727f4cc5d5f38e1187c363a8ea33a12333fc289
|
7
|
+
data.tar.gz: c3ad4c82a9e25ecb58c0ea906f1170cffdd6811952f9c1d71a6c75166358a37e0ebba40e55e9a7433156a51122b9ca1450bb5a4a2a87f9081a4a4268d9abfdb4
|
data/.rspec
CHANGED
data/.rspec_parallel
ADDED
@@ -437,7 +437,6 @@ void Init_cs__contrast_patch(void) {
|
|
437
437
|
rb_sym_contrast_apply_pre_patch = rb_intern("apply_pre_patch");
|
438
438
|
rb_sym_cs_to_s = rb_intern("to_s");
|
439
439
|
rb_sym_custom_patch = rb_intern("requires_custom_patch?");
|
440
|
-
rb_sym_in_request_context = rb_intern("in_request_context?");
|
441
440
|
rb_sym_info_for = rb_intern("info_for");
|
442
441
|
rb_sym_propagation_node = rb_intern("propagation_node");
|
443
442
|
rb_sym_set_info_for = rb_intern("set_info_for");
|
@@ -28,7 +28,6 @@ module Contrast
|
|
28
28
|
# @attr_reader args [Array<Contrast::Agent::Assess::ContrastObject>] the safe representation of the Arguments
|
29
29
|
# with which the method was invoked
|
30
30
|
class ContrastEvent
|
31
|
-
|
32
31
|
attr_reader :event_id, :policy_node, :stack_trace, :time, :thread, :object, :ret, :args, :tags
|
33
32
|
|
34
33
|
# We need this to track the parent id's of events to build up a flow chart of the finding
|
@@ -10,7 +10,6 @@ module Contrast
|
|
10
10
|
# An extension of Hash that doesn't impact GC of the object being stored by storing its ID as a Key to lookup
|
11
11
|
# and registering a finalizer on the object to remove its entry from the Hash immediately after it's GC'd.
|
12
12
|
class Hash < Hash
|
13
|
-
|
14
13
|
FROZEN_FINALIZED_IDS = Set.new
|
15
14
|
|
16
15
|
def []= key, obj
|
@@ -12,8 +12,6 @@ module Contrast
|
|
12
12
|
# of a file vs data flow, such as the detection of Hardcoded Passwords
|
13
13
|
# or Keys.
|
14
14
|
module PolicyScanner
|
15
|
-
|
16
|
-
|
17
15
|
class << self
|
18
16
|
# Use the given trace_point, built from an :end event, to determine
|
19
17
|
# where the loaded code lives and scan that code for policy
|
@@ -10,7 +10,7 @@ module Contrast
|
|
10
10
|
# caused, we'll need to store the state before the change occurred.
|
11
11
|
class PreShift
|
12
12
|
include Contrast::Components::Logger::InstanceMethods
|
13
|
-
|
13
|
+
extend Contrast::Components::Logger::InstanceMethods
|
14
14
|
|
15
15
|
UNDUPLICABLE_MODULES = [
|
16
16
|
Enumerator # dup'ing results in 'can't copy execution context'
|
@@ -84,12 +84,15 @@ module Contrast
|
|
84
84
|
|
85
85
|
def append_arg_details preshift, args
|
86
86
|
preshift.args = args.dup
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
idx = 0
|
88
|
+
while idx < preshift.args.size
|
89
|
+
original_arg = args[idx]
|
90
|
+
p_arg = preshift.args[idx]
|
91
|
+
idx += 1
|
92
|
+
next if p_arg.__id__ == original_arg.__id__
|
90
93
|
next unless Contrast::Agent::Assess::Tracker.tracked?(original_arg)
|
91
94
|
|
92
|
-
Contrast::Agent::Assess::Tracker.copy(original_arg,
|
95
|
+
Contrast::Agent::Assess::Tracker.copy(original_arg, p_arg)
|
93
96
|
end
|
94
97
|
preshift.arg_lengths = preshift.args.map do |preshift_arg|
|
95
98
|
Contrast::Utils::DuckUtils.quacks_to?(preshift_arg, :length) ? preshift_arg.length : 0
|
@@ -12,14 +12,11 @@ module Contrast
|
|
12
12
|
module Agent
|
13
13
|
module Assess
|
14
14
|
module Policy
|
15
|
-
# This class is responsible for the continuation of traces. A
|
16
|
-
#
|
17
|
-
# general, these methods work on the String class or a holder of
|
18
|
-
# Strings
|
15
|
+
# This class is responsible for the continuation of traces. A Propagator is any method that transforms an
|
16
|
+
# untrusted value. In general, these methods work on the String class or a holder of Strings.
|
19
17
|
module PropagationMethod
|
20
18
|
extend Contrast::Components::Logger::InstanceMethods
|
21
19
|
|
22
|
-
|
23
20
|
APPEND_ACTION = 'APPEND'
|
24
21
|
CENTER_ACTION = 'CENTER'
|
25
22
|
INSERT_ACTION = 'INSERT'
|
@@ -48,19 +45,16 @@ module Contrast
|
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
51
|
-
# @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy]
|
52
|
-
#
|
53
|
-
# @param preshift [Contrast::Agent::Assess::PreShift] The capture
|
54
|
-
#
|
55
|
-
# patched method.
|
48
|
+
# @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] the policy that governs the
|
49
|
+
# patches to this method
|
50
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
51
|
+
# the invocation of the patched method.
|
56
52
|
# @param object [Object] the Object on which the method was invoked
|
57
53
|
# @param ret [Object] the Return of the invoked method
|
58
|
-
# @param args [Array<Object>] the Arguments with which the method
|
59
|
-
# was invoked
|
54
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
60
55
|
# @param block [Block] the Block passed to the original method
|
61
|
-
# @return [Object, nil] the tracked Return or nil if no changes
|
62
|
-
#
|
63
|
-
# not nil
|
56
|
+
# @return [Object, nil] the tracked Return or nil if no changes were made; will replace the return of the
|
57
|
+
# original function if not nil
|
64
58
|
def apply_propagation method_policy, preshift, object, ret, args, block
|
65
59
|
return unless method_policy.propagation_node
|
66
60
|
return unless preshift
|
@@ -86,26 +80,21 @@ module Contrast
|
|
86
80
|
SPLIT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Split
|
87
81
|
}.cs__freeze
|
88
82
|
|
89
|
-
# I lied above. We had to figure out what the target of the
|
90
|
-
#
|
91
|
-
# it
|
92
|
-
# return of the patched function unless it is nil, so be sure
|
93
|
-
# you're returning what you intend.
|
83
|
+
# I lied above. We had to figure out what the target of the propagation was. Now that we know, we'll
|
84
|
+
# actually do things to it. Note that the return of this method will replace the original return of the
|
85
|
+
# patched function unless it is nil, so be sure you're returning what you intend.
|
94
86
|
#
|
95
|
-
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
|
96
|
-
#
|
97
|
-
# @param preshift [Contrast::Agent::Assess::PreShift] The capture
|
98
|
-
#
|
99
|
-
# patched method.
|
87
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
88
|
+
# propagation event.
|
89
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
90
|
+
# the invocation of the patched method.
|
100
91
|
# @param target [Object] the Target to which to propagate.
|
101
92
|
# @param object [Object] the Object on which the method was invoked
|
102
93
|
# @param ret [Object] the Return of the invoked method
|
103
|
-
# @param args [Array<Object>] the Arguments with which the method
|
104
|
-
# was invoked
|
94
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
105
95
|
# @param block [Block] the Block passed to the original method
|
106
|
-
# @return [Object, nil] the tracked Return or nil if no changes
|
107
|
-
#
|
108
|
-
# not nil
|
96
|
+
# @return [Object, nil] the tracked Return or nil if no changes were made; will replace the return of the
|
97
|
+
# original function if not nil
|
109
98
|
def apply_propagator propagation_node, preshift, target, object, ret, args, block
|
110
99
|
return unless propagation_possible?(propagation_node, target)
|
111
100
|
|
@@ -127,13 +116,16 @@ module Contrast
|
|
127
116
|
nil
|
128
117
|
end
|
129
118
|
|
130
|
-
# Custom actions tend to be the more complex of our propagations.
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
119
|
+
# Custom actions tend to be the more complex of our propagations. Often, the method has to make decisions
|
120
|
+
# about the target based on the context with which the method was called. As such, defer determining if the
|
121
|
+
# target is valid to that method.
|
122
|
+
#
|
123
|
+
# In all other cases, a target is valid for propagation if it is not nil
|
134
124
|
#
|
135
|
-
#
|
136
|
-
#
|
125
|
+
# @param target [Object] the thing to which to propagate
|
126
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
127
|
+
# propagation event.
|
128
|
+
# @return [Boolean]
|
137
129
|
def valid_target? target, propagation_node
|
138
130
|
return true if propagation_node.action == CUSTOM_ACTION
|
139
131
|
|
@@ -141,8 +133,11 @@ module Contrast
|
|
141
133
|
end
|
142
134
|
|
143
135
|
ZERO_LENGTH_ACTIONS = [DB_WRITE_ACTION, CUSTOM_ACTION, KEEP_ACTION, REPLACE_ACTION, SPLAT_ACTION].cs__freeze
|
144
|
-
# If the action required needs a length and the target does not have
|
145
|
-
#
|
136
|
+
# If the action required needs a length and the target does not have one, the length is not valid
|
137
|
+
#
|
138
|
+
# @param target [Object] the thing to which to propagate
|
139
|
+
# @param action [String] the name of the action taken during this propagation
|
140
|
+
# @return [Boolean]
|
146
141
|
def valid_length? target, action
|
147
142
|
return true if ZERO_LENGTH_ACTIONS.include?(action)
|
148
143
|
|
@@ -153,9 +148,15 @@ module Contrast
|
|
153
148
|
end
|
154
149
|
end
|
155
150
|
|
156
|
-
# Before we do any work, we should check if we even need to.
|
157
|
-
#
|
158
|
-
#
|
151
|
+
# Before we do any work, we should check if we even need to. If the source and target of this patcher are
|
152
|
+
# not tracked, there's no need to do anything. A copy of nothing is still nothing.
|
153
|
+
#
|
154
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
155
|
+
# propagation event.
|
156
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
157
|
+
# the invocation of the patched method.
|
158
|
+
# @param target [Object] the thing to which to propagate
|
159
|
+
# @return [Boolean]
|
159
160
|
def can_propagate? propagation_node, preshift, target
|
160
161
|
return false unless appropriate_target?(propagation_node, target)
|
161
162
|
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(target)
|
@@ -165,22 +166,21 @@ module Contrast
|
|
165
166
|
case source
|
166
167
|
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
167
168
|
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.object)
|
168
|
-
else
|
169
|
+
else
|
170
|
+
# has to be P, there's no ret source type (yet? ever?)
|
169
171
|
return true if preshift.args && Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.args[source])
|
170
172
|
end
|
171
173
|
end
|
172
174
|
false
|
173
175
|
end
|
174
176
|
|
175
|
-
# We cannot propagate to frozen things that have not been updated
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
# they're supposed to be immutable, but third parties do jenky
|
180
|
-
# things, so allow it as long as it is safe to do.
|
177
|
+
# We cannot propagate to frozen things that have not been updated to work with our property tracking,
|
178
|
+
# unless they're duplicable and the return. We probably shouldn't propagate to frozen things at all, as
|
179
|
+
# they're supposed to be immutable, but third parties do jenky things, so allow it as long as it is safe to
|
180
|
+
# do.
|
181
181
|
#
|
182
|
-
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
|
183
|
-
#
|
182
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
183
|
+
# propagation event.
|
184
184
|
# @param target [Object] the Target to which to propagate.
|
185
185
|
# @return [Boolean] if the target can be propagated to
|
186
186
|
def appropriate_target? propagation_node, target
|
@@ -191,6 +191,9 @@ module Contrast
|
|
191
191
|
end
|
192
192
|
|
193
193
|
# If this patcher has tags, apply them to the entire target
|
194
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
195
|
+
# propagation event.
|
196
|
+
# @param target [Object] the Target to which to propagate.
|
194
197
|
def apply_tags propagation_node, target
|
195
198
|
return unless propagation_node.tags
|
196
199
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties(target))
|
@@ -202,6 +205,10 @@ module Contrast
|
|
202
205
|
end
|
203
206
|
|
204
207
|
# If this patcher has tags, remove them from the entire target
|
208
|
+
#
|
209
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
210
|
+
# propagation event.
|
211
|
+
# @param target [Object] the Target to which to propagate.
|
205
212
|
def apply_untags propagation_node, target
|
206
213
|
return unless propagation_node.untags
|
207
214
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties(target))
|
@@ -214,6 +221,10 @@ module Contrast
|
|
214
221
|
private
|
215
222
|
|
216
223
|
# This is checked right before actual propagation
|
224
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
225
|
+
# propagation event.
|
226
|
+
# @param target [Object] the Target to which to propagate.
|
227
|
+
# @return [Boolean]
|
217
228
|
def propagation_possible? propagation_node, target
|
218
229
|
return false unless propagation_node && valid_target?(target, propagation_node)
|
219
230
|
return false unless valid_length?(target, propagation_node.action)
|
@@ -224,12 +235,24 @@ module Contrast
|
|
224
235
|
# Safely duplicate the target, or return nil
|
225
236
|
#
|
226
237
|
# @param target [Object] the thing to check for duplication
|
238
|
+
# @return [Object, nil]
|
227
239
|
def safe_dup target
|
228
240
|
target.dup
|
229
241
|
rescue StandardError => _e
|
230
242
|
nil
|
231
243
|
end
|
232
244
|
|
245
|
+
# Iterate over each key and value in a hash to allow for propagation to each.
|
246
|
+
#
|
247
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
248
|
+
# propagation event.
|
249
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
250
|
+
# the invocation of the patched method.
|
251
|
+
# @param target [Object] the Target to which to propagate.
|
252
|
+
# @param object [Object] the Object on which the method was invoked
|
253
|
+
# @param ret [Object] the Return of the invoked method
|
254
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
255
|
+
# @param block [Block] the Block passed to the original method
|
233
256
|
def handle_hash_propagation propagation_node, preshift, target, object, ret, args, block
|
234
257
|
target.each_pair do |key, value|
|
235
258
|
apply_propagator(propagation_node, preshift, key, object, ret, args, block)
|
@@ -237,6 +260,17 @@ module Contrast
|
|
237
260
|
end
|
238
261
|
end
|
239
262
|
|
263
|
+
# Iterate over each value in an enumerable to allow for propagation to each.
|
264
|
+
#
|
265
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
266
|
+
# propagation event.
|
267
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
268
|
+
# the invocation of the patched method.
|
269
|
+
# @param target [Object] the Target to which to propagate.
|
270
|
+
# @param object [Object] the Object on which the method was invoked
|
271
|
+
# @param ret [Object] the Return of the invoked method
|
272
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
273
|
+
# @param block [Block] the Block passed to the original method
|
240
274
|
def handle_enumerable_propagation propagation_node, preshift, target, object, ret, args, block
|
241
275
|
target.each do |value|
|
242
276
|
next if target == value
|
@@ -245,6 +279,17 @@ module Contrast
|
|
245
279
|
end
|
246
280
|
end
|
247
281
|
|
282
|
+
# Move the properties from the source(s) to the target of the propagation.
|
283
|
+
#
|
284
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
285
|
+
# propagation event.
|
286
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
287
|
+
# the invocation of the patched method.
|
288
|
+
# @param target [Object] the Target to which to propagate.
|
289
|
+
# @param object [Object] the Object on which the method was invoked
|
290
|
+
# @param ret [Object] the Return of the invoked method
|
291
|
+
# @param args [Array<Object>] the Arguments with which the method was invoked
|
292
|
+
# @param _block [Block] the Block passed to the original method
|
248
293
|
def handle_cs_properties_propagation propagation_node, preshift, target, object, ret, args, _block
|
249
294
|
return if propagation_node.action == NOOP_ACTION
|
250
295
|
return unless can_propagate?(propagation_node, preshift, target)
|
@@ -266,12 +311,9 @@ module Contrast
|
|
266
311
|
propagation_class.propagate(propagation_node, preshift, target)
|
267
312
|
# Once we've propagated, attempt to tag the target if there is a tag(s) to be applied
|
268
313
|
apply_tags(propagation_node, target)
|
269
|
-
# Even though we skipped propagating tags from the source if they
|
270
|
-
#
|
271
|
-
#
|
272
|
-
# In this order, untags takes precedent over tags; but we control
|
273
|
-
# both and there should never be a propagator that has a tag in
|
274
|
-
# its untag.
|
314
|
+
# Even though we skipped propagating tags from the source if they were included in untags, the target may
|
315
|
+
# have already had some on it. Let's go ahead and remove them. In this order, untags takes precedent over
|
316
|
+
# tags; but we control both and there should never be a propagator that has a tag in its untag.
|
275
317
|
apply_untags(propagation_node, target)
|
276
318
|
return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target))
|
277
319
|
|
@@ -302,7 +344,8 @@ module Contrast
|
|
302
344
|
# propagation event.
|
303
345
|
# @return [Boolean]
|
304
346
|
def can_handle_frozen? propagation_node
|
305
|
-
::Contrast::ASSESS.track_frozen_sources? &&
|
347
|
+
::Contrast::ASSESS.track_frozen_sources? &&
|
348
|
+
propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
|
306
349
|
end
|
307
350
|
end
|
308
351
|
end
|
@@ -11,8 +11,6 @@ module Contrast
|
|
11
11
|
# results in new source nodes to track which columns in the database
|
12
12
|
# have been tainted.
|
13
13
|
class DatabaseWrite < Contrast::Agent::Assess::Policy::Propagator::Base
|
14
|
-
|
15
|
-
|
16
14
|
class << self
|
17
15
|
def propagate propagation_node, preshift, target
|
18
16
|
class_type = preshift.object.cs__class
|
@@ -14,16 +14,15 @@ module Contrast
|
|
14
14
|
def square_bracket_tagger propagation_node, preshift, ret, _block
|
15
15
|
case ret
|
16
16
|
when Array
|
17
|
-
|
17
|
+
idx = 0
|
18
|
+
while idx < ret.size
|
19
|
+
return_value = ret[idx]
|
20
|
+
index = idx
|
21
|
+
idx += 1
|
18
22
|
next unless return_value
|
19
23
|
|
20
|
-
target_matchdata_index
|
21
|
-
|
22
|
-
arg_range.to_a.empty? ? index + 1 : arg_range.to_a[index]
|
23
|
-
else
|
24
|
-
preshift.args[index]
|
25
|
-
end
|
26
|
-
square_bracket_single(target_matchdata_index, preshift, return_value, propagation_node)
|
24
|
+
square_bracket_single(target_matchdata_index(preshift, index), preshift, return_value,
|
25
|
+
propagation_node)
|
27
26
|
end
|
28
27
|
when String
|
29
28
|
target_matchdata_index = preshift.args[0]
|
@@ -34,7 +33,11 @@ module Contrast
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def captures_tagger propagation_node, preshift, ret, _block
|
37
|
-
|
36
|
+
idx = 0
|
37
|
+
while idx < ret.size
|
38
|
+
return_value = ret[idx]
|
39
|
+
index = idx
|
40
|
+
idx += 1
|
38
41
|
next unless return_value
|
39
42
|
|
40
43
|
targetted_index = index + 1
|
@@ -44,7 +47,11 @@ module Contrast
|
|
44
47
|
end
|
45
48
|
|
46
49
|
def to_a_tagger propagation_node, preshift, ret, _block
|
47
|
-
|
50
|
+
idx = 0
|
51
|
+
while idx < ret.size
|
52
|
+
return_value = ret[idx]
|
53
|
+
index = idx
|
54
|
+
idx += 1
|
48
55
|
next unless return_value
|
49
56
|
|
50
57
|
square_bracket_single(index, preshift, return_value, propagation_node)
|
@@ -53,7 +60,11 @@ module Contrast
|
|
53
60
|
end
|
54
61
|
|
55
62
|
def values_at_tagger propagation_node, preshift, ret, _block
|
56
|
-
|
63
|
+
idx = 0
|
64
|
+
while idx < ret.size
|
65
|
+
return_value = ret[idx]
|
66
|
+
return_index = idx
|
67
|
+
idx += 1
|
57
68
|
next unless return_value
|
58
69
|
|
59
70
|
original_group_arg_index = preshift.args[return_index]
|
@@ -64,6 +75,15 @@ module Contrast
|
|
64
75
|
|
65
76
|
private
|
66
77
|
|
78
|
+
def target_matchdata_index preshift, index
|
79
|
+
if preshift.args[0].is_a?(Range)
|
80
|
+
arg_range = preshift.args[0]
|
81
|
+
arg_range.to_a.empty? ? index + 1 : arg_range.to_a[index]
|
82
|
+
else
|
83
|
+
preshift.args[index]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
67
87
|
def square_bracket_single argument_index, preshift, return_value, propagation_node
|
68
88
|
original_start_index = preshift.object.begin(argument_index)
|
69
89
|
original_end_index = preshift.object.end(argument_index)
|