contrast-agent 3.13.2 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (250) hide show
  1. checksums.yaml +4 -4
  2. data/exe/contrast_service +1 -7
  3. data/ext/cs__assess_active_record_named/cs__active_record_named.c +8 -7
  4. data/ext/cs__assess_array/cs__assess_array.c +6 -5
  5. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +5 -5
  6. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +2 -1
  7. data/ext/cs__assess_hash/cs__assess_hash.c +18 -17
  8. data/ext/cs__assess_hash/cs__assess_hash.h +2 -1
  9. data/ext/cs__assess_kernel/cs__assess_kernel.c +7 -8
  10. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +18 -16
  11. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +1 -0
  12. data/ext/cs__assess_module/cs__assess_module.c +6 -6
  13. data/ext/cs__assess_regexp/cs__assess_regexp.c +4 -4
  14. data/ext/cs__assess_string/cs__assess_string.c +31 -16
  15. data/ext/cs__assess_string/cs__assess_string.h +6 -1
  16. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +4 -2
  17. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +2 -2
  18. data/ext/cs__common/cs__common.c +48 -39
  19. data/ext/cs__common/cs__common.h +16 -21
  20. data/ext/cs__contrast_patch/cs__contrast_patch.c +27 -25
  21. data/ext/cs__contrast_patch/cs__contrast_patch.h +5 -7
  22. data/ext/cs__protect_kernel/cs__protect_kernel.c +11 -12
  23. data/ext/cs__protect_kernel/cs__protect_kernel.h +2 -2
  24. data/lib/contrast-agent.rb +1 -1
  25. data/lib/contrast.rb +13 -23
  26. data/lib/contrast/agent.rb +39 -47
  27. data/lib/contrast/agent/assess.rb +12 -12
  28. data/lib/contrast/agent/assess/contrast_event.rb +151 -85
  29. data/lib/contrast/agent/assess/events/event_factory.rb +2 -2
  30. data/lib/contrast/agent/assess/events/source_event.rb +3 -3
  31. data/lib/contrast/agent/assess/finalizers/freeze.rb +15 -0
  32. data/lib/contrast/agent/assess/finalizers/hash.rb +97 -0
  33. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +11 -4
  34. data/lib/contrast/agent/assess/policy/patcher.rb +6 -6
  35. data/lib/contrast/agent/assess/policy/policy.rb +9 -11
  36. data/lib/contrast/agent/assess/policy/policy_node.rb +17 -12
  37. data/lib/contrast/agent/assess/policy/policy_scanner.rb +21 -5
  38. data/lib/contrast/agent/assess/policy/preshift.rb +13 -7
  39. data/lib/contrast/agent/assess/policy/propagation_method.rb +64 -44
  40. data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -2
  41. data/lib/contrast/agent/assess/policy/propagator.rb +18 -18
  42. data/lib/contrast/agent/assess/policy/propagator/append.rb +8 -5
  43. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  44. data/lib/contrast/agent/assess/policy/propagator/center.rb +9 -5
  45. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  46. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +6 -4
  47. data/lib/contrast/agent/assess/policy/propagator/insert.rb +7 -4
  48. data/lib/contrast/agent/assess/policy/propagator/keep.rb +4 -1
  49. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +7 -9
  50. data/lib/contrast/agent/assess/policy/propagator/next.rb +7 -5
  51. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +13 -5
  52. data/lib/contrast/agent/assess/policy/propagator/remove.rb +8 -4
  53. data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -2
  54. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +7 -5
  55. data/lib/contrast/agent/assess/policy/propagator/select.rb +13 -7
  56. data/lib/contrast/agent/assess/policy/propagator/splat.rb +10 -9
  57. data/lib/contrast/agent/assess/policy/propagator/split.rb +27 -22
  58. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +52 -35
  59. data/lib/contrast/agent/assess/policy/propagator/trim.rb +11 -5
  60. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +5 -5
  61. data/lib/contrast/agent/assess/policy/source_method.rb +90 -72
  62. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +1 -1
  63. data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +1 -1
  64. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -12
  65. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +2 -2
  66. data/lib/contrast/agent/assess/policy/trigger_method.rb +81 -33
  67. data/lib/contrast/agent/assess/policy/trigger_node.rb +41 -46
  68. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +2 -1
  69. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +2 -2
  70. data/lib/contrast/agent/assess/properties.rb +15 -5
  71. data/lib/contrast/agent/assess/property/evented.rb +7 -20
  72. data/lib/contrast/agent/assess/property/tagged.rb +13 -7
  73. data/lib/contrast/agent/assess/property/updated.rb +131 -0
  74. data/lib/contrast/agent/assess/rule.rb +2 -2
  75. data/lib/contrast/agent/assess/rule/base.rb +3 -4
  76. data/lib/contrast/agent/assess/rule/provider.rb +3 -3
  77. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +58 -5
  78. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +24 -9
  79. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +85 -16
  80. data/lib/contrast/agent/assess/tag.rb +1 -1
  81. data/lib/contrast/agent/assess/tracker.rb +66 -0
  82. data/lib/contrast/agent/at_exit_hook.rb +6 -6
  83. data/lib/contrast/agent/class_reopener.rb +14 -11
  84. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +1 -1
  85. data/lib/contrast/agent/deadzone/policy/policy.rb +2 -2
  86. data/lib/contrast/agent/disable_reaction.rb +1 -1
  87. data/lib/contrast/agent/exclusion_matcher.rb +1 -1
  88. data/lib/contrast/agent/inventory.rb +15 -0
  89. data/lib/contrast/agent/inventory/dependencies.rb +50 -0
  90. data/lib/contrast/agent/inventory/dependency_analysis.rb +37 -0
  91. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +104 -0
  92. data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +38 -0
  93. data/lib/contrast/agent/inventory/policy/datastores.rb +2 -2
  94. data/lib/contrast/agent/inventory/policy/policy.rb +3 -3
  95. data/lib/contrast/agent/inventory/policy/trigger_node.rb +1 -1
  96. data/lib/contrast/agent/middleware.rb +33 -34
  97. data/lib/contrast/agent/patching/policy/after_load_patch.rb +9 -9
  98. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +23 -22
  99. data/lib/contrast/agent/patching/policy/module_policy.rb +11 -11
  100. data/lib/contrast/agent/patching/policy/patch.rb +15 -15
  101. data/lib/contrast/agent/patching/policy/patcher.rb +43 -44
  102. data/lib/contrast/agent/patching/policy/policy.rb +23 -12
  103. data/lib/contrast/agent/patching/policy/policy_node.rb +1 -1
  104. data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -2
  105. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +6 -8
  106. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +2 -2
  107. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
  108. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +7 -6
  109. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +2 -2
  110. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +4 -4
  111. data/lib/contrast/agent/protect/policy/policy.rb +8 -8
  112. data/lib/contrast/agent/protect/policy/rule_applicator.rb +1 -1
  113. data/lib/contrast/agent/protect/policy/trigger_node.rb +1 -1
  114. data/lib/contrast/agent/protect/rule.rb +18 -18
  115. data/lib/contrast/agent/protect/rule/base.rb +4 -3
  116. data/lib/contrast/agent/protect/rule/base_service.rb +1 -1
  117. data/lib/contrast/agent/protect/rule/cmd_injection.rb +5 -5
  118. data/lib/contrast/agent/protect/rule/deserialization.rb +1 -1
  119. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +1 -1
  120. data/lib/contrast/agent/protect/rule/no_sqli.rb +1 -1
  121. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +1 -0
  122. data/lib/contrast/agent/protect/rule/path_traversal.rb +4 -5
  123. data/lib/contrast/agent/protect/rule/sqli.rb +2 -2
  124. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +1 -1
  125. data/lib/contrast/agent/protect/rule/xss.rb +1 -1
  126. data/lib/contrast/agent/protect/rule/xxe.rb +3 -5
  127. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +2 -2
  128. data/lib/contrast/agent/railtie.rb +1 -1
  129. data/lib/contrast/agent/reaction_processor.rb +2 -2
  130. data/lib/contrast/agent/request.rb +45 -43
  131. data/lib/contrast/agent/request_context.rb +10 -6
  132. data/lib/contrast/agent/request_handler.rb +1 -1
  133. data/lib/contrast/agent/response.rb +23 -12
  134. data/lib/contrast/agent/rewriter.rb +6 -9
  135. data/lib/contrast/agent/service_heartbeat.rb +2 -2
  136. data/lib/contrast/agent/static_analysis.rb +9 -9
  137. data/lib/contrast/agent/thread.rb +1 -1
  138. data/lib/contrast/agent/thread_watcher.rb +2 -2
  139. data/lib/contrast/agent/tracepoint_hook.rb +2 -2
  140. data/lib/contrast/agent/version.rb +1 -1
  141. data/lib/contrast/api.rb +4 -4
  142. data/lib/contrast/api/communication.rb +9 -9
  143. data/lib/contrast/api/communication/messaging_queue.rb +3 -6
  144. data/lib/contrast/api/communication/response_processor.rb +1 -1
  145. data/lib/contrast/api/communication/socket_client.rb +41 -6
  146. data/lib/contrast/api/communication/speedracer.rb +1 -1
  147. data/lib/contrast/api/communication/tcp_socket.rb +1 -1
  148. data/lib/contrast/api/communication/unix_socket.rb +1 -1
  149. data/lib/contrast/api/decorators.rb +17 -14
  150. data/lib/contrast/api/decorators/address.rb +20 -20
  151. data/lib/contrast/api/decorators/application_settings.rb +3 -2
  152. data/lib/contrast/api/decorators/application_update.rb +7 -8
  153. data/lib/contrast/api/decorators/http_request.rb +13 -12
  154. data/lib/contrast/api/decorators/input_analysis.rb +3 -2
  155. data/lib/contrast/api/decorators/library.rb +53 -0
  156. data/lib/contrast/api/decorators/library_usage_update.rb +30 -0
  157. data/lib/contrast/api/decorators/message.rb +4 -2
  158. data/lib/contrast/api/decorators/rasp_rule_sample.rb +2 -1
  159. data/lib/contrast/api/decorators/route_coverage.rb +3 -2
  160. data/lib/contrast/api/decorators/server_features.rb +3 -2
  161. data/lib/contrast/api/decorators/trace_event.rb +28 -25
  162. data/lib/contrast/api/decorators/trace_event_object.rb +6 -5
  163. data/lib/contrast/api/decorators/trace_event_signature.rb +5 -4
  164. data/lib/contrast/api/decorators/trace_taint_range.rb +4 -3
  165. data/lib/contrast/api/decorators/user_input.rb +4 -4
  166. data/lib/contrast/common_agent_configuration.rb +2 -2
  167. data/lib/contrast/components/agent.rb +8 -7
  168. data/lib/contrast/components/app_context.rb +50 -39
  169. data/lib/contrast/components/config.rb +32 -50
  170. data/lib/contrast/components/contrast_service.rb +10 -10
  171. data/lib/contrast/components/interface.rb +39 -17
  172. data/lib/contrast/components/inventory.rb +6 -1
  173. data/lib/contrast/components/logger.rb +1 -1
  174. data/lib/contrast/components/scope.rb +3 -3
  175. data/lib/contrast/components/settings.rb +20 -23
  176. data/lib/contrast/config.rb +18 -18
  177. data/lib/contrast/config/application_configuration.rb +5 -2
  178. data/lib/contrast/config/base_configuration.rb +2 -2
  179. data/lib/contrast/config/inventory_configuration.rb +2 -2
  180. data/lib/contrast/config/protect_rule_configuration.rb +1 -1
  181. data/lib/contrast/config/service_configuration.rb +8 -0
  182. data/lib/contrast/configuration.rb +93 -52
  183. data/lib/contrast/extension/assess.rb +21 -22
  184. data/lib/contrast/extension/assess/array.rb +18 -11
  185. data/lib/contrast/extension/assess/erb.rb +11 -3
  186. data/lib/contrast/extension/assess/eval_trigger.rb +7 -7
  187. data/lib/contrast/extension/assess/exec_trigger.rb +2 -2
  188. data/lib/contrast/extension/assess/fiber.rb +14 -14
  189. data/lib/contrast/extension/assess/hash.rb +7 -6
  190. data/lib/contrast/extension/assess/kernel.rb +34 -28
  191. data/lib/contrast/extension/assess/marshal.rb +67 -0
  192. data/lib/contrast/extension/assess/regexp.rb +10 -9
  193. data/lib/contrast/extension/assess/string.rb +23 -23
  194. data/lib/contrast/extension/inventory.rb +4 -4
  195. data/lib/contrast/extension/kernel.rb +1 -1
  196. data/lib/contrast/extension/module.rb +1 -1
  197. data/lib/contrast/extension/protect.rb +3 -3
  198. data/lib/contrast/extension/protect/kernel.rb +4 -4
  199. data/lib/contrast/extension/protect/psych.rb +2 -2
  200. data/lib/contrast/framework/base_support.rb +1 -1
  201. data/lib/contrast/framework/manager.rb +10 -11
  202. data/lib/contrast/framework/rack/patch/session_cookie.rb +23 -29
  203. data/lib/contrast/framework/rack/patch/support.rb +1 -1
  204. data/lib/contrast/framework/rack/support.rb +2 -2
  205. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +13 -13
  206. data/lib/contrast/framework/rails/patch/assess_configuration.rb +7 -13
  207. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +11 -11
  208. data/lib/contrast/framework/rails/patch/support.rb +4 -4
  209. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +11 -11
  210. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +12 -12
  211. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +4 -4
  212. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +12 -12
  213. data/lib/contrast/framework/rails/support.rb +67 -14
  214. data/lib/contrast/framework/sinatra/patch/base.rb +12 -12
  215. data/lib/contrast/framework/sinatra/patch/support.rb +1 -1
  216. data/lib/contrast/framework/sinatra/support.rb +6 -6
  217. data/lib/contrast/funchook/funchook.rb +1 -1
  218. data/lib/contrast/logger/application.rb +13 -5
  219. data/lib/contrast/logger/format.rb +22 -9
  220. data/lib/contrast/logger/log.rb +17 -10
  221. data/lib/contrast/logger/request.rb +30 -0
  222. data/lib/contrast/tasks/config.rb +1 -1
  223. data/lib/contrast/tasks/service.rb +2 -2
  224. data/lib/contrast/utils/assess/sampling_util.rb +2 -2
  225. data/lib/contrast/utils/assess/tracking_util.rb +49 -4
  226. data/lib/contrast/utils/class_util.rb +2 -2
  227. data/lib/contrast/utils/duck_utils.rb +0 -10
  228. data/lib/contrast/utils/env_configuration_item.rb +2 -1
  229. data/lib/contrast/utils/hash_digest.rb +2 -1
  230. data/lib/contrast/utils/heap_dump_util.rb +2 -2
  231. data/lib/contrast/utils/invalid_configuration_util.rb +21 -22
  232. data/lib/contrast/utils/inventory_util.rb +3 -10
  233. data/lib/contrast/utils/io_util.rb +1 -1
  234. data/lib/contrast/utils/os.rb +1 -1
  235. data/lib/contrast/utils/ruby_ast_rewriter.rb +1 -1
  236. data/lib/contrast/utils/sha256_builder.rb +2 -14
  237. data/lib/contrast/utils/stack_trace_utils.rb +2 -2
  238. data/lib/contrast/utils/string_utils.rb +11 -6
  239. data/resources/assess/policy.json +31 -22
  240. data/ruby-agent.gemspec +21 -19
  241. data/service_executables/VERSION +1 -1
  242. data/service_executables/linux/contrast-service +0 -0
  243. data/service_executables/mac/contrast-service +0 -0
  244. metadata +73 -30
  245. data/lib/contrast/agent/assess/insulator.rb +0 -49
  246. data/lib/contrast/agent/require_state.rb +0 -61
  247. data/lib/contrast/extension/assess/assess_extension.rb +0 -147
  248. data/lib/contrast/utils/boolean_util.rb +0 -30
  249. data/lib/contrast/utils/freeze_util.rb +0 -32
  250. data/lib/contrast/utils/gemfile_reader.rb +0 -193
