contrast-agent 3.14.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +18 -15
  3. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +1 -0
  4. data/ext/cs__assess_string/cs__assess_string.c +24 -25
  5. data/ext/cs__assess_string/cs__assess_string.h +3 -1
  6. data/ext/cs__common/cs__common.c +4 -2
  7. data/ext/cs__common/cs__common.h +1 -1
  8. data/lib/contrast.rb +1 -1
  9. data/lib/contrast/agent.rb +4 -12
  10. data/lib/contrast/agent/assess.rb +1 -0
  11. data/lib/contrast/agent/assess/contrast_event.rb +143 -79
  12. data/lib/contrast/agent/assess/events/source_event.rb +1 -1
  13. data/lib/contrast/agent/assess/finalizers/freeze.rb +3 -1
  14. data/lib/contrast/agent/assess/finalizers/hash.rb +45 -1
  15. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +10 -3
  16. data/lib/contrast/agent/assess/policy/patcher.rb +1 -1
  17. data/lib/contrast/agent/assess/policy/policy.rb +0 -2
  18. data/lib/contrast/agent/assess/policy/policy_node.rb +15 -10
  19. data/lib/contrast/agent/assess/policy/policy_scanner.rb +19 -3
  20. data/lib/contrast/agent/assess/policy/preshift.rb +7 -11
  21. data/lib/contrast/agent/assess/policy/propagation_method.rb +50 -33
  22. data/lib/contrast/agent/assess/policy/propagator/append.rb +8 -5
  23. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  24. data/lib/contrast/agent/assess/policy/propagator/center.rb +9 -5
  25. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -3
  26. data/lib/contrast/agent/assess/policy/propagator/insert.rb +7 -4
  27. data/lib/contrast/agent/assess/policy/propagator/keep.rb +4 -1
  28. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +4 -7
  29. data/lib/contrast/agent/assess/policy/propagator/next.rb +7 -5
  30. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +8 -5
  31. data/lib/contrast/agent/assess/policy/propagator/remove.rb +8 -4
  32. data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -2
  33. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +7 -5
  34. data/lib/contrast/agent/assess/policy/propagator/select.rb +13 -7
  35. data/lib/contrast/agent/assess/policy/propagator/splat.rb +10 -9
  36. data/lib/contrast/agent/assess/policy/propagator/split.rb +24 -19
  37. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +47 -31
  38. data/lib/contrast/agent/assess/policy/propagator/trim.rb +11 -5
  39. data/lib/contrast/agent/assess/policy/source_method.rb +85 -58
  40. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -12
  41. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
  42. data/lib/contrast/agent/assess/policy/trigger_method.rb +76 -28
  43. data/lib/contrast/agent/assess/policy/trigger_node.rb +38 -43
  44. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +2 -1
  45. data/lib/contrast/agent/assess/properties.rb +2 -0
  46. data/lib/contrast/agent/assess/property/evented.rb +5 -18
  47. data/lib/contrast/agent/assess/property/tagged.rb +9 -3
  48. data/lib/contrast/agent/assess/property/updated.rb +131 -0
  49. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +58 -5
  50. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +23 -8
  51. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +83 -14
  52. data/lib/contrast/agent/assess/tag.rb +1 -1
  53. data/lib/contrast/agent/assess/tracker.rb +66 -0
  54. data/lib/contrast/agent/at_exit_hook.rb +5 -5
  55. data/lib/contrast/agent/class_reopener.rb +7 -5
  56. data/lib/contrast/agent/inventory.rb +15 -0
  57. data/lib/contrast/agent/inventory/dependencies.rb +50 -0
  58. data/lib/contrast/agent/inventory/dependency_analysis.rb +37 -0
  59. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +104 -0
  60. data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +38 -0
  61. data/lib/contrast/agent/middleware.rb +1 -3
  62. data/lib/contrast/agent/patching/policy/after_load_patch.rb +5 -5
  63. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +20 -20
  64. data/lib/contrast/agent/patching/policy/module_policy.rb +10 -10
  65. data/lib/contrast/agent/patching/policy/patch.rb +6 -0
  66. data/lib/contrast/agent/patching/policy/patcher.rb +13 -22
  67. data/lib/contrast/agent/patching/policy/policy.rb +17 -6
  68. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +3 -5
  69. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +4 -3
  70. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
  71. data/lib/contrast/agent/protect/rule/cmd_injection.rb +9 -25
  72. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +1 -0
  73. data/lib/contrast/agent/request.rb +34 -34
  74. data/lib/contrast/agent/request_handler.rb +1 -1
  75. data/lib/contrast/agent/response.rb +17 -6
  76. data/lib/contrast/agent/rewriter.rb +1 -3
  77. data/lib/contrast/agent/scope.rb +59 -53
  78. data/lib/contrast/agent/static_analysis.rb +7 -7
  79. data/lib/contrast/agent/tracepoint_hook.rb +1 -1
  80. data/lib/contrast/agent/version.rb +1 -1
  81. data/lib/contrast/api/communication/messaging_queue.rb +1 -4
  82. data/lib/contrast/api/communication/socket_client.rb +36 -1
  83. data/lib/contrast/api/decorators.rb +3 -0
  84. data/lib/contrast/api/decorators/address.rb +13 -14
  85. data/lib/contrast/api/decorators/application_update.rb +2 -4
  86. data/lib/contrast/api/decorators/library.rb +53 -0
  87. data/lib/contrast/api/decorators/library_usage_update.rb +30 -0
  88. data/lib/contrast/api/decorators/message.rb +1 -0
  89. data/lib/contrast/api/decorators/trace_event.rb +25 -23
  90. data/lib/contrast/common_agent_configuration.rb +2 -1
  91. data/lib/contrast/components/agent.rb +6 -5
  92. data/lib/contrast/components/app_context.rb +49 -38
  93. data/lib/contrast/components/config.rb +30 -48
  94. data/lib/contrast/components/contrast_service.rb +9 -9
  95. data/lib/contrast/components/interface.rb +25 -3
  96. data/lib/contrast/components/inventory.rb +6 -1
  97. data/lib/contrast/components/scope.rb +49 -6
  98. data/lib/contrast/components/settings.rb +23 -23
  99. data/lib/contrast/config/application_configuration.rb +5 -2
  100. data/lib/contrast/config/inventory_configuration.rb +2 -2
  101. data/lib/contrast/config/service_configuration.rb +8 -0
  102. data/lib/contrast/configuration.rb +88 -47
  103. data/lib/contrast/extension/assess.rb +0 -2
  104. data/lib/contrast/extension/assess/array.rb +15 -8
  105. data/lib/contrast/extension/assess/erb.rb +11 -3
  106. data/lib/contrast/extension/assess/eval_trigger.rb +6 -6
  107. data/lib/contrast/extension/assess/exec_trigger.rb +1 -4
  108. data/lib/contrast/extension/assess/fiber.rb +12 -12
  109. data/lib/contrast/extension/assess/hash.rb +5 -6
  110. data/lib/contrast/extension/assess/kernel.rb +28 -23
  111. data/lib/contrast/extension/assess/marshal.rb +11 -6
  112. data/lib/contrast/extension/assess/regexp.rb +8 -7
  113. data/lib/contrast/extension/assess/string.rb +21 -21
  114. data/lib/contrast/extension/protect/kernel.rb +3 -3
  115. data/lib/contrast/framework/base_support.rb +1 -1
  116. data/lib/contrast/framework/manager.rb +3 -3
  117. data/lib/contrast/framework/rack/patch/session_cookie.rb +22 -28
  118. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +13 -13
  119. data/lib/contrast/framework/rails/patch/assess_configuration.rb +5 -11
  120. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +10 -10
  121. data/lib/contrast/framework/rails/patch/support.rb +1 -1
  122. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +11 -11
  123. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +12 -12
  124. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -3
  125. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +12 -12
  126. data/lib/contrast/framework/rails/support.rb +5 -0
  127. data/lib/contrast/framework/sinatra/patch/base.rb +11 -11
  128. data/lib/contrast/framework/sinatra/support.rb +4 -4
  129. data/lib/contrast/logger/application.rb +11 -3
  130. data/lib/contrast/logger/log.rb +7 -2
  131. data/lib/contrast/utils/assess/tracking_util.rb +48 -3
  132. data/lib/contrast/utils/duck_utils.rb +0 -10
  133. data/lib/contrast/utils/env_configuration_item.rb +2 -1
  134. data/lib/contrast/utils/invalid_configuration_util.rb +20 -21
  135. data/lib/contrast/utils/inventory_util.rb +0 -7
  136. data/lib/contrast/utils/sha256_builder.rb +0 -12
  137. data/lib/contrast/utils/string_utils.rb +10 -5
  138. data/resources/assess/policy.json +31 -22
  139. data/ruby-agent.gemspec +21 -18
  140. data/service_executables/VERSION +1 -1
  141. data/service_executables/linux/contrast-service +0 -0
  142. data/service_executables/mac/contrast-service +0 -0
  143. metadata +71 -30
  144. data/lib/contrast/agent/assess/finalizers/finalize.rb +0 -21
  145. data/lib/contrast/extension/assess/assess_extension.rb +0 -145
  146. data/lib/contrast/utils/boolean_util.rb +0 -30
  147. data/lib/contrast/utils/freeze_util.rb +0 -32
  148. data/lib/contrast/utils/gemfile_reader.rb +0 -193
