Module: Contrast::Agent::Patching::Policy::Patch
- Extended by:
- Assess::Policy::PropagationMethod, Assess::Policy::SourceMethod, Assess::Policy::TriggerMethod, Components::Logger::InstanceMethods, Components::Scope::InstanceMethods, Utils::Patching::PatchUtils
- Defined in:
- lib/contrast/agent/patching/policy/patch.rb,
ext/cs__common/cs__common.c
Overview
This is how we patch into our customer’s code. It provides a way to track which classes we need to patch into and, once we’ve woven, provides a map for which methods our renamed functions need to call and how.
Constant Summary collapse
- POLICIES =
[ Contrast::Agent::Assess::Policy::Policy, Contrast::Agent::Inventory::Policy::Policy, Contrast::Agent::Protect::Policy::Policy ].cs__freeze
Constants included from Assess::Policy::TriggerMethod
Assess::Policy::TriggerMethod::NON_REQUEST_RULES
Constants included from Utils::Assess::PropagationMethodUtils
Utils::Assess::PropagationMethodUtils::APPEND_ACTION, Utils::Assess::PropagationMethodUtils::BUFFER_ACTION, Utils::Assess::PropagationMethodUtils::CENTER_ACTION, Utils::Assess::PropagationMethodUtils::CUSTOM_ACTION, Utils::Assess::PropagationMethodUtils::DB_WRITE_ACTION, Utils::Assess::PropagationMethodUtils::INSERT_ACTION, Utils::Assess::PropagationMethodUtils::KEEP_ACTION, Utils::Assess::PropagationMethodUtils::NEXT_ACTION, Utils::Assess::PropagationMethodUtils::NOOP_ACTION, Utils::Assess::PropagationMethodUtils::PREPEND_ACTION, Utils::Assess::PropagationMethodUtils::PROPAGATION_ACTIONS, Utils::Assess::PropagationMethodUtils::REMOVE_ACTION, Utils::Assess::PropagationMethodUtils::REPLACE_ACTION, Utils::Assess::PropagationMethodUtils::RESPONSE_ACTION, Utils::Assess::PropagationMethodUtils::REVERSE_ACTION, Utils::Assess::PropagationMethodUtils::SPLAT_ACTION, Utils::Assess::PropagationMethodUtils::SPLIT_ACTION, Utils::Assess::PropagationMethodUtils::ZERO_LENGTH_ACTIONS
Constants included from Assess::Policy::SourceMethod
Assess::Policy::SourceMethod::COOKIE_KEY_TYPE, Assess::Policy::SourceMethod::COOKIE_TYPE, Assess::Policy::SourceMethod::HEADER_KEY_TYPE, Assess::Policy::SourceMethod::HEADER_TYPE, Assess::Policy::SourceMethod::PARAMETER_KEY_TYPE, Assess::Policy::SourceMethod::PARAMETER_TYPE
Class Method Summary collapse
- .enter_method_scope!(method_policy) ⇒ Object
- .exit_method_scope!(method_policy) ⇒ Object
-
.instrument_with_alias(mod, methods, method_policy) ⇒ Boolean
If patched, either by this invocation or a previous, or not.
-
.instrument_with_prepend(mod, method_policy) ⇒ Boolean
If patched, either by this invocation or a previous, or not.
- .reflect_implementation(impl, target_module, unbound_method, visibility) ⇒ Object
- .register_c_hook(unbound_method) ⇒ Object
-
.register_c_patch(target_module_name, unbound_method, impl = :alias_instance) ⇒ Symbol
New alias for the underlying method (presumably, so the patched method can call it).
-
.skip_assess_analysis? ⇒ Boolean
Skip if we should skip_contrast_analysis?, sampling says to ignore this request, or assess has been disabled.
- .skip_contrast_analysis? ⇒ Boolean
- .underlying_method_name(method_name, impl) ⇒ Object
Methods included from Components::Scope::InstanceMethods
contrast_enter_method_scopes!, contrast_exit_method_scopes!, with_app_scope, with_contrast_scope, with_deserialization_scope, with_split_scope
Methods included from Components::Logger::InstanceMethods
Methods included from Assess::Policy::TriggerMethod
apply_eval_trigger, apply_trigger_rule, build_finding, report_finding
Methods included from Utils::Assess::TriggerMethodUtils
#apply_dataflow_rule, #apply_regexp_rule, #apply_trigger, #find_event_request, #find_request, #reportable?
Methods included from Utils::Assess::EventLimitUtils
#event_limit?, #event_limit_for_rule?, #increment_event_count
Methods included from Assess::Policy::PropagationMethod
apply_propagation, apply_propagator, apply_tags, apply_untags, context_available?
Methods included from Utils::Assess::PropagationMethodUtils
#appropriate_source?, #appropriate_target?, #can_propagate?, #determine_target, #valid_length?, #valid_target?
Methods included from Assess::Policy::SourceMethod
Methods included from Utils::Assess::SourceMethodUtils
#analyze?, #determine_source_name, #safe_invocation?
Methods included from Utils::Patching::PatchUtils
apply_assess, apply_inventory, apply_post_patch, apply_pre_patch, apply_protect, apply_trigger_only, build_method_name, build_unbound_method_name
Class Method Details
.enter_method_scope!(method_policy) ⇒ Object
51 52 53 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 51 def enter_method_scope! method_policy contrast_enter_method_scopes!(method_policy.scopes_to_enter) end |
.exit_method_scope!(method_policy) ⇒ Object
55 56 57 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 55 def exit_method_scope! method_policy contrast_exit_method_scopes!(method_policy.scopes_to_exit) end |
.instrument_with_alias(mod, methods, method_policy) ⇒ Boolean
Returns if patched, either by this invocation or a previous, or not.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 67 def instrument_with_alias mod, methods, method_policy cs_method_name = build_method_name(mod, method_policy.method_name) # we've already patched this class, don't do it again return true if methods.include?(cs_method_name) # that method is within Contrast definition so it should be skipped method = mod.instance_method(method_policy.method_name) if method_policy.instance_method method = mod.singleton_method(method_policy.method_name) unless method_policy.instance_method return true if method.owner <= Contrast begin contrast_define_method(mod, method_policy, cs_method_name) rescue NameError => e # This shouldn't happen anymore, but just in case calling alias # results in a NameError, we'll be safe here. logger.error( 'Attempted to alias a method on a Module that doesn\'t respond to it.', e, module: mod.cs__name, method: method_policy.method_name) return false end true end |
.instrument_with_prepend(mod, method_policy) ⇒ Boolean
Returns if patched, either by this invocation or a previous, or not.
98 99 100 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 98 def instrument_with_prepend mod, method_policy contrast_prepend_method(mod, method_policy) end |
.reflect_implementation(impl, target_module, unbound_method, visibility) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 161 def reflect_implementation impl, target_module, unbound_method, visibility method_name = unbound_method.name.to_sym # rubocop:disable Security/Module/Name -- ruby built in attribute. = (method_name, impl) case impl when :alias_instance, :alias_singleton # Core to patching. Ignore define method usage cop. # rubocop:disable Performance/Kernel/DefineMethod unless target_module.instance_methods(false).include?() # alias_method may be private target_module.send(:alias_method, , method_name) target_module.send(:define_method, method_name, unbound_method.bind(target_module)) end target_module.send(visibility, method_name) # e.g., module.private(:my_method) when :prepend_instance, :prepend_singleton prepending_module = Module.new prepending_module.send(:define_method, method_name, unbound_method.bind(target_module)) prepending_module.send(visibility, method_name) # This prepends to the singleton class (it patches a class method) target_module.prepend(prepending_module) # rubocop:enable Performance/Kernel/DefineMethod end end |
.register_c_hook(unbound_method) ⇒ Object
104 105 106 107 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 104 def register_c_hook unbound_method # current binding is as meaningless as any other. but we need something unbound_method.bind_call(self) end |
.register_c_patch(target_module_name, unbound_method, impl = :alias_instance) ⇒ Symbol
Returns new alias for the underlying method (presumably, so the patched method can call it).
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 119 def register_c_patch target_module_name, unbound_method, impl = :alias_instance # These could be set as AfterLoadPatches. method_name = unbound_method.name.to_sym # rubocop:disable Security/Module/Name -- ruby built in attribute. = (method_name, impl) target_module = Module.cs__const_get(target_module_name) target_module = target_module.cs__singleton_class if %i[prepend_singleton alias_singleton].include?(impl) visibility = if target_module.private_instance_methods(false).include?(method_name) :private elsif target_module.protected_instance_methods(false).include?(method_name) :protected elsif target_module.public_instance_methods(false).include?(method_name) :public else raise(NoMethodError, <<~ERR) Tried to register a C-defined #{ impl } patch for \ #{ target_module_name }##{ method_name }, but can't find :#{ method_name }. ERR end reflect_implementation(impl, target_module, unbound_method, visibility) # Ougai::Logger.create_item_with_2args calls Hash#[]=, so we # can't invoke this logging method or we'll seg fault as we'd # change the method definition mid-call # if method_name != :[]= && # Contrast::Agent::Logger.defined! # logger.trace( # 'Registered C-defined patch', # implementation: impl, # module: target_mod, # method: method_name, # visibility: visibility) # end end |
.skip_assess_analysis? ⇒ Boolean
Skip if we should skip_contrast_analysis?, sampling says to ignore this request, or assess has been disabled.
200 201 202 203 204 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 200 def skip_assess_analysis? return true if skip_contrast_analysis? !ASSESS&.enabled? end |
.skip_contrast_analysis? ⇒ Boolean
187 188 189 190 191 192 193 194 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 187 def skip_contrast_analysis? return true if in_contrast_scope? return false unless defined?(Contrast::Agent::REQUEST_TRACKER) return false unless Contrast::Agent::REQUEST_TRACKER.current return true unless Contrast::Agent::REQUEST_TRACKER.current.analyze_request? false end |
.underlying_method_name(method_name, impl) ⇒ Object
206 207 208 209 210 |
# File 'lib/contrast/agent/patching/policy/patch.rb', line 206 def method_name, impl return method_name.to_sym if %i[prepend_instance prepend_singleton].include?(impl) build_unbound_method_name(method_name).to_sym end |