contrast-agent 3.8.5 → 3.9.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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_array/cs__assess_array.c +1 -1
  3. data/ext/cs__assess_module/cs__assess_module.c +0 -1
  4. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +34 -0
  5. data/ext/cs__assess_yield_track/cs__assess_yield_track.h +12 -0
  6. data/ext/{cs__scope → cs__assess_yield_track}/extconf.rb +0 -0
  7. data/ext/cs__common/cs__common.c +6 -6
  8. data/ext/cs__common/cs__common.h +3 -1
  9. data/ext/cs__contrast_patch/cs__contrast_patch.c +142 -119
  10. data/ext/cs__contrast_patch/cs__contrast_patch.h +3 -0
  11. data/funchook/autom4te.cache/requests +48 -48
  12. data/funchook/config.log +2 -2
  13. data/lib/contrast/agent.rb +15 -5
  14. data/lib/contrast/agent/assess.rb +0 -1
  15. data/lib/contrast/agent/assess/contrast_event.rb +9 -8
  16. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +68 -18
  17. data/lib/contrast/agent/assess/policy/policy.rb +0 -14
  18. data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
  19. data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
  20. data/lib/contrast/agent/assess/policy/propagation_method.rb +4 -2
  21. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  22. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
  23. data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -2
  24. data/lib/contrast/agent/assess/policy/propagator/split.rb +166 -1
  25. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +1 -0
  26. data/lib/contrast/agent/assess/policy/source_method.rb +199 -140
  27. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +30 -0
  28. data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +36 -0
  29. data/lib/contrast/agent/assess/policy/trigger_method.rb +238 -153
  30. data/lib/contrast/agent/assess/policy/trigger_node.rb +54 -9
  31. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +13 -0
  32. data/lib/contrast/agent/assess/properties.rb +29 -0
  33. data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +35 -31
  34. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +1 -1
  35. data/lib/contrast/agent/class_reopener.rb +98 -55
  36. data/lib/contrast/agent/feature_state.rb +1 -1
  37. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  38. data/lib/contrast/agent/logger_manager.rb +2 -2
  39. data/lib/contrast/agent/middleware.rb +1 -3
  40. data/lib/contrast/agent/patching/policy/after_load_patch.rb +40 -4
  41. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +33 -8
  42. data/lib/contrast/agent/patching/policy/method_policy.rb +20 -7
  43. data/lib/contrast/agent/patching/policy/patch.rb +54 -23
  44. data/lib/contrast/agent/patching/policy/patch_status.rb +0 -2
  45. data/lib/contrast/agent/patching/policy/patcher.rb +10 -11
  46. data/lib/contrast/agent/patching/policy/policy.rb +4 -0
  47. data/lib/contrast/agent/patching/policy/policy_node.rb +14 -1
  48. data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -1
  49. data/lib/contrast/agent/protect/policy/policy.rb +6 -6
  50. data/lib/contrast/agent/protect/rule/base.rb +1 -1
  51. data/lib/contrast/agent/protect/rule/deserialization.rb +3 -25
  52. data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
  53. data/lib/contrast/agent/railtie.rb +11 -5
  54. data/lib/contrast/agent/request.rb +1 -19
  55. data/lib/contrast/agent/request_context.rb +1 -1
  56. data/lib/contrast/agent/rewriter.rb +4 -3
  57. data/lib/contrast/agent/scope.rb +116 -19
  58. data/lib/contrast/agent/service_heartbeat.rb +5 -2
  59. data/lib/contrast/agent/settings_state.rb +12 -8
  60. data/lib/contrast/agent/version.rb +1 -1
  61. data/lib/contrast/api.rb +1 -0
  62. data/lib/contrast/api/speedracer.rb +2 -2
  63. data/lib/contrast/components/agent.rb +26 -7
  64. data/lib/contrast/components/app_context.rb +8 -45
  65. data/lib/contrast/components/contrast_service.rb +3 -4
  66. data/lib/contrast/components/interface.rb +1 -1
  67. data/lib/contrast/components/scope.rb +56 -26
  68. data/lib/contrast/config/ruby_configuration.rb +8 -3
  69. data/lib/contrast/delegators.rb +9 -0
  70. data/lib/contrast/delegators/application_update.rb +32 -0
  71. data/lib/contrast/extensions/framework/rack/cookie.rb +24 -0
  72. data/lib/contrast/extensions/framework/rack/request.rb +24 -0
  73. data/lib/contrast/extensions/framework/rack/response.rb +23 -0
  74. data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +20 -0
  75. data/lib/contrast/extensions/framework/rails/active_record.rb +26 -0
  76. data/lib/contrast/extensions/framework/rails/active_record_named.rb +53 -0
  77. data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +21 -0
  78. data/lib/contrast/extensions/framework/rails/buffer.rb +28 -0
  79. data/lib/contrast/extensions/framework/rails/configuration.rb +27 -0
  80. data/lib/contrast/extensions/framework/sinatra/base.rb +59 -0
  81. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess.rb +12 -11
  82. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/array.rb +4 -3
  83. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/assess_extension.rb +0 -2
  84. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/basic_object.rb +1 -1
  85. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/erb.rb +0 -0
  86. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/exec_trigger.rb +0 -0
  87. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/fiber.rb +3 -4
  88. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/hash.rb +0 -0
  89. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/kernel.rb +1 -1
  90. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/module.rb +1 -1
  91. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/regexp.rb +0 -0
  92. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/string.rb +0 -0
  93. data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/tilt_template_trigger.rb +0 -0
  94. data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +40 -0
  95. data/lib/contrast/{core_extensions → extensions/ruby_core}/delegator.rb +0 -0
  96. data/lib/contrast/{core_extensions → extensions/ruby_core}/eval_trigger.rb +1 -1
  97. data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory.rb +0 -0
  98. data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory/datastores.rb +1 -1
  99. data/lib/contrast/extensions/ruby_core/module.rb +17 -0
  100. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect.rb +0 -0
  101. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_command_injection_rule.rb +8 -6
  102. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_deserialization_rule.rb +7 -5
  103. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_no_sqli_rule.rb +5 -3
  104. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_path_traversal_rule.rb +31 -27
  105. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_sqli_rule.rb +5 -3
  106. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_xxe_rule.rb +9 -7
  107. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/kernel.rb +0 -0
  108. data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/psych.rb +1 -1
  109. data/lib/contrast/{core_extensions → extensions/ruby_core}/thread.rb +0 -0
  110. data/lib/contrast/framework/base_support.rb +63 -0
  111. data/lib/contrast/framework/manager.rb +109 -0
  112. data/lib/contrast/framework/platform_version.rb +21 -0
  113. data/lib/contrast/framework/rails_support.rb +88 -0
  114. data/lib/contrast/framework/sinatra_application_helper.rb +49 -0
  115. data/lib/contrast/framework/sinatra_support.rb +94 -0
  116. data/lib/contrast/framework/view_technologies_descriptor.rb +20 -0
  117. data/lib/contrast/utils/assess/tracking_util.rb +2 -4
  118. data/lib/contrast/utils/class_util.rb +92 -37
  119. data/lib/contrast/utils/duck_utils.rb +59 -39
  120. data/lib/contrast/utils/environment_util.rb +5 -75
  121. data/lib/contrast/utils/freeze_util.rb +3 -7
  122. data/lib/contrast/utils/invalid_configuration_util.rb +5 -5
  123. data/lib/contrast/utils/job_servers_running.rb +39 -0
  124. data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -2
  125. data/lib/contrast/utils/service_response_util.rb +0 -6
  126. data/lib/contrast/utils/sinatra_helper.rb +6 -0
  127. data/lib/contrast/utils/stack_trace_utils.rb +1 -1
  128. data/resources/assess/policy.json +74 -23
  129. data/resources/inventory/policy.json +1 -1
  130. data/resources/protect/policy.json +11 -9
  131. data/resources/rubocops/object/frozen_cop.rb +1 -1
  132. data/ruby-agent.gemspec +2 -0
  133. data/service_executables/VERSION +1 -1
  134. data/service_executables/linux/contrast-service +0 -0
  135. data/service_executables/mac/contrast-service +0 -0
  136. metadata +94 -57
  137. data/ext/cs__scope/cs__scope.c +0 -96
  138. data/ext/cs__scope/cs__scope.h +0 -33
  139. data/lib/contrast/agent/assess/class_reverter.rb +0 -82
  140. data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +0 -28
  141. data/lib/contrast/core_extensions/module.rb +0 -42
  142. data/lib/contrast/core_extensions/object.rb +0 -27
  143. data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +0 -48
  144. data/lib/contrast/rails_extensions/assess/active_record.rb +0 -32
  145. data/lib/contrast/rails_extensions/assess/active_record_named.rb +0 -61
  146. data/lib/contrast/rails_extensions/assess/configuration.rb +0 -26
  147. data/lib/contrast/rails_extensions/buffer.rb +0 -30
  148. data/lib/contrast/rails_extensions/rack.rb +0 -45
  149. data/lib/contrast/sinatra_extensions/assess/cookie.rb +0 -26
  150. data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +0 -59
  151. data/lib/contrast/utils/operating_environment.rb +0 -38
  152. data/lib/contrast/utils/path_util.rb +0 -151
  153. data/lib/contrast/utils/scope_util.rb +0 -99
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  cs__scoped_require 'contrast/agent/settings_state'
5
- cs__scoped_require 'contrast/core_extensions/module'
5
+ cs__scoped_require 'contrast/extensions/ruby_core/module'
6
6
  cs__scoped_require 'contrast/utils/boolean_util'