@@ -0,0 +1,37 @@
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/inventory/dependencies'
5
+ require 'contrast/components/interface'
6
+ require 'contrast/utils/object_share'
7
+
8
+ module Contrast
9
+ module Agent
10
+ module Inventory
11
+ # Used to collect dependencies of the application for reporting
12
+ class DependencyAnalysis
13
+ include Singleton
14
+ include Contrast::Agent::Inventory::Dependencies
15
+ include Contrast::Components::Interface
16
+
17
+ access_component :analysis
18
+
19
+ # Report the dependencies of this application
20
+ #
21
+ # @return [Array<Contrast::Api::Dtm::Library>] protobuf form of the
22
+ # Gem::Specification that have been loaded for this application.
23
+ def library_pb_list
24
+ return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless INVENTORY.enabled?
25
+ return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless INVENTORY.analyze_libraries?
26
+
27
+ loaded_specs.each_with_object([]) do |(_name, spec), reported_lib_list|
28
+ next unless spec
29
+ next unless (digest = Contrast::Utils::Sha256Builder.instance.build_from_spec(spec))
30
+
31
+ reported_lib_list << Contrast::Api::Dtm::Library.build(digest, spec)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,104 @@
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/inventory/gemfile_digest_cache'
5
+ require 'contrast/agent/inventory/dependencies'
6
+ require 'contrast/components/interface'
7
+ require 'contrast/utils/object_share'
8
+
9
+ module Contrast
10
+ module Agent
11
+ module Inventory
12
+ # Used to analyze class usage for reporting
13
+ class DependencyUsageAnalysis
14
+ include Singleton
15
+ include Contrast::Components::Interface
16
+ include Contrast::Agent::Inventory::Dependencies
17
+
18
+ access_component :analysis, :config, :logging
19
+
20
+ def initialize
21
+ return unless enabled?
22
+
23
+ @gemdigest_cache = Contrast::Agent::Inventory::GemfileDigestCache.new
24
+ end
25
+
26
+ # This method is invoked once, along with the rest of our catchup code
27
+ # to report libraries and their associated files that have already been loaded pre-contrast
28
+ def catchup
29
+ return unless enabled?
30
+
31
+ loaded_specs.each do |_name, spec|
32
+ # Get a digest of the Gem file itself
33
+ next unless (digest = Contrast::Utils::Sha256Builder.instance.build_from_spec(spec))
34
+
35
+ @gemdigest_cache.use_cache(digest) do |existing_files|
36
+ loaded_files_from_gem = $LOADED_FEATURES.select { |f| f.start_with?(spec.full_gem_path) }
37
+ loaded_files_from_gem.each do |file_path|
38
+ logger.trace('Recording loaded file for inventory analysis', line: file_path)
39
+ existing_files << adjust_path_for_reporting(file_path, spec)
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ # This method is invoked once per TracePoint :end - to map a specific
46
+ # file being required to the gem it belongs to
47
+ #
48
+ # @param path [String] the result of TracePoint#path from the :end
49
+ # event in which the Module was defined
50
+ def associate_file path
51
+ return unless enabled?
52
+
53
+ spec_lookup_path = adjust_path_for_spec_lookup(path)
54
+
55
+ spec = Gem::Specification.find_by_path(spec_lookup_path)
56
+ unless spec
57
+ logger.debug('Unable to resolve gem spec for path', path: path)
58
+ return
59
+ end
60
+
61
+ digest = Contrast::Utils::Sha256Builder.instance.build_from_spec(spec)
62
+ unless digest
63
+ logger.debug('Unable to resolve digest for gem spec', spec: spec.to_s)
64
+ return
65
+ end
66
+ report_path = adjust_path_for_reporting(path, spec)
67
+ @gemdigest_cache.get(digest) << report_path
68
+ rescue StandardError => e
69
+ logger.error('Unable to inventory file path', e, path: path)
70
+ end
71
+
72
+ # Populate the library_usages filed of the Activity message using the
73
+ # data stored in the @gemdigest_cache
74
+ #
75
+ # @param activity [Contrast::Api::Dtm::Activity] the message to which
76
+ # to append the usage data
77
+ def generate_library_usage activity
78
+ return unless enabled?
79
+ return if @gemdigest_cache.empty?
80
+
81
+ @gemdigest_cache.generate_usage_data(activity)
82
+ end
83
+
84
+ private
85
+
86
+ def adjust_path_for_spec_lookup path
87
+ idx = path.index('/lib/')
88
+ path = path[(idx + 4)..-1] if idx
89
+ path
90
+ end
91
+
92
+ def adjust_path_for_reporting path, gem_spec
93
+ path.delete_prefix(gem_spec.full_gem_path)
94
+ end
95
+
96
+ # We only use this if inventory and library analysis are enabled
97
+ def enabled?
98
+ @_enabled = INVENTORY.enabled? && INVENTORY.analyze_libraries? if @_enabled.nil?
99
+ @_enabled
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,38 @@
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
+ module Contrast
5
+ module Agent
6
+ module Inventory
7
+ # Keeps a map of gem digest to files for reporting file usage
8
+ class GemfileDigestCache
9
+ extend Forwardable
10
+ def_delegator :@gem_spec_digest_to_files,
11
+ :empty?
12
+
13
+ def initialize
14
+ @gem_spec_digest_to_files = {}
15
+ end
16
+
17
+ def generate_usage_data activity
18
+ return unless activity
19
+
20
+ @gem_spec_digest_to_files.each_pair do |digest, files|
21
+ usage = Contrast::Api::Dtm::LibraryUsageUpdate.build(digest, files)
22
+ activity.library_usages[usage.hash_code] = usage if activity
23
+ end
24
+ @gem_spec_digest_to_files.clear
25
+ end
26
+
27
+ def use_cache digest
28
+ yield get(digest)
29
+ end
30
+
31
+ def get digest
32
+ @gem_spec_digest_to_files[digest] = Set.new unless @gem_spec_digest_to_files.key?(digest)
33
+ @gem_spec_digest_to_files[digest]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -13,7 +13,6 @@ require 'contrast/agent/request_handler'
13
13
  require 'contrast/agent/static_analysis'
