Class: Contrast::Agent::Assess::Policy::Propagator::Split
- Includes:
- Components::Interface
- Defined in:
- lib/contrast/agent/assess/policy/propagator/split.rb,
ext/cs__assess_yield_track/cs__assess_yield_track.c
Overview
This class is specifically for String#split & String#grapheme_clusters propagation it propagates tag ranges from a string to elements within an untracked array
Constant Summary collapse
- SPLIT_TRACKER =
Contrast::Utils::ThreadTracker.new
Class Method Summary collapse
-
.begin_split(string, args) ⇒ Object
Marks the point in which the String#split method is called.
-
.end_split ⇒ Object
Marks the point in which the String#split method is exited.
- .instrument_string_split ⇒ Object
-
.propagate(propagation_node, preshift, target) ⇒ nil
Propagate taint from a source as it is split into composite sections.
-
.propagate_yield(target) ⇒ Object
This method is called whenever an rb_yield is called.
Methods included from Components::Interface
Methods inherited from Base
Class Method Details
.begin_split(string, args) ⇒ Object
Marks the point in which the String#split method is called. Responsible for building the context required to propagate when the results of #split are yielded directly to a block
81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/contrast/agent/assess/policy/propagator/split.rb', line 81 def begin_split string, args save_split_depth! depth = SPLIT_TRACKER.get(:split_depth) save_split_index!(depth) save_split_value!(depth, string, args) rescue Exception => e # rubocop:disable Lint/RescueException # don't let our errors propagate and disable String#split for # this since we're in an error state logger.warn('Unable to record split context', e) end_split end |
.end_split ⇒ Object
Marks the point in which the String#split method is exited. Responsible for removing the context required to propagate when the results of #split are yielded directly to a block
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/contrast/agent/assess/policy/propagator/split.rb', line 96 def end_split depth = SPLIT_TRACKER.get(:split_depth) return unless depth depth -= 1 if depth.negative? SPLIT_TRACKER.delete(:split_depth) SPLIT_TRACKER.delete(:split_index) SPLIT_TRACKER.delete(:split_value) else SPLIT_TRACKER.set(:split_depth, depth) end rescue StandardError => e logger.warn('Unable to remove split context', e) end |
.instrument_string_split ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/contrast/agent/assess/policy/propagator/split.rb', line 144 def instrument_string_split if @_instrument_string_split.nil? @_instrument_string_split = begin require 'cs__assess_yield_track/cs__assess_yield_track' if AGENT.patch_yield? && Funchook.available? true rescue StandardError => e logger.error('Error loading split rb_yield patch', e) false end end @_instrument_string_split end |
.propagate(propagation_node, preshift, target) ⇒ nil
Propagate taint from a source as it is split into composite sections. This method MUST return nil, otherwise it risks changing the result of of the propagation.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/contrast/agent/assess/policy/propagator/split.rb', line 33 def propagate propagation_node, preshift, target logger.trace('Propagation detected', node_id: propagation_node.id, target_id: target.__id__) unless target.is_a?(Array) Contrast::Agent::Assess::Policy::Propagator::Keep.propagate(propagation_node, preshift, target) properties = Contrast::Agent::Assess::Tracker.properties(target) properties.build_event(propagation_node, target, object, ret, args) return end source = find_source(propagation_node.sources[0], preshift) separator_length = if propagation_node.method_name == :grapheme_clusters # grapheme_clusters break the string apart based on each "user-perceived" character 0 else # The default for String#split is to use a single whitespace preshift&.args&.first&.to_s&.length || $FIELD_SEPARATOR&.to_s&.length || 1 end current_index = 0 target.each do |elem| elem_length = elem.length range = current_index...(current_index + elem_length) elem_properties = Contrast::Agent::Assess::Tracker.properties(elem) next unless elem_properties source_properties = Contrast::Agent::Assess::Tracker.properties(source) = source_properties.(range) elem_properties. .each_pair do |key, value| elem_properties.(key, value) end elem_properties.build_event(propagation_node, elem, preshift.object, target, preshift.args, 0) elem_properties.add_properties(propagation_node.properties) current_index = current_index + elem_length + separator_length end nil end |
.propagate_yield(target) ⇒ Object
This method is called whenever an rb_yield is called. We need to leave it as soon as possible with as little work as possible.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/contrast/agent/assess/policy/propagator/split.rb', line 118 def propagate_yield target depth, index = nil depth = SPLIT_TRACKER.get(:split_depth) return unless depth source = SPLIT_TRACKER.get(:split_value)&.fetch(depth) return unless source index = SPLIT_TRACKER.get(:split_index)&.fetch(depth) return unless index properties = Contrast::Agent::Assess::Tracker.properties(target) return unless properties true_source = source[index] properties.copy_from(true_source, target) rescue StandardError => e logger.warn('Unable to track within split context', e) ensure if depth && index idx = SPLIT_TRACKER.get(:split_index) idx[depth] = index + 1 if defined?(idx) && idx.is_a?(Array) end end |