7
7
 
8
8
  module Contrast
@@ -5,7 +5,7 @@ cs__scoped_require 'contrast/agent/inventory/policy/trigger_node'
5
5
  cs__scoped_require 'contrast/agent/patching/policy/policy'
6
6
 
7
7
  # classes required by patches in the policy
8
- cs__scoped_require 'contrast/core_extensions/inventory/datastores'
8
+ cs__scoped_require 'contrast/extensions/ruby_core/inventory/datastores'
9
9
 
10
10
  module Contrast
11
11
  module Agent
@@ -3,7 +3,7 @@
3
3
 
4
4
  cs__scoped_require 'logger'
5
5
 
6
- cs__scoped_require 'contrast/core_extensions/module'
6
+ cs__scoped_require 'contrast/extensions/ruby_core/module'
7
7
  cs__scoped_require 'contrast/components/interface'
8
8
 
9
9
  module Contrast
@@ -60,7 +60,7 @@ module Contrast
60
60
  private
61
61
 
62
62
  def default_progname
63
- "Contrast #{ APP_CONTEXT.name }"
63
+ 'Contrast Agent'
64
64
  end
65
65
 
66
66
  def build path: STDOUT_STR, progname: default_progname, level_const: DEFAULT_LEVEL
@@ -4,16 +4,14 @@
4
4
  cs__scoped_require 'ipaddr'