14
14
 
15
15
  require 'contrast/utils/timer'
16
- require 'contrast/utils/freeze_util'
17
16
 
18
17
  module Contrast
19
18
  module Agent
@@ -95,8 +94,7 @@ module Contrast
95
94
  if CONFIG.invalid?
96
95
  AGENT.disable!
97
96
  logger.error('!!! CONFIG FILE IS INVALID - DISABLING CONTRAST AGENT !!!')
98
- elsif CONFIG.disabled?
99
- AGENT.disable!
97
+ elsif AGENT.disabled?
100
98
  logger.warn('Contrast disabled by configuration. Continuing without instrumentation.')
101
99
  else
102
100
  AGENT.enable!
@@ -15,7 +15,7 @@ module Contrast
15
15
  access_component :scope
16
16
  attr_reader :applied, :module_name, :instrumentation_file_path, :method_to_instrument, :instrumenting_module
17
17
 
18
- def initialize module_name, instrumentation_file_path, method_to_instrument: nil, instrumenting_module:
18
+ def initialize module_name, instrumentation_file_path, method_to_instrument: nil, instrumenting_module: nil
19
19
  @applied = false
20
20
  @module_name = module_name
21
21
  @method_to_instrument = method_to_instrument
@@ -71,10 +71,10 @@ module Contrast
71
71
 
