contrast-agent 4.9.1 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rspec_parallel +6 -0
  4. data/ext/cs__contrast_patch/cs__contrast_patch.c +0 -1
  5. data/ext/cs__contrast_patch/cs__contrast_patch.h +0 -2
  6. data/lib/contrast/agent/assess/contrast_event.rb +0 -1
  7. data/lib/contrast/agent/assess/finalizers/hash.rb +0 -1
  8. data/lib/contrast/agent/assess/policy/patcher.rb +0 -1
  9. data/lib/contrast/agent/assess/policy/policy_scanner.rb +0 -2
  10. data/lib/contrast/agent/assess/policy/preshift.rb +8 -5
  11. data/lib/contrast/agent/assess/policy/propagation_method.rb +100 -57
  12. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +0 -2
  13. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +31 -11
  14. data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -2
  15. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +1 -0
  16. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +0 -1
  17. data/lib/contrast/agent/assess/policy/source_method.rb +13 -17
  18. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +0 -1
  19. data/lib/contrast/agent/assess/policy/trigger_method.rb +59 -83
  20. data/lib/contrast/agent/assess/property/evented.rb +2 -1
  21. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +0 -1
  22. data/lib/contrast/agent/disable_reaction.rb +1 -1
  23. data/lib/contrast/agent/exclusion_matcher.rb +0 -4
  24. data/lib/contrast/agent/inventory/database_config.rb +117 -0
  25. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +5 -4
  26. data/lib/contrast/agent/inventory/policy/datastores.rb +2 -2
  27. data/lib/contrast/agent/middleware.rb +1 -0
  28. data/lib/contrast/agent/patching/policy/after_load_patch.rb +3 -0
  29. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +18 -12
  30. data/lib/contrast/agent/patching/policy/module_policy.rb +2 -4
  31. data/lib/contrast/agent/patching/policy/patch.rb +5 -0
  32. data/lib/contrast/agent/patching/policy/patch_status.rb +3 -7
  33. data/lib/contrast/agent/patching/policy/patcher.rb +8 -8
  34. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +1 -1
  35. data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -53
  36. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +137 -0
  37. data/lib/contrast/agent/protect/rule/sqli.rb +7 -70
  38. data/lib/contrast/agent/reaction_processor.rb +1 -1
  39. data/lib/contrast/agent/request.rb +5 -2
  40. data/lib/contrast/agent/request_context.rb +19 -22
  41. data/lib/contrast/agent/static_analysis.rb +1 -1
  42. data/lib/contrast/agent/tracepoint_hook.rb +6 -1
  43. data/lib/contrast/agent/version.rb +1 -1
  44. data/lib/contrast/api/communication/messaging_queue.rb +12 -6
  45. data/lib/contrast/api/communication/service_lifecycle.rb +4 -1
  46. data/lib/contrast/api/communication/socket_client.rb +4 -4
  47. data/lib/contrast/api/decorators/agent_startup.rb +4 -4
  48. data/lib/contrast/api/decorators/application_startup.rb +6 -5
  49. data/lib/contrast/api/decorators/route_coverage.rb +24 -1
  50. data/lib/contrast/components/agent.rb +5 -2
  51. data/lib/contrast/components/assess.rb +6 -3
  52. data/lib/contrast/components/base.rb +2 -2
  53. data/lib/contrast/components/config.rb +1 -0
  54. data/lib/contrast/components/contrast_service.rb +4 -2
  55. data/lib/contrast/components/logger.rb +13 -8
  56. data/lib/contrast/components/scope.rb +9 -28
  57. data/lib/contrast/config/base_configuration.rb +14 -6
  58. data/lib/contrast/configuration.rb +19 -15
  59. data/lib/contrast/extension/assess/array.rb +1 -11
  60. data/lib/contrast/extension/assess/eval_trigger.rb +0 -20
  61. data/lib/contrast/extension/assess/fiber.rb +0 -11
  62. data/lib/contrast/extension/assess/hash.rb +0 -10
  63. data/lib/contrast/extension/assess/kernel.rb +1 -10
  64. data/lib/contrast/extension/assess/marshal.rb +3 -11
  65. data/lib/contrast/extension/assess/regexp.rb +0 -11
  66. data/lib/contrast/extension/assess/string.rb +1 -26
  67. data/lib/contrast/extension/extension.rb +61 -0
  68. data/lib/contrast/extension/protect/kernel.rb +0 -10
  69. data/lib/contrast/framework/grape/support.rb +174 -0
  70. data/lib/contrast/framework/manager.rb +42 -6
  71. data/lib/contrast/framework/rack/support.rb +1 -1
  72. data/lib/contrast/framework/rails/patch/assess_configuration.rb +0 -1
  73. data/lib/contrast/framework/rails/patch/support.rb +6 -3
  74. data/lib/contrast/framework/rails/railtie.rb +1 -1
  75. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +1 -0
  76. data/lib/contrast/framework/rails/support.rb +60 -13
  77. data/lib/contrast/framework/sinatra/support.rb +1 -1
  78. data/lib/contrast/logger/log.rb +89 -15
  79. data/lib/contrast/utils/io_util.rb +1 -1
  80. data/lib/contrast/utils/ruby_ast_rewriter.rb +16 -13
  81. data/lib/contrast/utils/tag_util.rb +2 -1
  82. data/resources/assess/policy.json +197 -2
  83. data/resources/deadzone/policy.json +10 -0
  84. data/ruby-agent.gemspec +10 -1
  85. metadata +78 -12
  86. data/lib/contrast/utils/inventory_util.rb +0 -113
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27e411d1ab6398ca59e77859552c6956b0590dc94973512d0bd6e8e63ffa7f74
4
- data.tar.gz: 79fee8e128ace994b8aa791d6e945edada8bd69ff099494272af60fba437937c
3
+ metadata.gz: ab65fd574ef84fbe339e4f4d4bf340623235a442ecc11d7ba28c6af3c6f04d4d
4
+ data.tar.gz: 0fa9cc44fe85713ee924101139e615d361de6d906c8f5ff4fdd345a930eee9d2
5
5
  SHA512:
6
- metadata.gz: 6029048d3bc67b6c4f0e5408d37c2b9a8362bd5b8bf5d5e5858f93a26f499e4454896613dc71003e123cd1ca9473d558ec11cc9d7fbebe648b192d9040a44d8e
7
- data.tar.gz: e1e697c39c4611f3fadccc82c189e700facd5f399214f96b6bc053bd702ccd05b10aa37a302231e39f82611b13ae40adbf45c2ca0e2ef7fb10eef790310a1836
6
+ metadata.gz: cb21ebcad0e772649d16a25d2f00cc057ee10df71638b7bd7cc6a4710a1ded28ce4dca749fa040ba2fb78e992727f4cc5d5f38e1187c363a8ea33a12333fc289
7
+ data.tar.gz: c3ad4c82a9e25ecb58c0ea906f1170cffdd6811952f9c1d71a6c75166358a37e0ebba40e55e9a7433156a51122b9ca1450bb5a4a2a87f9081a4a4268d9abfdb4
data/.rspec CHANGED
@@ -3,4 +3,3 @@
3
3
  --format documentation
4
4
  --format RspecJunitFormatter
5
5
  --out ./test-results/results.xml
6
- --color
data/.rspec_parallel ADDED
@@ -0,0 +1,6 @@
1
+ --require spec_helper
2
+ --order rand
3
+ --format progress
4
+ --format RspecJunitFormatter
5
+ --out ./test-results/results.xml
6
+ --format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log
@@ -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");
@@ -16,8 +16,6 @@ static VALUE rb_sym_contrast_apply_pre_patch;
16
16
  static VALUE rb_sym_custom_patch;
17
17
  static VALUE rb_sym_cs_to_s;
18
18
 
19
- static VALUE rb_sym_in_request_context;
20
-
21
19
  static VALUE rb_sym_enter_method_scope;
22
20
  static VALUE rb_sym_exit_method_scope;
23
21
 
@@ -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
@@ -20,7 +20,6 @@ module Contrast
20
20
  extend Contrast::Components::Logger::InstanceMethods
21
21
  extend Contrast::Components::Scope::InstanceMethods
22
22
 
23
-
24
23
  class << self
25
24
  def policy
26
25
  Contrast::Agent::Assess::Policy::Policy.instance
@@ -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
- preshift.args.each_with_index do |preshift_arg, index|
88
- original_arg = args[index]
89
- next if preshift_arg.__id__ == original_arg.__id__
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, preshift_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
- # Propagator is any method that transforms an untrusted value. In
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
- # the policy that governs the patches to this method
53
- # @param preshift [Contrast::Agent::Assess::PreShift] The capture
54
- # of the state of the code just prior to the invocation of the
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
- # were made; will replace the return of the original function if
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
- # propagation was. Now that we know, we'll actually do things to
91
- # it. Note that the return of this method will replace the original
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
- # the node that governs this propagation event.
97
- # @param preshift [Contrast::Agent::Assess::PreShift] The capture
98
- # of the state of the code just prior to the invocation of the
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
- # were made; will replace the return of the original function if
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
- # Often, the method has to make decisions about the target based on
132
- # the context with which the method was called. As such, defer
133
- # determining if the target is valid to that method.
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
- # In all other cases, a target is valid for propagation if it is not
136
- # nil
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
- # one, the length is not valid
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
- # If the source of this patcher is not tracked, there's no need to do
158
- # anything. A copy of nothing is still nothing.
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 # has to be P, there's no ret source type (yet? ever?)
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
- # to work with our property tracking, unless they're duplicable and
177
- # the return.
178
- # We probably shouldn't propagate to frozen things at all, as
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
- # the node that governs this propagation event.
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
- # were included in untags, the target may have already had some on
271
- # it. Let's go ahead and remove them.
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? && propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
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
- ret.each_with_index do |return_value, index|
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 = if preshift.args[0].is_a?(Range)
21
- arg_range = preshift.args[0]
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
- ret.each_with_index do |return_value, index|
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
- ret.each_with_index do |return_value, index|
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
- ret.each_with_index do |return_value, return_index|
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)