5
5
  cs__scoped_require 'json'
6
6
  cs__scoped_require 'rack'
7
- cs__scoped_require 'contrast/core_extensions/object'
7
+
8
8
  cs__scoped_require 'contrast/security_exception'
9
9
  cs__scoped_require 'contrast/utils/object_share'
10
10
  cs__scoped_require 'contrast/utils/gemfile_reader'
11
- cs__scoped_require 'contrast/utils/operating_environment'
12
11
  cs__scoped_require 'contrast/agent/service_heartbeat'
13
12
  cs__scoped_require 'contrast/components/interface'
14
13
  cs__scoped_require 'contrast/utils/heap_dump_util'
15
14
 
16
- cs__scoped_require 'contrast/utils/path_util'
17
15
  cs__scoped_require 'contrast/utils/timer'
18
16
  cs__scoped_require 'contrast/utils/freeze_util'
19
17
  cs__scoped_require 'contrast/utils/service_sender_util'
@@ -1,16 +1,19 @@
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/class_util'
5
+
4
6
  module Contrast
5
7
  module Agent
6
8
  module Patching
7
9
  module Policy
8
10
  # Used to handle tracking patches that need to apply special instrumentation when a module is loaded
9
11
  class AfterLoadPatch
10
- attr_reader :applied, :module_name, :instrumentation_file_path
11
- def initialize module_name, instrumentation_file_path
12
+ attr_reader :applied, :module_name, :instrumentation_file_path, :method_to_instrument
13
+ def initialize module_name, instrumentation_file_path, method_to_instrument: nil
12
14
  @applied = false
13
15
  @module_name = module_name
16
+ @method_to_instrument = method_to_instrument
14
17
  @instrumentation_file_path = instrumentation_file_path