72
72
  def module_lookup
73
73
  @_module_lookup ||= begin
74
- Module.cs__const_get module_name
75
- rescue StandardError => _e
76
- nil
77
- end
74
+ Module.cs__const_get module_name
75
+ rescue StandardError => _e
76
+ nil
77
+ end
78
78
  end
79
79
  end
80
80
  end
@@ -30,20 +30,20 @@ module Contrast
30
30
  # extensions.
31
31
  def apply_direct_patches!
32
32
  @_apply_direct_patches ||= begin
33
- Contrast::Extension::Assess::ArrayPropagator.instrument_array_track
34
- Contrast::Extension::Assess::EvalTrigger.instrument_basic_object_track
35
- Contrast::Extension::Assess::EvalTrigger.instrument_module_track
36
- Contrast::Extension::Assess::FiberPropagator.instrument_fiber_track
37
- Contrast::Extension::Assess::HashPropagator.instrument_hash_track
38
- Contrast::Extension::Assess::KernelPropagator.instrument_kernel_track
39
- Contrast::Extension::Assess::MarshalPropagator.instrument_marshal_load
40
- Contrast::Extension::Assess::RegexpPropagator.instrument_regexp_track
41
- Contrast::Extension::Assess::StringPropagator.instrument_string
42
- Contrast::Extension::Assess::StringPropagator.instrument_string_interpolation
33
+ Contrast::Extension::Assess::ArrayPropagator.instrument_array_track
34
+ Contrast::Extension::Assess::EvalTrigger.instrument_basic_object_track
35
+ Contrast::Extension::Assess::EvalTrigger.instrument_module_track
36
+ Contrast::Extension::Assess::FiberPropagator.instrument_fiber_track
37
+ Contrast::Extension::Assess::HashPropagator.instrument_hash_track
38
+ Contrast::Extension::Assess::KernelPropagator.instrument_kernel_track
39
+ Contrast::Extension::Assess::MarshalPropagator.instrument_marshal_load
40
+ Contrast::Extension::Assess::RegexpPropagator.instrument_regexp_track
41
+ Contrast::Extension::Assess::StringPropagator.instrument_string
42
+ Contrast::Extension::Assess::StringPropagator.instrument_string_interpolation
43
43
 