@@ -1,8 +1,8 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/agent/assess/contrast_event'
5
- cs__scoped_require 'contrast/agent/assess/events/source_event'
4
+ require 'contrast/agent/assess/contrast_event'
5
+ require 'contrast/agent/assess/events/source_event'
6
6
 
7
7
  module Contrast
8
8
  module Agent
@@ -1,8 +1,8 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/agent/assess/contrast_event'
5
- cs__scoped_require 'contrast/utils/string_utils'
4
+ require 'contrast/agent/assess/contrast_event'
5
+ require 'contrast/utils/string_utils'
6
6
 
7
7
  module Contrast
8
8
  module Agent
@@ -21,7 +21,7 @@ module Contrast
21
21
  @request = Contrast::Agent::REQUEST_TRACKER.current&.request
22
22
  end
23
23
 
24
- def find_parent_ids _policy_node, _object, _ret, _args
24
+ def parent_events
25
25
  nil
26
26
  end
27
27
 
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/agent/assess/tracker'
5
+
6
+ # Our patch of the Object#freeze method, allowing any Object we track to
7
+ # function with our Contrast::Agent::Assess::Finalizers::Hash
8
+ class Object
9
+ alias_method :cs__patched_object_freeze, :freeze
10
+
11
+ def freeze
12
+ Contrast::Agent::Assess::Tracker.pre_freeze(self)
13
+ cs__patched_object_freeze
14
+ end
15
+ end
@@ -0,0 +1,97 @@
1
+ # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ require 'contrast/utils/duck_utils'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Assess
9
+ module Finalizers
10
+ # An extension of Hash that doesn't impact GC of the object being
11
+ # stored by storing its ID as a Key to lookup and registering a
12
+ # finalizer on the object to remove its entry from the Hash immediately
13
+ # after it's GC'd.
14
+ class Hash < Hash
15
+ FROZEN_FINALIZED_IDS = Set.new
16
+
17
+ def []= key, obj
18
+ # We can't finalize frozen things, so only act on those that went
19
+ # through .pre_freeze
20
+ if key.cs__frozen?
21
+ return unless FROZEN_FINALIZED_IDS.include?(key.__id__)
22
+ else
23
+ ObjectSpace.define_finalizer(key, finalize(key.__id__))
24
+ end
25
+ super key.__id__, obj
26
+ end
27
+
28
+ def [] key
29
+ super key.__id__
30
+ end
31
+
32
+ # Something is trackable if it is not a collection and either not
33
+ # frozen or it was frozen after we put a finalizer on it.
34
+ #
35
+ # @param key [Object] the thing to determine if trackable
36
+ # @return [Boolean]
37
+ def trackable? key
38
+ # Track things in these, not them themselves.
39
+ return false if Contrast::Utils::DuckUtils.iterable_hash?(key)
40
+ return false if Contrast::Utils::DuckUtils.iterable_enumerable?(key)
41
+ # If it's not frozen, we can finalize/ track it.
42
+ return true unless key.cs__frozen?
43
+
44
+ # Otherwise, we can only track it if we've finalized it in our
45
+ # freeze patch.
46
+ FROZEN_FINALIZED_IDS.include?(key.__id__)
47
+ end
48
+
49
+ # Determine if the given Object is tracked, meaning it has a known
50
+ # set of properties and those properties are tracked.
51
+ #
52
+ # @param key [Object] the Object whose properties, by id, we want to
53
+ # check for tracked status
54
+ # @return [Boolean]
55
+ def tracked? key
56
+ key?(key.__id__) && fetch(key.__id__, nil)&.tracked?
57
+ end
58
+
59
+ # Remove the given key from our frozen and properties tracking during
60
+ # finalization of the Object to which the given key_id pertains.
61
+ # NOTE: by necessity, this is the only method which takes the __id__,
62
+ # not the Object itself. You CANNOT pass the Object to this as a
63
+ # finalizer cannot hold reference to the Object being finalized; that
64
+ # prevents GC, which introduces a memory leak and defeats the entire
65
+ # purpose of this.
66
+ #
67
+ # @param key_id [Integer] the Object Identifier to clean up during
68
+ # finalization.
69
+ def finalize key_id
70
+ proc do
71
+ FROZEN_FINALIZED_IDS.delete(key_id)
72
+ delete(key_id)
73
+ end
74
+ end
75
+
76
+ # Frozen things cannot be finalized. To avoid any issue here, we
77
+ # intercept the #freeze call and set finalizers on the Object. To
78
+ # ensure later we know it's been pre-finalized, we add it's __id__ to
79
+ # our tracking.
80
+ #
81
+ # @param key [Object] the Object on which we need to pre-define
82
+ # finalizers
83
+ def pre_freeze key
84
+ return if key.cs__frozen?
85
+ return if FROZEN_FINALIZED_IDS.include?(key.__id__)
86
+
87
+ ObjectSpace.define_finalizer(key, finalize(key.__id__))
88
+
89
+ FROZEN_FINALIZED_IDS << key.__id__
90
+ rescue StandardError => _e
91
+ nil
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/agent/patching/policy/method_policy'
4
+ require 'contrast/agent/patching/policy/method_policy'
5
5
 