15
18
  end
16
19
 
@@ -18,18 +21,51 @@ module Contrast
18
21
  @applied
19
22
  end
20
23
 
24
+ # Modules can be re-opened, so the first load may not
25
+ # necessarily define the method we're looking for:
26
+ #
27
+ # patching MyMod#instrumentable:
28
+ #
29
+ # file1:
30
+ # module MyMod
31
+ # def unrelated <-- false lead
32
+ # end
33
+ # end
34
+ #
35
+ # file2:
36
+ # module MyMod
37
+ # def instrumentable <-- actual target
38
+ # end
39
+ # end
40
+ def blocked_by_method?
41
+ return true unless target_defined? # bc no methods are loaded
42
+ return false unless method_to_instrument
43
+
44
+ !module_lookup.instance_methods.include? method_to_instrument
45
+ end
46
+
21
47
  def applies? loaded_module_name
22
- loaded_module_name == module_name
48
+ (loaded_module_name == module_name) && !blocked_by_method?
23
49
  end
24
50
 
25
51
  def target_defined?
26
- Module.cs__truly_defined?(module_name)
52
+ Contrast::Utils::ClassUtil.truly_defined?(module_name)
27
53
  end
28
54
 
29
55
  def instrument!
30
56
  cs__scoped_require instrumentation_file_path
31
57
  @applied = true
32
58
  end
59
+
60
+ private
61
+
62
+ def module_lookup
63
+ @_module_lookup ||= begin
64
+ Module.cs__const_get module_name
65
+ rescue StandardError => _e
66
+ nil
67
+ end
68
+ end
33
69
  end
34
70
  end
35
71
  end
@@ -12,18 +12,42 @@ module Contrast
12
12
  # after they've been loaded
13
13
  module AfterLoadPatcher
14
14
  include Contrast::Components::Interface
15
- access_component :logging
15
+ access_component :logging, :agent
16
16
 
17
17
  AFTER_LOAD_PATCHES = Set.new([
18
18
  Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
19
19
  'ActiveRecord::AttributeMethods::TimeZoneConversion::ClassMethods',
20
- 'contrast/rails_extensions/assess/action_controller_inheritance'),
21
- Contrast::Agent::Patching::Policy::AfterLoadPatch.new('ActiveRecord::Scoping::Named::ClassMethods',
22
- 'contrast/rails_extensions/assess/active_record_named'),
23
- Contrast::Agent::Patching::Policy::AfterLoadPatch.new('ActiveRecord::AttributeMethods::Read::ClassMethods',
24
- 'contrast/rails_extensions/assess/active_record'),
25
- Contrast::Agent::Patching::Policy::AfterLoadPatch.new('Sinatra::Base',
26
- 'contrast/sinatra_extensions/inventory/sinatra_base')
20
+ 'contrast/extensions/framework/rails/active_record_time_zone_inherited',
21
+ method_to_instrument: :inherited),
22
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
23
+ 'ActionController::Railties::Helper::ClassMethods',
24
+ 'contrast/extensions/framework/rails/action_controller_railties_helper_inherited',
25
+ method_to_instrument: :inherited),
26
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
27
+ 'ActiveRecord::Scoping::Named::ClassMethods',
28
+ 'contrast/extensions/framework/rails/active_record_named'),
29
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
30
+ 'ActiveRecord::AttributeMethods::Read::ClassMethods',
31
+ 'contrast/extensions/framework/rails/active_record'),
32
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
33
+ 'Sinatra::Base',
34
+ 'contrast/extensions/framework/sinatra/base'),
35
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
36
+ 'Rails::Application::Configuration',
37
+ 'contrast/extensions/framework/rails/configuration',
38
+ method_to_instrument: :session_store),
39
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
40
+ 'Rack::Request',
41
+ 'contrast/extensions/framework/rack/request'),
42
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
43
+ 'Rack::Response',
44
+ 'contrast/extensions/framework/rack/response'),
45
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
46
+ 'ActionController::Live::Buffer',
47
+ 'contrast/extensions/framework/rails/buffer'),
48
+ Contrast::Agent::Patching::Policy::AfterLoadPatch.new(
49
+ 'Rack::Session::Cookie',
50
+ 'contrast/extensions/framework/rack/cookie')
27
51
  ])
28
52
 