44
- Contrast::Extension::Protect::Kernel.instrument
45
- true
46
- end
44
+ Contrast::Extension::Protect::Kernel.instrument
45
+ true
46
+ end
47
47
  end
48
48
 
49
49
  def apply_load_patches!
@@ -65,13 +65,13 @@ module Contrast
65
65
  # handling
66
66
  def apply_require_patches!
67
67
  @_apply_require_patches ||= begin
68
- require 'contrast/extension/thread'
69
- require 'contrast/extension/kernel'
70
- true
71
- rescue LoadError, StandardError => e
72
- logger.error('failed instrumenting apply_require_patches!', e)
73
- false
74
- end
68
+ require 'contrast/extension/thread'
69
+ require 'contrast/extension/kernel'
70
+ true
71
+ rescue LoadError, StandardError => e
72
+ logger.error('failed instrumenting apply_require_patches!', e)
73
+ false
74
+ end
75
75
  end
76
76
 
77
77
  def after_load_patches
@@ -61,16 +61,16 @@ module Contrast
61
61
  # @return [Integer] count of methods to be patched
62
62
  def num_expected_patches
63
63
  @_num_expected_patches ||= begin
64
- instance_methods = Set.new
65
- singleton_methods = Set.new
66
- sort_method_names(source_nodes, instance_methods, singleton_methods)
67
- sort_method_names(propagator_nodes, instance_methods, singleton_methods)
68
- sort_method_names(trigger_nodes, instance_methods, singleton_methods)
69
- sort_method_names(inventory_nodes, instance_methods, singleton_methods)
70
- sort_method_names(protect_nodes, instance_methods, singleton_methods)
71
- sort_method_names(deadzone_nodes, instance_methods, singleton_methods)
72
- instance_methods.length + singleton_methods.length
73
- end
64
+ instance_methods = Set.new
65
+ singleton_methods = Set.new
66
+ sort_method_names(source_nodes, instance_methods, singleton_methods)
67
+ sort_method_names(propagator_nodes, instance_methods, singleton_methods)
68
+ sort_method_names(trigger_nodes, instance_methods, singleton_methods)
69
+ sort_method_names(inventory_nodes, instance_methods, singleton_methods)
70
+ sort_method_names(protect_nodes, instance_methods, singleton_methods)
71
+ sort_method_names(deadzone_nodes, instance_methods, singleton_methods)
72
+ instance_methods.length + singleton_methods.length
73
+ end
74
74
  end