6
6
  module Contrast
7
7
  module Agent
@@ -110,16 +110,23 @@ module Contrast
110
110
  dynamic_source.method_name = Contrast::Utils::StringUtils.force_utf8(field)
111
111
  dynamic_source.instance_method = source_node.instance_method?
112
112
  dynamic_source.target = Contrast::Utils::StringUtils.force_utf8(source_node.target_string)
113
- properties.events.each do |event|
114
- dynamic_source.events << event.to_dtm_event
115
- end
116
113
  dynamic_source.properties[READ_TABLE] = Contrast::Utils::StringUtils.force_utf8(source_node.class_name)
117
114
  dynamic_source.properties[READ_COLUMN] = Contrast::Utils::StringUtils.force_utf8(field)
118
115
  dynamic_source.properties[WRITE_QUERY_TIME] = Contrast::Utils::StringUtils.force_utf8(Contrast::Utils::Timer.now_ms)
119
116
  url = current_context.request.normalized_uri
120
117
  dynamic_source.properties[WRITE_QUERY_URL] = Contrast::Utils::StringUtils.force_utf8(url)
118
+ append_events(dynamic_source, properties.event)
121
119
  dynamic_source
122
120
  end
121
+
122
+ def append_events dynamic_source, event
123
+ return unless event
124
+
125
+ event.parent_events&.each do |parent_event|
126
+ append_events(dynamic_source, parent_event)
127
+ end
128
+ dynamic_source.events << event.to_dtm_event
129
+ end
123
130
  end