29
53
  # After initialization run a catchup check to instrument any already loaded modules we care about
@@ -31,6 +55,7 @@ module Contrast
31
55
  applied = []
32
56
  AFTER_LOAD_PATCHES.each do |after_load_patch|
33
57
  next unless after_load_patch.target_defined?
58
+ next if AGENT.skip_instrumentation?(after_load_patch.module_name)
34
59
 
35
60
  logger.debug("Detected loading of #{ after_load_patch.module_name } - applying instrumentation")
36
61
  after_load_patch.instrument!
@@ -31,20 +31,33 @@ module Contrast
31
31
  end
32
32
 
33
33
  def empty?
34
- return false if source_node
35
- return false if propagation_node
36
- return false if trigger_node
37
- return false if inventory_node
38
- return false if protect_node
39
- return false if deadzone_node
34
+ nodes.none?
35
+ end
36
+
37
+ def scopes_to_enter
38
+ @_scopes_to_enter ||= method_scopes
39
+ end
40
40
 
41
- true
41
+ def scopes_to_exit
42
+ @_scopes_to_exit ||= method_scopes.reverse
42
43
  end
43
44
 
44
45
  def requires_custom_patch?
45
46
  !!@trigger_node&.custom_patch?
46
47
  end
47
48
 
49
+ private
50
+
51
+ def nodes
52
+ @_nodes ||= [source_node, propagation_node, trigger_node, inventory_node, protect_node, deadzone_node].compact
53
+ end
54
+
55
+ def method_scopes
56
+ # Implicitly, the scope precedence is the node order
57
+ # defined by #nodes.
58
+ @_method_scopes ||= nodes.flat_map(&:method_scope).tap(&:compact!).tap(&:uniq!)
59
+ end
60
+
48
61
  class << self
49
62
  # Given a Contrast::Agent::Patching::Policy::ModulePolicy, parse
50
63
  # out its information for the given method in order to construct a
@@ -3,28 +3,27 @@
3
3
 
4
4
  cs__scoped_require 'monitor'
5
5
  # base
6
- cs__scoped_require 'contrast/core_extensions/module'
6
+ cs__scoped_require 'contrast/extensions/ruby_core/module'
7
7
  cs__scoped_require 'contrast/agent/patching/policy/method_policy'
8
8
  cs__scoped_require 'contrast/agent/patching/policy/patch_status'
9
9
  cs__scoped_require 'contrast/agent/patching/policy/trigger_node'
10
10
  cs__scoped_require 'contrast/components/interface'
11
- cs__scoped_require 'contrast/utils/scope_util'
12
11
 
13
12
  # assess
14
13
  cs__scoped_require 'contrast/agent/assess/policy/policy'
15
14
  cs__scoped_require 'contrast/agent/assess/policy/propagation_method'
16
15
  cs__scoped_require 'contrast/agent/assess/policy/source_method'
17
16
  cs__scoped_require 'contrast/agent/assess/policy/trigger_method'
18
- cs__scoped_require 'contrast/core_extensions/assess'
17
+ cs__scoped_require 'contrast/extensions/ruby_core/assess'
19
18
 
20
19
  # inventory
21
20
  cs__scoped_require 'contrast/agent/inventory/policy/policy'
22
- cs__scoped_require 'contrast/core_extensions/inventory'
21
+ cs__scoped_require 'contrast/extensions/ruby_core/inventory'
23
22
 
24
23
  # protect
25
24
  cs__scoped_require 'contrast/agent/protect/policy/policy'
26
- cs__scoped_require 'contrast/core_extensions/protect'
27
- cs__scoped_require 'contrast/core_extensions/protect/kernel'
25
+ cs__scoped_require 'contrast/extensions/ruby_core/protect'
26
+ cs__scoped_require 'contrast/extensions/ruby_core/protect/kernel'
28
27
 
29
28
  module Contrast
30
29
  module Agent
@@ -39,7 +38,6 @@ module Contrast
39
38
  include Contrast::Agent::Assess::Policy::SourceMethod
40
39
  include Contrast::Agent::Assess::Policy::PropagationMethod
41
40
  include Contrast::Agent::Assess::Policy::TriggerMethod
42
- extend Contrast::Utils::ScopeUtil
43
41
 
44
42
  include Contrast::Components::Interface
