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.
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)