124
131
  end
125
132
  end
@@ -1,11 +1,11 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/agent/assess/policy/policy'
5
- cs__scoped_require 'contrast/agent/patching/policy/patcher'
6
- cs__scoped_require 'contrast/agent/patching/policy/method_policy'
7
- cs__scoped_require 'contrast/agent/patching/policy/module_policy'
8
- cs__scoped_require 'contrast/components/interface'
4
+ require 'contrast/agent/assess/policy/policy'
5
+ require 'contrast/agent/patching/policy/patcher'
6
+ require 'contrast/agent/patching/policy/method_policy'
7
+ require 'contrast/agent/patching/policy/module_policy'
8
+ require 'contrast/components/interface'
9
9
 
10
10
  module Contrast
11
11
  module Agent
@@ -37,7 +37,7 @@ module Contrast
37
37
  return unless ASSESS.enabled?
38
38
  return if in_contrast_scope?
39
39
 
40
- with_contrast_scope { patcher.patch_specific_module(mod) }
40
+ patcher.patch_specific_module(mod)
41
41
  rescue StandardError => e
42
42
  logger.warn(
43
43
  'Unable to patch assess during eval',
@@ -1,15 +1,15 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'json'
5
- cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_value_rule'
6
- cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_key'
7
- cs__scoped_require 'contrast/agent/assess/rule/provider/hardcoded_password'
8
- cs__scoped_require 'contrast/agent/assess/policy/policy_node'
9
- cs__scoped_require 'contrast/agent/assess/policy/source_node'
10
- cs__scoped_require 'contrast/agent/assess/policy/propagation_node'
11
- cs__scoped_require 'contrast/agent/assess/policy/trigger_node'
12
- cs__scoped_require 'contrast/agent/patching/policy/policy'
4
+ require 'json'
5
+ require 'contrast/agent/assess/rule/provider/hardcoded_value_rule'
6
+ require 'contrast/agent/assess/rule/provider/hardcoded_key'
7
+ require 'contrast/agent/assess/rule/provider/hardcoded_password'
8
+ require 'contrast/agent/assess/policy/policy_node'
9
+ require 'contrast/agent/assess/policy/source_node'
10
+ require 'contrast/agent/assess/policy/propagation_node'
11
+ require 'contrast/agent/assess/policy/trigger_node'
12
+ require 'contrast/agent/patching/policy/policy'
13
13
 
14
14
  module Contrast
15
15
  module Agent
@@ -72,8 +72,6 @@ module Contrast
72
72
  add_node(trigger_node)
73
73
  end
74
74
  end
75
-
76
- tracked_classes.concat(policy_data[TRACKED_CLASSES_KEY])
77
75
  end
78
76
 
79
77
  # Providers is a term that we're taking from Java until we come up with
@@ -1,8 +1,8 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/agent/patching/policy/policy_node'
5
- cs__scoped_require 'contrast/api/decorators/trace_taint_range_tags'
4
+ require 'contrast/agent/patching/policy/policy_node'
5
+ require 'contrast/api/decorators/trace_taint_range_tags'
6
6
 
7
7
  module Contrast
8
8
  module Agent
@@ -157,19 +157,24 @@ module Contrast
157
157
  # Everything else (propagation nodes) are Source2Target
158
158
  def build_action
159
159
  @event_action ||= begin
160
- source = source_string
161
- target = target_string
162
- if source.nil?
160
+ case node_class
161
+ when Contrast::Agent::Assess::Policy::SourceNode::SOURCE
163
162
  :CREATION
164
- elsif target.nil?
163
+ when Contrast::Agent::Assess::Policy::TriggerNode::TRIGGER
165
164
  :TRIGGER
166
165
  else
167
- # TeamServer can't handle the multi-source or multi-target
168
- # values. Give it some help by changing them to 'A'
169
- source = ALL_TYPE if source.include?(Contrast::Utils::ObjectShare::COMMA)
170
- target = ALL_TYPE if target.include?(Contrast::Utils::ObjectShare::COMMA)
171
- str = source[0] + TO_MARKER + target[0]
172
- str.to_sym
166
+ if source_string.nil?
167
+ :CREATION
168
+ elsif target_string.nil?
169
+ :TRIGGER
170
+ else
171
+ # TeamServer can't handle the multi-source or multi-target
172
+ # values. Give it some help by changing them to 'A'
173
+ source = source_string.include?(Contrast::Utils::ObjectShare::COMMA) ? ALL_TYPE : source_string
174
+ target = target_string.include?(Contrast::Utils::ObjectShare::COMMA) ? ALL_TYPE : target_string
175
+ str = source[0] + TO_MARKER + target[0]
176
+ str.to_sym
177
+ end
173
178
  end
174
179
  end
175
180
  @event_action
@@ -1,9 +1,8 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/utils/object_share'
5
- cs__scoped_require 'contrast/components/interface'
6
- cs__scoped_require 'contrast/extension/assess/assess_extension'
4
+ require 'contrast/components/interface'
5
+ require 'contrast/utils/object_share'
7
6
 
8
7
  module Contrast
9
8
  module Agent
@@ -18,18 +17,35 @@ module Contrast
18
17
  access_component :analysis
19
18
 
20
19
  class << self
20
+ # Use the given trace_point, built from an :end event, to determine
21
+ # where the loaded code lives and scan that code for policy
22
+ # violations.
23
+ #
24
+ # @param trace_point [TracePoint] the TracePoint generated by an
25
+ # :end event at the end of a Module definition.
21
26
  def scan trace_point
22
27
  return unless ASSESS.enabled?
23
28
  return unless ASSESS.require_scan?
24
29
 
30
+ provider_values = policy.providers.values
31
+ return if provider_values.all?(&:disabled?)
32
+
25
33
  return unless trace_point.path
26
34
  return if trace_point.path.start_with?(Gem.dir)
27
35
 
28
36
  mod = trace_point.self
29
37
  return if mod.cs__frozen? || mod.singleton_class?
30
38
 
31
- policy.providers.each_value do |provider|
32
- provider.analyze mod
39
+ # TODO: RUBY-1014 - remove non-AST approach
40
+ if RUBY_VERSION >= '2.6.0'
41
+ ast = RubyVM::AbstractSyntaxTree.parse_file(trace_point.path)
42
+ provider_values.each do |provider|
43
+ provider.parse(trace_point, ast)
44
+ end
45
+ else
46
+ provider_values.each do |provider|
47
+ provider.analyze(mod)
48
+ end
33
49
  end
34
50
  end
35
51
 
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- cs__scoped_require 'contrast/components/interface'
4
+ require 'contrast/components/interface'
5
5
 
6
6
  module Contrast
7
7
  module Agent
@@ -69,23 +69,29 @@ module Contrast
69
69
  end
70
70
 
71
71
  def append_object_details preshift, initializing, object
72
- preshift.object = can_dup?(initializing, object) ? object.dup : object
73
- preshift.object.cs__copy_from(object) if object.cs__frozen? && Contrast::Utils::DuckUtils.quacks_to?(preshift.object, :cs__copy_from)
72
+ can = can_dup?(initializing, object)
73
+ preshift.object = can ? object.dup : object
74
74
  preshift.object_length = if Contrast::Utils::DuckUtils.quacks_to?(preshift.object, :length)
75
75
  object.length
76
76
  else
77
77
  0
78
78
  end
79
+ return unless can
80
+ return unless Contrast::Agent::Assess::Tracker.tracked?(object)
81
+
82
+ Contrast::Agent::Assess::Tracker.copy(object, preshift.object)
79
83
  end
80
84
 
81
85
  def append_arg_details preshift, args
82
86
  preshift.args = args.dup
83
- preshift.args.each_with_index do |arg, index|
84
- next unless args[index].cs__frozen? && Contrast::Utils::DuckUtils.quacks_to?(arg, :cs__copy_from)
87
+ preshift.args.each_with_index do |preshift_arg, index|
88
+ original_arg = args[index]
89
+ next if preshift_arg.__id__ == original_arg.__id__
90
+ next unless Contrast::Agent::Assess::Tracker.tracked?(original_arg)
85
91
 
86
- arg.cs__copy_from(args[index])
92
+ Contrast::Agent::Assess::Tracker.copy(original_arg, preshift_arg)
87
93
  end
88
- preshift.arg_lengths = preshift.args.map { |arg| Contrast::Utils::DuckUtils.quacks_to?(arg, :length) ? arg.length : 0 }
94
+ preshift.arg_lengths = preshift.args.map { |preshift_arg| Contrast::Utils::DuckUtils.quacks_to?(preshift_arg, :length) ? preshift_arg.length : 0 }
89
95
  end
90
96
  end
91
97
  end
@@ -1,27 +1,24 @@
1
1
  # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- # This class is responsible for the continuation of traces. A Propagator is any
5
- # method that transforms an untrusted value. In general, these methods work on
6
- # the String class or a holder of Strings
7
- cs__scoped_require 'set'
4
+ require 'set'
8
5
 
9
- cs__scoped_require 'contrast/utils/object_share'
10
- cs__scoped_require 'contrast/utils/sha256_builder'
11
-
12
- cs__scoped_require 'contrast/agent/assess/policy/propagator'
13
-
14
- cs__scoped_require 'contrast/components/interface'
6
+ require 'contrast/agent/assess/policy/propagator'
7
+ require 'contrast/components/interface'
8
+ require 'contrast/utils/object_share'
9
+ require 'contrast/utils/sha256_builder'
15
10
 
16
11
  module Contrast
17
12
  module Agent
18
13
  module Assess
19
14
  module Policy
20
- # This module contains the logic for determining how to propagate tags
21
- # and events from a source to a target
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
22
19
  module PropagationMethod
23
20
  include Contrast::Components::Interface
24
- access_component :logging
21
+ access_component :analysis, :logging
25
22
 
26
23
  APPEND_ACTION = 'APPEND'
27
24
  CENTER_ACTION = 'CENTER'
@@ -127,15 +124,16 @@ module Contrast
127
124
  Contrast::Agent::Assess::Policy::Propagator::Custom.propagate(propagation_node, preshift, ret, block)
128
125
  elsif propagation_node.action == SPLIT_ACTION
129
126
  Contrast::Agent::Assess::Policy::Propagator::Split.propagate(propagation_node, preshift, target)
130
- elsif Contrast::Utils::DuckUtils.quacks_to?(target, :cs__properties)
131
- handle_cs_properties_propagation(propagation_node, preshift, target, object, ret, args, block)
132
127
  elsif Contrast::Utils::DuckUtils.iterable_hash?(target)
133
128
  handle_hash_propagation(propagation_node, preshift, target, object, ret, args, block)
134
129
  elsif Contrast::Utils::DuckUtils.iterable_enumerable?(target)
135
130
  handle_enumerable_propagation(propagation_node, preshift, target, object, ret, args, block)
131
+ else
132
+ handle_cs_properties_propagation(propagation_node, preshift, target, object, ret, args, block)
136
133
  end
137
134
  rescue StandardError => e
138
135
  logger.warn('Unable to apply propagation', e, node_id: propagation_node.id)
136
+ nil
139
137
  end
140
138
 
141
139
  # Custom actions tend to be the more complex of our propagations.
@@ -174,15 +172,7 @@ module Contrast
174
172
  # If the source of this patcher is not tracked, there's no need to do
175
173
  # anything. A copy of nothing is still nothing.
176
174
  def can_propagate? propagation_node, preshift, target
177
- # We cannot propagate to things that do not have cs__properties.
178
- return false unless Contrast::Utils::DuckUtils.quacks_to?(target, :cs__properties)
179
-
180
- # We cannot propagate to frozen things that have not been
181
- # previously tracked. We probably shouldn't propagate to frozen
182
- # things at all, as they're supposed to be immutable, but third
183
- # parties do jenky things, so allow it as long as it is safe to do.
184
- return false if target.cs__properties == Contrast::Agent::Assess::Insulator.generate_frozen.properties &&
185
- propagation_node.targets[0] != Contrast::Utils::ObjectShare::RETURN_KEY
175
+ return false unless appropriate_target?(propagation_node, target)
186
176
  return true if Contrast::Utils::Assess::TrackingUtil.tracked?(target)
187
177
  return false unless preshift
188
178
 
@@ -197,13 +187,32 @@ module Contrast
197
187
  false
198
188
  end
199
189
 
190
+ # We cannot propagate to frozen things that have not been updated
191
+ # to work with our property tracking, unless they're duplicable and
192
+ # the return.
193
+ # We probably shouldn't propagate to frozen things at all, as
194
+ # they're supposed to be immutable, but third parties do jenky
195
+ # things, so allow it as long as it is safe to do.
196
+ #
197
+ # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode]
198
+ # the node that governs this propagation event.
199
+ # @param target [Object] the Target to which to propagate.
200
+ # @return [Boolean] if the target can be propagated to
201
+ def appropriate_target? propagation_node, target
202
+ # special handle Returns b/c we can do unfreezing magic during propagation
203
+ return true if propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
204
+
205
+ Contrast::Agent::Assess::Tracker.trackable?(target)
206
+ end
207
+
200
208
  # If this patcher has tags, apply them to the entire target
201
209
  def apply_tags propagation_node, target
202
210
  return unless propagation_node.tags
203
211
 
212
+ properties = Contrast::Agent::Assess::Tracker.properties(target)
204
213
  length = Contrast::Utils::StringUtils.ret_length(target)
205
214
  propagation_node.tags.each do |tag|
206
- target.cs__properties.add_tag(tag, 0...length)
215
+ properties.add_tag(tag, 0...length)
207
216
  end
208
217
  end
209
218
 
@@ -211,8 +220,11 @@ module Contrast
211
220
  def apply_untags propagation_node, target
212
221
  return unless propagation_node.untags
213
222
 
223
+ properties = Contrast::Agent::Assess::Tracker.properties(target)
224
+ return unless properties
225
+
214
226
  propagation_node.untags.each do |tag|
215
- target.cs__properties.delete_tags(tag)
227
+ properties.delete_tags(tag)
216
228
  end
217
229
  end
218
230
 
@@ -226,6 +238,15 @@ module Contrast
226
238
  true
227
239
  end
228
240
 
241
+ # Safely duplicate the target, or return nil
242
+ #
243
+ # @param target [Object] the thing to check for duplication
244
+ def safe_dup target
245
+ target.dup
246
+ rescue StandardError => _e
247
+ nil
248
+ end
249
+
229
250
  def handle_hash_propagation propagation_node, preshift, target, object, ret, args, block
230
251
  target.each_pair do |key, value|
231
252
  apply_propagator(propagation_node, preshift, key, object, ret, args, block)
@@ -245,31 +266,33 @@ module Contrast
245
266
  return if propagation_node.action == NOOP_ACTION
246
267
  return unless can_propagate?(propagation_node, preshift, target)
247
268
 
248
- # propagate all the tags from the sources to the target
249
269
  propagation_class = PROPAGATION_ACTIONS.fetch(propagation_node.action, nil)
250
270
  unless propagation_class
251
271
  logger.warn(
252
- 'Unknown propgation action receieved. Unable to propagate.',
272
+ 'Unknown propagation action received. Unable to propagate.',
253
273
  node_id: propagation_node.id,
254
274
  action: propagation_node.action)
255
- return ret
275
+ return
256
276
  end
257
-
258
277
  restore_frozen_state = false
259
- if target.cs__frozen?
260
- return ret unless propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
278
+ if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
279
+ return unless ASSESS.track_frozen_sources?
280
+ return unless propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
281
+
282
+ dup = safe_dup(ret)
283
+ return unless dup
261
284
 
262
285
  restore_frozen_state = true
263
- ret = Contrast::Utils::FreezeUtil.unfreeze_dup(target)
286
+ ret = dup
264
287
  target = ret
288
+ Contrast::Agent::Assess::Tracker.pre_freeze(ret)
289
+ ret.cs__freeze
290
+ # double check that we were able to finalize the replaced return
291
+ return unless Contrast::Agent::Assess::Tracker.trackable?(target)
265
292
  end
266
- return if target.cs__properties == Contrast::Agent::Assess::Insulator.generate_frozen.properties
267
-
268
293
  propagation_class.propagate(propagation_node, preshift, target)
269
-
270
294
  # Once we've propagated, attempt to tag the target if there is a tag(s) to be applied
271
295
  apply_tags(propagation_node, target)
272
-
273
296
  # Even though we skipped propagating tags from the source if they
274
297
  # were included in untags, the target may have already had some on
275
298
  # it. Let's go ahead and remove them.
@@ -277,16 +300,13 @@ module Contrast
277
300
  # both and there should never be a propagator that has a tag in
278
301
  # its untag.
279
302
  apply_untags(propagation_node, target)
280
-
281
- target.cs__properties.add_properties(propagation_node.properties)
282
-
283
- target.cs__properties.build_event(propagation_node, target, object, ret, args)
284
-
303
+ properties = Contrast::Agent::Assess::Tracker.properties(target)
304
+ properties.add_properties(propagation_node.properties)
305
+ properties.build_event(propagation_node, target, object, ret, args)
285
306
  logger.trace('Propagation detected',
286
307
  node_id: propagation_node.id,
287
308
  target_id: target.__id__)
288
- ret.cs__freeze if restore_frozen_state
289
- ret
309
+ restore_frozen_state ? ret : nil
290
310
  end
291
311
  end
292
312
  end