75
75
 
76
76
  private
@@ -365,12 +365,18 @@ module Contrast
365
365
  unless target_module.instance_methods(false).include? underlying_method_name
366
366
  # alias_method may be private
367
367
  target_module.send(:alias_method, underlying_method_name, method_name)
368
+ # TODO: RUBY-1052
369
+ # rubocop:disable Kernel/DefineMethod
368
370
  target_module.send(:define_method, method_name, unbound_method.bind(target_module))
371
+ # rubocop:enable Kernel/DefineMethod
369
372
  end
370
373
  target_module.send(visibility, method_name) # e.g., module.private(:my_method)
371
374
  when :prepend
372
375
  prepending_module = Module.new
376
+ # TODO: RUBY-1052
377
+ # rubocop:disable Kernel/DefineMethod
373
378
  prepending_module.send(:define_method, method_name, unbound_method.bind(target_module))
379
+ # rubocop:enable Kernel/DefineMethod
374
380
  prepending_module.send(visibility, method_name)
375
381
  # This prepends to the singleton class (it patches a class method)
376
382
  target_module.prepend prepending_module
@@ -77,19 +77,21 @@ module Contrast
77
77
  # This method is called by TracePointHook to instrument a specific class during a require
78
78
  # or eval of dynamic class definition
79
79
  def patch_specific_module mod
80
- mod_name = mod.cs__name
81
- return unless Contrast::Utils::ClassUtil.truly_defined?(mod_name)
82
- return if AGENT.skip_instrumentation?(mod_name)
80
+ with_contrast_scope do
81
+ mod_name = mod.cs__name
82
+ return unless Contrast::Utils::ClassUtil.truly_defined?(mod_name)
83
+ return if AGENT.skip_instrumentation?(mod_name)
83
84
 
84
- load_patches_for_module(mod_name)
85
+ load_patches_for_module(mod_name)
85
86
 
86
- return unless all_module_names.any? { |name| name == mod_name }
87
+ return unless all_module_names.any? { |name| name == mod_name }
87
88
 
88
- module_data = Contrast::Agent::ModuleData.new(mod, mod_name)
89
- patch_into_module(module_data)
90
- all_module_names.delete(mod_name) if status_type.get_status(mod).patched?
91
- rescue StandardError => e
92
- logger.error('Unable to patch module', e, module: mod_name)
89
+ module_data = Contrast::Agent::ModuleData.new(mod, mod_name)
90
+ patch_into_module(module_data)
91
+ all_module_names.delete(mod_name) if status_type.get_status(mod).patched?
92
+ rescue StandardError => e
93
+ logger.error('Unable to patch module', e, module: mod_name)
94
+ end
93
95
  end
94
96
 
95
97
  # We did it, team. We found a patcher(s) that applies to the given
@@ -186,7 +188,7 @@ module Contrast
186
188
  clazz = module_data.mod
187
189
 
188
190
  status.patching!
189
- patched = include_module(module_data)
191
+ patched = false
190
192
 