45
43
  access_component :logging, :analysis, :agent, :scope
@@ -50,6 +48,18 @@ module Contrast
50
48
  Contrast::Agent::Protect::Policy::Policy
51
49
  ].cs__freeze
52
50
 
51
+ def enter_method_scope! method_policy
52
+ method_policy.scopes_to_enter.each do |scope|
53
+ enter_scope!(scope)
54
+ end
55
+ end
56
+
57
+ def exit_method_scope! method_policy
58
+ method_policy.scopes_to_exit.each do |scope|
59
+ exit_scope!(scope)
60
+ end
61
+ end
62
+
53
63
  # THIS IS CALLED FROM C. Do not change the signature lightly.
54
64
  #
55
65
  # This method functions to call the infilter methods from our
@@ -68,18 +78,20 @@ module Contrast
68
78
  def apply_pre_patch method_policy, method, exception, object, args
69
79
  apply_protect(method_policy, method, exception, object, args)
70
80
  apply_inventory(method_policy, method, exception, object, args)
71
- # We were told to block something, so we gotta. Don't catch this
72
- # one, let it get back to our Middleware or even all the way out to
73
- # the framework
74
81
  rescue Contrast::SecurityException => e
75
- # This can be C's responsibility, but it's a lot of code.
76
- # Rewrite this to make C do it, once we have better macroing.
77
- exit_contrast_scope!
82
+ # We were told to block something, so we gotta. Don't catch this
83
+ # one, let it get back to our Middleware or even all the way out to
84
+ # the framework
78
85
  raise e
79
- # Anything else was our bad and we gotta catch that to allow for
80
- # normal application flow
81
86
  rescue StandardError => e
87
+ # Anything else was our bad and we gotta catch that to allow for
88
+ # normal application flow
82
89
  logger.error(e, 'Unable to apply pre patch to method.')
90
+ rescue Exception => e # rubocop:disable Lint/RescueException
91
+ # This is something like NoMemoryError that we can't
92
+ # hope to handle. Nonetheless, shouldn't leak scope.
93
+ exit_contrast_scope!
94
+ raise e
83
95
  end
84
96
 
85
97
  # THIS IS CALLED FROM C. Do not change the signature lightly.
@@ -197,9 +209,6 @@ module Contrast
197
209
  rescue Exception => e # rubocop:disable Lint/RescueException
198
210
  logger.error(e, 'Unable to assess method call.')
199
211
  handle_return(propagated_ret, source_ret, ret)
200
- # This will unwind the stack, so we handle our own scope exit.
201
- # Move this to C when it's convenient.
202
- exit_contrast_scope!
203
212
  raise e
204
213
  end
205
214
 
@@ -257,13 +266,17 @@ module Contrast
257
266
  safe_return
258
267
  end
259
268
 
260
- # Given a class, method, and type, return a symbol in the format
261
- # <method_start>_<class_name>_<method_name>
262
- def build_method_name patcher_class, patcher_method
269
+ # Given a module and method, construct an expected name for the
270
+ # alias by which Contrast will reference the original.
271
+ #
272
+ # @param patched_class [Module] the module being patched
273
+ # @param patched_method [Symbol] the method being patched
274
+ # @return [Symbol]
275
+ def build_method_name patched_class, patched_method
263
276
  (Contrast::Utils::ObjectShare::CONTRAST_PATCHED_METHOD_START +
264
- patcher_class.cs__name.gsub('::', '_').downcase +
277
+ patched_class.cs__name.gsub('::', '_').downcase +
265
278
  Contrast::Utils::ObjectShare::UNDERSCORE +
266
- patcher_method.to_s).to_sym
279
+ patched_method.to_s).to_sym
267
280
  end
268
281
 
269
282
  # @param mod [Module] the module in which the patch should be
@@ -302,6 +315,24 @@ module Contrast
302
315
  def instrument_with_prepend mod, method_policy
303
316
  contrast_prepend_method(mod, method_policy)
304
317
  end
318
+
319
+ # @return [Boolean]
320
+ def skip_contrast_analysis?
321
+ return true if in_contrast_scope?
322
+ return true unless Contrast::Agent::REQUEST_TRACKER.current&.analyze_request?
323
+
324
+ false
325
+ end
326
+
327
+ # Skip if we should skip_contrast_analysis?, sampling says to ignore this
328
+ # request, or assess has been disabled.
329
+ #
330
+ # @return [Boolean]
331
+ def skip_assess_analysis?
332
+ return true if skip_contrast_analysis?
333
+
334
+ !ASSESS.enabled?
335
+ end
305
336
  end
306
337
  end
307
338
  end
@@ -1,8 +1,6 @@
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/core_extensions/object'
5
-
6
4
  module Contrast
7
5
  module Agent
8
6
  module Patching
@@ -7,10 +7,8 @@ cs__scoped_require 'monitor'
7
7
  cs__scoped_require 'contrast/agent/patching/policy/patch_status'
8
8
  cs__scoped_require 'contrast/agent/patching/policy/method_policy'
9
9
  cs__scoped_require 'contrast/agent/patching/policy/module_policy'
10
- cs__scoped_require 'contrast/agent/patching/policy/policy_unpatcher'
11
10
  cs__scoped_require 'contrast/components/interface'
12
11
  cs__scoped_require 'contrast/utils/class_util'
13
- cs__scoped_require 'contrast/utils/scope_util'
14
12
 
15
13
  # assess
16
14
  cs__scoped_require 'contrast/agent/assess/policy/policy'
@@ -43,7 +41,6 @@ module Contrast
43
41
  # provides a map for which methods our renamed functions need to call
44
42
  # and how.
45
43
  module Patcher
46
- extend Contrast::Utils::ScopeUtil
47
44
  extend Contrast::Agent::Patching::Policy::AfterLoadPatcher
48
45
 
49
46
  include Contrast::Components::Interface
@@ -58,7 +55,6 @@ module Contrast
58
55
  catchup_after_load_patches
59
56
  patch_methods
60
57
  Contrast::Agent::Assess::Policy::RewriterPatch.rewrite_interpolations
61
- Contrast::Agent::Patching::Policy::PolicyUnpatcher.revert_conflicting_patches
62
58
  end
63
59
  end
64
60
 
@@ -84,7 +80,8 @@ module Contrast
84
80
  # or eval of dynamic class definition
85
81
  def patch_specific_module mod
86
82
  mod_name = mod.cs__name
87
- return unless Module.cs__truly_defined?(mod_name)
83
+ return unless Contrast::Utils::ClassUtil.truly_defined?(mod_name)
84
+ return if AGENT.skip_instrumentation?(mod_name)
88
85
 
89
86
  load_patches_for_module(mod_name)
90
87
 
@@ -137,7 +134,7 @@ module Contrast
137
134
  # @param name [String] the constant whose value should be retrieved
138
135
  # @return [Object, nil]
139
136
  def patchable name
140
- return unless Module.cs__truly_defined?(name)
137
+ return unless Contrast::Utils::ClassUtil.truly_defined?(name)
141
138
 
142
139
  Module.cs__const_get(name)
143
140
  end
@@ -156,6 +153,8 @@ module Contrast
156
153
  # logger.trace_with_time("\t\tRunning patching") do # TODO: RUBY-547
157
154
  patched = []
158
155
  all_module_names.each do |patchable_name|
156
+ next if AGENT.skip_instrumentation?(patchable_name)
157
+
159
158
  patchable_mod = patchable(patchable_name)
160
159
  next unless patchable_mod
161
160
 
@@ -301,10 +300,10 @@ module Contrast
301
300
  end
302
301
 
303
302
  # core extensions
304
- cs__scoped_require 'contrast/core_extensions/module'
305
- cs__scoped_require 'contrast/core_extensions/assess'
306
- cs__scoped_require 'contrast/core_extensions/inventory'
307
- cs__scoped_require 'contrast/core_extensions/protect'
308
- cs__scoped_require 'contrast/core_extensions/protect/kernel'
303
+ cs__scoped_require 'contrast/extensions/ruby_core/module'
304
+ cs__scoped_require 'contrast/extensions/ruby_core/assess'
305
+ cs__scoped_require 'contrast/extensions/ruby_core/inventory'
306
+ cs__scoped_require 'contrast/extensions/ruby_core/protect'
307
+ cs__scoped_require 'contrast/extensions/ruby_core/protect/kernel'
309
308
 
310
309
  cs__scoped_require 'cs__contrast_patch/cs__contrast_patch'