191
193
  counts = 0
192
194
  # Monkey patch any methods in this class that have matching nodes in the policy
@@ -219,17 +221,6 @@ module Contrast
219
221
  module_data.mod).patch_status)
220
222
  end
221
223
 
222
- # Includes the given module with the
223
- # Contrast::Extension::Assess::AssessExtension
224
- # @param module_data [Contrast::Agent::ModuleData] the module, and
225
- # its name, that's being patched into
226
- def include_module module_data
227
- return false unless Contrast::Agent::Assess::Policy::Policy.instance.tracked_classes.include?(module_data.name)
228
-
229
- module_data.mod.send(:include, Contrast::Extension::Assess::AssessExtension)
230
- true
231
- end
232
-
233
224
  # Get all of the instance methods on the given module, excluding
234
225
  # those from super classes. this list will always include the
235
226
  # initialize method
@@ -37,13 +37,12 @@ module Contrast
37
37
 
38
38
  access_component :analysis, :logging
39
39
 
40
- attr_reader :sources, :propagators, :triggers, :providers, :tracked_classes
40
+ attr_reader :sources, :propagators, :triggers, :providers
41
41
 
42
42
  SOURCES_KEY = 'sources'
43
43
  PROPAGATION_KEY = 'propagators'
44
44
  RULES_KEY = 'rules'
45
45
  TRIGGERS_KEY = 'triggers'
46
- TRACKED_CLASSES_KEY = 'tracked_classes'
47
46
 
48
47
  def self.policy_json
49
48
  File.join(policy_folder, 'policy.json').cs__freeze
@@ -54,7 +53,6 @@ module Contrast
54
53
  @propagators = []
55
54
  @triggers = []
56
55
  @providers = {}
57
- @tracked_classes = []
58
56
 
59
57
  json = Contrast::Utils::ResourceLoader.load(cs__class.policy_json)
60
58
  from_hash_string(json)
@@ -114,7 +112,6 @@ module Contrast
114
112
  def module_names
115
113
  @_module_names ||= begin
116
114
  m = Set.new
117
- tracked_classes.each { |tracked| m << tracked }
118
115
  sources.each { |source| m << source.class_name }
119
116
  propagators.each { |propagator| m << propagator.class_name }
120
117
  triggers.each { |trigger| m << trigger.class_name }
@@ -127,12 +124,26 @@ module Contrast
127
124
  end
128
125
 
129
126
  def find_source_node class_name, method_name, instance_method
130
- sources.find { |source| source.class_name == class_name && source.method_name == method_name && source.instance_method == instance_method }
127
+ sources.find do |source|
128
+ source.class_name == class_name &&
129
+ source.method_name == method_name &&
130
+ source.instance_method == instance_method
131
+ end
132
+ end
133
+
134
+ def find_propagator_node class_name, method_name, instance_method
135
+ propagators.find do |propagator|
136
+ propagator.class_name == class_name &&
137
+ propagator.method_name == method_name &&
138
+ propagator.instance_method == instance_method
139
+ end
131
140
  end
132
141
 
133
142
  def find_node rule_id, class_name, method_name, instance_method
134
143
  find_triggers_by_rule(rule_id).find do |node|
135
- node.class_name == class_name && node.method_name == method_name && node.instance_method == instance_method
144
+ node.class_name == class_name &&
145
+ node.method_name == method_name &&
146
+ node.instance_method == instance_method
136
147
  end
137
148
  end
138
149
  end
@@ -30,11 +30,9 @@ module Contrast
30
30
  Contrast::Agent::Protect::Policy::AppliesDeserializationRule.apply_deserialization_command_check(command)
31
31
  return if skip_analysis?
32
32
 
33
- begin
34
- clazz = object.is_a?(Module) ? object : object.cs__class
35
- class_name = clazz.cs__name
36
- rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, class_name, method, command)
37
- end
33
+ clazz = object.is_a?(Module) ? object : object.cs__class
34
+ class_name = clazz.cs__name
35
+ rule.infilter(Contrast::Agent::REQUEST_TRACKER.current, class_name, method, command)
38
36
  end
39
37
 
40
38
  protected