contrast-agent 6.2.0 → 6.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/.simplecov +1 -0
  4. data/Rakefile +0 -27
  5. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +7 -5
  6. data/ext/cs__assess_kernel/cs__assess_kernel.c +14 -3
  7. data/ext/cs__assess_kernel/cs__assess_kernel.h +2 -0
  8. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +10 -3
  9. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +2 -1
  10. data/ext/cs__assess_regexp/cs__assess_regexp.c +9 -7
  11. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.c → cs__assess_string_interpolation/cs__assess_string_interpolation.c} +14 -3
  12. data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.h → cs__assess_string_interpolation/cs__assess_string_interpolation.h} +1 -1
  13. data/ext/{cs__assess_string_interpolation26 → cs__assess_string_interpolation}/extconf.rb +0 -0
  14. data/ext/cs__common/cs__common.c +5 -4
  15. data/ext/cs__contrast_patch/cs__contrast_patch.c +17 -11
  16. data/lib/contrast/agent/assess/events/source_event.rb +16 -12
  17. data/lib/contrast/agent/assess/finalizers/hash.rb +1 -0
  18. data/lib/contrast/agent/assess/policy/policy_node.rb +6 -0
  19. data/lib/contrast/agent/assess/policy/propagation_method.rb +8 -42
  20. data/lib/contrast/agent/assess/policy/propagation_node.rb +8 -0
  21. data/lib/contrast/agent/assess/policy/propagator/base.rb +2 -0
  22. data/lib/contrast/agent/assess/policy/propagator/custom.rb +4 -0
  23. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -0
  24. data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -0
  25. data/lib/contrast/agent/assess/policy/source_method.rb +7 -47
  26. data/lib/contrast/agent/assess/policy/source_node.rb +1 -0
  27. data/lib/contrast/agent/assess/policy/trigger_method.rb +9 -3
  28. data/lib/contrast/agent/assess/policy/trigger_node.rb +8 -0
  29. data/lib/contrast/agent/assess/property/evented.rb +4 -18
  30. data/lib/contrast/agent/assess/tag.rb +19 -0
  31. data/lib/contrast/agent/assess/tracker.rb +12 -0
  32. data/lib/contrast/agent/at_exit_hook.rb +8 -8
  33. data/lib/contrast/agent/inventory/database_config.rb +6 -3
  34. data/lib/contrast/agent/inventory/dependency_analysis.rb +5 -4
  35. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +11 -11
  36. data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
  37. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  38. data/lib/contrast/agent/middleware.rb +4 -0
  39. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +27 -2
  40. data/lib/contrast/agent/patching/policy/method_policy.rb +3 -3
  41. data/lib/contrast/agent/patching/policy/policy.rb +5 -0
  42. data/lib/contrast/agent/patching/policy/policy_node.rb +6 -0
  43. data/lib/contrast/agent/patching/policy/trigger_node.rb +3 -0
  44. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +3 -4
  45. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -0
  46. data/lib/contrast/agent/protect/policy/rule_applicator.rb +2 -2
  47. data/lib/contrast/agent/protect/rule/base.rb +1 -0
  48. data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -0
  49. data/lib/contrast/agent/reporting/reporter.rb +32 -7
  50. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +22 -18
  51. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +17 -21
  52. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -1
  53. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +26 -3
  54. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
  55. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
  56. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +8 -1
  57. data/lib/contrast/agent/reporting/reporting_events/finding.rb +7 -1
  58. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
  59. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
  60. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
  61. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
  62. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
  63. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
  64. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
  65. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
  66. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
  67. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
  68. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +13 -1
  69. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -8
  70. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +12 -5
  71. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +8 -1
  72. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +9 -1
  73. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
  74. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
  75. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
  76. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -4
  77. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -22
  78. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -3
  79. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
  80. data/lib/contrast/agent/request.rb +5 -7
  81. data/lib/contrast/agent/request_context.rb +16 -17
  82. data/lib/contrast/agent/request_context_extend.rb +8 -9
  83. data/lib/contrast/agent/request_handler.rb +9 -38
  84. data/lib/contrast/agent/rule_set.rb +4 -0
  85. data/lib/contrast/agent/service_heartbeat.rb +3 -4
  86. data/lib/contrast/agent/static_analysis.rb +7 -12
  87. data/lib/contrast/agent/telemetry/base.rb +35 -35
  88. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
  89. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
  90. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
  91. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
  92. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
  93. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
  94. data/lib/contrast/agent/thread_watcher.rb +1 -4
  95. data/lib/contrast/agent/version.rb +1 -1
  96. data/lib/contrast/agent/worker_thread.rb +10 -0
  97. data/lib/contrast/api/communication/socket.rb +1 -0
  98. data/lib/contrast/api/decorators/message.rb +0 -6
  99. data/lib/contrast/api/decorators.rb +0 -2
  100. data/lib/contrast/api/dtm.pb.rb +1 -1
  101. data/lib/contrast/api/settings.pb.rb +1 -1
  102. data/lib/contrast/components/agent.rb +51 -13
  103. data/lib/contrast/components/assess.rb +16 -6
  104. data/lib/contrast/components/config.rb +18 -2
  105. data/lib/contrast/components/contrast_service.rb +1 -1
  106. data/lib/contrast/components/heap_dump.rb +51 -1
  107. data/lib/contrast/components/inventory.rb +19 -13
  108. data/lib/contrast/components/logger.rb +18 -0
  109. data/lib/contrast/config/assess_configuration.rb +28 -0
  110. data/lib/contrast/config/base_configuration.rb +8 -15
  111. data/lib/contrast/config/root_configuration.rb +12 -8
  112. data/lib/contrast/config/ruby_configuration.rb +2 -9
  113. data/lib/contrast/config/service_configuration.rb +4 -4
  114. data/lib/contrast/config.rb +0 -6
  115. data/lib/contrast/configuration.rb +0 -2
  116. data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
  117. data/lib/contrast/extension/assess/hash.rb +3 -2
  118. data/lib/contrast/extension/assess/kernel.rb +22 -0
  119. data/lib/contrast/extension/assess/marshal.rb +16 -0
  120. data/lib/contrast/extension/assess/string.rb +21 -20
  121. data/lib/contrast/extension/object.rb +19 -0
  122. data/lib/contrast/framework/base_support.rb +8 -0
  123. data/lib/contrast/framework/manager.rb +6 -20
  124. data/lib/contrast/framework/manager_extend.rb +0 -1
  125. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -16
  126. data/lib/contrast/framework/rails/support.rb +4 -1
  127. data/lib/contrast/logger/aliased_logging.rb +2 -0
  128. data/lib/contrast/logger/log.rb +2 -1
  129. data/lib/contrast/utils/assess/event_limit_utils.rb +96 -0
  130. data/lib/contrast/utils/assess/propagation_method_utils.rb +27 -7
  131. data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
  132. data/lib/contrast/utils/log_utils.rb +2 -2
  133. data/lib/contrast/utils/lru_cache.rb +3 -0
  134. data/lib/contrast/utils/middleware_utils.rb +2 -0
  135. data/lib/contrast/utils/patching/policy/patch_utils.rb +6 -23
  136. data/lib/contrast/utils/telemetry_client.rb +7 -7
  137. data/lib/contrast.rb +37 -18
  138. data/lib/protobuf/code_generator.rb +129 -0
  139. data/lib/protobuf/decoder.rb +28 -0
  140. data/lib/protobuf/deprecation.rb +117 -0
  141. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +79 -0
  142. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +360 -0
  143. data/lib/protobuf/descriptors.rb +3 -0
  144. data/lib/protobuf/encoder.rb +11 -0
  145. data/lib/protobuf/enum.rb +365 -0
  146. data/lib/protobuf/exceptions.rb +9 -0
  147. data/lib/protobuf/field/base_field.rb +380 -0
  148. data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
  149. data/lib/protobuf/field/bool_field.rb +64 -0
  150. data/lib/protobuf/field/bytes_field.rb +67 -0
  151. data/lib/protobuf/field/double_field.rb +25 -0
  152. data/lib/protobuf/field/enum_field.rb +56 -0
  153. data/lib/protobuf/field/field_array.rb +102 -0
  154. data/lib/protobuf/field/field_hash.rb +122 -0
  155. data/lib/protobuf/field/fixed32_field.rb +25 -0
  156. data/lib/protobuf/field/fixed64_field.rb +28 -0
  157. data/lib/protobuf/field/float_field.rb +43 -0
  158. data/lib/protobuf/field/int32_field.rb +21 -0
  159. data/lib/protobuf/field/int64_field.rb +34 -0
  160. data/lib/protobuf/field/integer_field.rb +23 -0
  161. data/lib/protobuf/field/message_field.rb +51 -0
  162. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  163. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  164. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  165. data/lib/protobuf/field/sint32_field.rb +21 -0
  166. data/lib/protobuf/field/sint64_field.rb +21 -0
  167. data/lib/protobuf/field/string_field.rb +51 -0
  168. data/lib/protobuf/field/uint32_field.rb +21 -0
  169. data/lib/protobuf/field/uint64_field.rb +21 -0
  170. data/lib/protobuf/field/varint_field.rb +77 -0
  171. data/lib/protobuf/field.rb +74 -0
  172. data/lib/protobuf/generators/base.rb +85 -0
  173. data/lib/protobuf/generators/enum_generator.rb +39 -0
  174. data/lib/protobuf/generators/extension_generator.rb +27 -0
  175. data/lib/protobuf/generators/field_generator.rb +193 -0
  176. data/lib/protobuf/generators/file_generator.rb +262 -0
  177. data/lib/protobuf/generators/group_generator.rb +122 -0
  178. data/lib/protobuf/generators/message_generator.rb +104 -0
  179. data/lib/protobuf/generators/option_generator.rb +17 -0
  180. data/lib/protobuf/generators/printable.rb +160 -0
  181. data/lib/protobuf/generators/service_generator.rb +50 -0
  182. data/lib/protobuf/lifecycle.rb +33 -0
  183. data/lib/protobuf/logging.rb +39 -0
  184. data/lib/protobuf/message/fields.rb +233 -0
  185. data/lib/protobuf/message/serialization.rb +85 -0
  186. data/lib/protobuf/message.rb +241 -0
  187. data/lib/protobuf/optionable.rb +72 -0
  188. data/lib/protobuf/tasks/compile.rake +80 -0
  189. data/lib/protobuf/tasks.rb +1 -0
  190. data/lib/protobuf/varint.rb +20 -0
  191. data/lib/protobuf/varint_pure.rb +31 -0
  192. data/lib/protobuf/version.rb +3 -0
  193. data/lib/protobuf/wire_type.rb +10 -0
  194. data/lib/protobuf.rb +91 -0
  195. data/proto/dynamic_discovery.proto +46 -0
  196. data/proto/google/protobuf/compiler/plugin.proto +183 -0
  197. data/proto/google/protobuf/descriptor.proto +911 -0
  198. data/proto/rpc.proto +71 -0
  199. data/resources/assess/policy.json +6 -23
  200. data/ruby-agent.gemspec +4 -2
  201. metadata +122 -33
  202. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
  203. data/lib/contrast/api/decorators/application_update.rb +0 -44
  204. data/lib/contrast/api/decorators/library.rb +0 -56
  205. data/lib/contrast/config/agent_configuration.rb +0 -63
  206. data/lib/contrast/config/heap_dump_configuration.rb +0 -59
  207. data/lib/contrast/config/inventory_configuration.rb +0 -33
  208. data/lib/contrast/config/logger_configuration.rb +0 -26
  209. data/lib/contrast/framework/platform_version.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b285299c51379c206ff8c7a64426ef5207594391d59c1ce284bae3a899d6d56f
4
- data.tar.gz: f7847b7523600ebad30ba380cd338d36f6ed2e8136e86d2fdb71f4c7953f530a
3
+ metadata.gz: bdb8bbd08206dafbb18eee844e1487701c419d27c1df8e4b58c4c226b1995d5c
4
+ data.tar.gz: 57bbfe5e3dca05729f95f2994246e74d59f7eecc2f7fe434e265fa5c60cc3734
5
5
  SHA512:
6
- metadata.gz: 3edc5557919437f5c7f76b741ed4133263bd975baebb6c81d8ac416713571c6ef871e9ab4d3b1ddf34aa0ff548242e71081443bc5c3cd04c2f4bae35b030e866
7
- data.tar.gz: 21c33b917d5f9c0f3b8070bde64b42c8d800dd73c952b0d45830b9d13eb6135ba086c9abf43b3003168f5c3902753cf1a480444bbfca506f00d7bf51b5039d03
6
+ metadata.gz: 5f6d80b48529b52719fb7aa4608e0cd42f8ec613e61138d7f7a977652054f9a24f05a78c0d79821749bc4cc1d86b0878009e93f65be47155e47c9e1ec084780d
7
+ data.tar.gz: ad3d855319ebf15f1af37cac9507c2774af76a6151d7e9a4559c9de23891bcc41f0642729087165b19d20ee4891e327895f9e0d9c9c5d4e402e3a4b901b44484
data/.gitignore CHANGED
@@ -56,8 +56,5 @@ contrast-agent-*.gem
56
56
  .ruby-gemset
57
57
  service_executables/*-*
58
58
 
59
- # Generated Protobuf files
60
- /lib/contrast/api/*.pb.rb
61
-
62
59
  # IDE stuff
63
60
  tags
data/.simplecov CHANGED
@@ -4,5 +4,6 @@
4
4
  SimpleCov.minimum_coverage(line: 94)
5
5
  SimpleCov.start do
6
6
  add_filter '/spec/'
7
+ add_filter '/lib/protobuf/'
7
8
  enable_coverage :branch
8
9
  end
data/Rakefile CHANGED
@@ -17,30 +17,3 @@ Dir['ext/cs__*'].each do |extension|
17
17
  ext.lib_dir = "lib/#{ name }"
18
18
  end
19
19
  end
20
-
21
- desc 'compile the protobuf files for the agent, translating them to .rb classes'
22
- task :contrast_pb_compile do
23
- # do some stuff before compile
24
-
25
- # Invoke the protobuf compile task with your sensible defaults
26
- ::Rake::Task['protobuf:compile'].invoke('lib', './agent-service-api/protobuf ./agent-service-api/protobuf/dtm.proto',
27
- 'lib/contrast/api',
28
- nil)
29
-
30
- ::Rake::Task['protobuf:compile'].reenable
31
-
32
- ::Rake::Task['protobuf:compile'].invoke('lib',
33
- './agent-service-api/protobuf ./agent-service-api/protobuf/settings.proto',
34
- 'lib/contrast/api',
35
- nil)
36
-
37
- ['dtm.pb.rb', 'settings.pb.rb'].each do |target_file|
38
- target_path = File.absolute_path(File.join(__dir__, "./lib/contrast/api/#{ target_file }"))
39
- unless File.exist?(target_path)
40
- puts "File not found #{ target_path }"
41
- exit 1
42
- end
43
- end
44
-
45
- puts 'Protobuf copied successfully'
46
- end
@@ -17,9 +17,10 @@
17
17
  * }
18
18
  */
19
19
 
20
- VALUE contrast_check_and_register_instance_patch(
21
- const char *module_name, const char *method_name,
22
- VALUE(c_fn)(const int, VALUE *, const VALUE));
20
+ VALUE contrast_check_and_register_instance_patch(const char *module_name,
21
+ const char *method_name,
22
+ VALUE(c_fn)(const int, VALUE *,
23
+ const VALUE));
23
24
 
24
25
  void contrast_assess_instance_eval_trigger_check(VALUE self, VALUE source,
25
26
  VALUE ret) {
@@ -65,6 +66,7 @@ void Init_cs__assess_basic_object(void) {
65
66
  * but if someone else patched BasicObject#instance_eval,
66
67
  * IDK if this is intentional... noting it. -ajm
67
68
  */
68
- contrast_check_and_register_instance_patch("BasicObject", "instance_eval",
69
- contrast_assess_basic_object_instance_eval);
69
+ contrast_check_and_register_instance_patch(
70
+ "BasicObject", "instance_eval",
71
+ contrast_assess_basic_object_instance_eval);
70
72
  }
@@ -26,14 +26,25 @@ contrast_patched_kernel_exec(const int argc, const VALUE *argv,
26
26
  return rb_funcall(self, rb_sym_assess_kernel_exec, argc, *argv);
27
27
  }
28
28
 
29
+ /* Check and see if the Kernel#exec is already prepended */
30
+ VALUE contrast_is_kernel_exec_prepended() {
31
+ return contrast_check_prepended(
32
+ rb_const_get(rb_cObject, rb_intern("Kernel")), rb_sym_kernel_exec,
33
+ Qfalse);
34
+ }
35
+
29
36
  void Init_cs__assess_kernel(void) {
37
+ VALUE rb_sym_kernel_exec = ID2SYM(rb_intern("exec"));
30
38
  kernel_propagator = rb_define_module_under(core_assess, "KernelPropagator");
31
39
  exec_apply_trigger = rb_intern("apply_trigger");
32
40
 
33
41
  rb_sym_assess_kernel_exec =
34
42
  contrast_register_patch("Kernel", "exec", contrast_patched_kernel_exec);
35
43
 
36
- /* should return the same value as above */
37
- rb_sym_assess_kernel_exec = contrast_register_singleton_patch(
38
- "Kernel", "exec", contrast_patched_kernel_exec);
44
+ /* check if prepended and register singleton patch if true */
45
+ if (contrast_is_kernel_exec_prepended() == Qtrue) {
46
+ /* should return the same value as above */
47
+ rb_sym_assess_kernel_exec = contrast_register_singleton_patch(
48
+ "Kernel", "exec", contrast_patched_kernel_exec);
49
+ }
39
50
  }
@@ -3,6 +3,8 @@
3
3
  static VALUE exec_apply_trigger;
4
4
  static VALUE kernel_propagator;
5
5
  static VALUE rb_sym_assess_kernel_exec;
6
+ static VALUE rb_sym_kernel_exec;
7
+ VALUE contrast_is_kernel_exec_prepended();
6
8
 
7
9
  VALUE
8
10
  contrast_patched_kernel_exec(const int argc, const VALUE *argv,
@@ -18,7 +18,7 @@
18
18
  * return rb_marshal_load_with_proc(port, proc);
19
19
  * }
20
20
  */
21
- static VALUE contrast_marshal_module_load(const int argc, const VALUE *argv) {
21
+ static VALUE contrast_marshal_module_prepend(const int argc, const VALUE *argv) {
22
22
  VALUE result;
23
23
  VALUE source_string;
24
24
 
@@ -67,6 +67,13 @@ void Init_cs__assess_marshal_module(void) {
67
67
  rb_sym_assess_marshal_load = rb_intern("cs__load_assess");
68
68
  rb_sym_protect_marshal_load = rb_intern("cs__load_protect");
69
69
 
70
- contrast_register_singleton_prepend_patch("Marshal", "load",
71
- &contrast_marshal_module_load);
70
+ /* check if prepended called form the after_load_patcher */
71
+ VALUE marshal = rb_const_get(rb_cObject, rb_intern("Marshal"));
72
+ VALUE marshal_load = ID2SYM(rb_intern("load"));
73
+ VALUE is_prepended = contrast_check_prepended(marshal, marshal_load, Qfalse);
74
+
75
+ if (is_prepended == Qtrue) {
76
+ contrast_register_singleton_prepend_patch("Marshal", "load",
77
+ &contrast_marshal_module_prepend);
78
+ }
72
79
  }
@@ -5,6 +5,7 @@ static VALUE marshal_propagator;
5
5
  static VALUE rb_sym_assess_marshal_load;
6
6
  static VALUE rb_sym_protect_marshal_load;
7
7
  static VALUE properties_hash;
8
+ static VALUE marshal, marshal_load, is_prepended;
8
9
 
9
10
  /*
10
11
  * Rails is a jerk. In Rails 5, they decided to do away with the alias chaining
@@ -14,7 +15,7 @@ static VALUE properties_hash;
14
15
  * special case this for now.
15
16
  * -HM (shamelessly commenting on DP's work)
16
17
  */
17
- static VALUE contrast_marshal_module_load(const int argc,
18
+ static VALUE contrast_marshal_module_prepend(const int argc,
18
19
  const VALUE *argv);
19
20
 
20
21
  void Init_cs__assess_marshal_module(void);
@@ -7,15 +7,15 @@
7
7
  #include <ruby.h>
8
8
 
9
9
  extern VALUE contrast_force_patch(const int argc, VALUE *argv) {
10
- return contrast_check_and_register_instance_patch(
10
+ return contrast_check_and_register_instance_patch(
11
11
  "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
12
12
  }
13
13
 
14
14
  /* check if method is prepended and register instance alias or prepend patch */
15
15
  VALUE contrast_check_and_register_instance_patch(const char *module_name,
16
- const char *method_name,
17
- VALUE(c_fn)(const int, VALUE *,
18
- const VALUE));
16
+ const char *method_name,
17
+ VALUE(c_fn)(const int, VALUE *,
18
+ const VALUE));
19
19
 
20
20
  void contrast_alias_method(const VALUE target, const char *to,
21
21
  const char *from);
@@ -58,8 +58,10 @@ void Init_cs__assess_regexp(void) {
58
58
  rb_global_variable(&rb_sym_string);
59
59
  rb_sym_back_ref = ID2SYM(rb_intern("back_ref"));
60
60
  rb_global_variable(&rb_sym_back_ref);
61
- rb_define_singleton_method(assess, "contrast_force_repatch_regexp", contrast_force_patch, 0);
61
+ rb_define_singleton_method(assess, "contrast_force_repatch_regexp",
62
+ contrast_force_patch, 0);
62
63
 
63
- rb_sym_assess_regexp_equal_squiggle = contrast_check_and_register_instance_patch(
64
- "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
64
+ rb_sym_assess_regexp_equal_squiggle =
65
+ contrast_check_and_register_instance_patch(
66
+ "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
65
67
  }
@@ -1,14 +1,25 @@
1
1
  /* Copyright (c) 2022 Contrast Security, Inc. See
2
2
  * https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
3
3
 
4
- #include "cs__assess_string_interpolation26.h"
4
+ #include "cs__assess_string_interpolation.h"
5
5
  #include "../cs__common/cs__common.h"
6
+ #include "../cs__scope/cs__scope.h"
6
7
  #include <ruby.h>
7
8
 
8
9
  static VALUE rb_str_concat_literals_hook(size_t num, VALUE *strary) {
9
10
  VALUE result = rb_str_concat_literals_original(num, strary);
10
11
  VALUE rb_params = rb_ary_new_from_values((int)num, strary);
11
- rb_funcall(string_propagator, track_interpolation, 2, rb_params, result);
12
+ VALUE in_contrast_scope = inst_methods_in_cntr_scope(contrast_patcher(), 0);
13
+
14
+ if (in_contrast_scope == Qfalse) {
15
+ /* enter scope */
16
+ inst_methods_enter_cntr_scope(contrast_patcher(), 0);
17
+ rb_funcall(string_propagator, track_interpolation, 2, rb_params,
18
+ result);
19
+ /* exit scope */
20
+ inst_methods_exit_cntr_scope(contrast_patcher(), 0);
21
+ }
22
+
12
23
  return result;
13
24
  }
14
25
 
@@ -20,7 +31,7 @@ static int install_hooks() {
20
31
  return 0;
21
32
  }
22
33
 
23
- void Init_cs__assess_string_interpolation26(void) {
34
+ void Init_cs__assess_string_interpolation(void) {
24
35
  string_propagator =
25
36
  rb_define_class_under(core_assess, "StringPropagator", rb_cObject);
26
37
  track_interpolation = rb_intern("track_interpolation");
@@ -10,4 +10,4 @@ static VALUE rb_str_concat_literals_hook(size_t num, VALUE *strary);
10
10
 
11
11
  static int install_hooks();
12
12
 
13
- void Init_cs__assess_string_interpolation26(void);
13
+ void Init_cs__assess_string_interpolation(void);
@@ -97,9 +97,10 @@ VALUE contrast_register_singleton_prepend_patch(const char *module_name,
97
97
  /* module name c_char "Module"; */
98
98
  /* method name c_char "method"; */
99
99
  /* c_func => pointer */
100
- VALUE contrast_check_and_register_instance_patch(
101
- const char *module_name, const char *method_name,
102
- VALUE(c_fn)(const int, VALUE *, const VALUE)) {
100
+ VALUE contrast_check_and_register_instance_patch(const char *module_name,
101
+ const char *method_name,
102
+ VALUE(c_fn)(const int, VALUE *,
103
+ const VALUE)) {
103
104
 
104
105
  VALUE object, method, is_prepended, patch_type;
105
106
  /* check if method is prepended */
@@ -291,5 +292,5 @@ void Init_cs__common(void) {
291
292
  contrast_check_prepended, 2);
292
293
  /* defined for object lookout */
293
294
  rb_define_singleton_method(assess, "cs__object_method_prepended?",
294
- contrast_lookout_prepended, 4);
295
+ contrast_lookout_prepended, 3);
295
296
  }
@@ -101,7 +101,18 @@ VALUE rescue_func(VALUE arg1) {
101
101
  return Qnil;
102
102
  }
103
103
 
104
+ /**
105
+ * In the event that the original_method call throws an exception we need to ensure that contrast_post_patch is called
106
+ * to report that error. However, if there is no error we will call post_patch with the original_return instead of
107
+ * Qnil.
108
+ *
109
+ **/
104
110
  VALUE contrast_patch_call_ensure(const VALUE *args) {
111
+ // we do not need to ensure that post patch is called if no error was thrown
112
+ if(!RTEST(rb_errinfo())) {
113
+ return Qnil;
114
+ }
115
+
105
116
  int argc;
106
117
  VALUE object, preshift, method_policy, method;
107
118
  VALUE *argv;
@@ -125,6 +136,7 @@ VALUE ensure_wrapper(const VALUE *args) {
125
136
  original_args = (VALUE)args[1];
126
137
  ensure_args = (VALUE)args[2];
127
138
 
139
+ //this ensure if being treated as a rescue due to issues surrounding Kernel#throw
128
140
  return rb_ensure(original_method, original_args, contrast_patch_call_ensure,
129
141
  (VALUE)ensure_args);
130
142
  }
@@ -220,21 +232,15 @@ VALUE contrast_run_patches(const VALUE *wrapped_args) {
220
232
  * If the original method threw an exception, contrast_patch_call_rescue
221
233
  * re-raises the original exception, which unwinds the stack back to the
222
234
  * call site. This means the rest of this function is not executed.
235
+ * post_patch is called in the ensure_wrapper on exception. rb_rescue
236
+ * raises the exception so the below will not be executed in that event.
223
237
  */
224
238
 
225
- /* Invoke Contrast post-call patching.
226
- * Post-call patching may transform the return value,
227
- * hence the assignment.
228
- */
229
- transformed_ret = contrast_call_post_patch(method_policy, preshift, object,
239
+ /* Invoke Contrast post-call patching. */
240
+ contrast_call_post_patch(method_policy, preshift, object,
230
241
  original_ret, argc, argv);
231
242
 
232
- /* Special case for tracking frozen sources */
233
- if (transformed_ret != Qnil) {
234
- return transformed_ret;
235
- } else {
236
- return original_ret;
237
- }
243
+ return original_ret;
238
244
  }
239
245
 
240
246
  VALUE contrast_ensure_function(const VALUE method_policy) {
@@ -56,18 +56,8 @@ module Contrast
56
56
 
57
57
  # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
58
58
  # in propagation events, so we'll future proof this
59
- def build_event_source_dtm
60
- # You can have a source w/o a name, but not w/o a type
61
- return unless source_type
62
-
63
- dtm = Contrast::Api::Dtm::TraceEventSource.new
64
- dtm.type = forced_source_type
65
- dtm.name = forced_source_name
66
- dtm
67
- end
68
-
69
- # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
70
- # in propagation events, so we'll future proof this
59
+ #
60
+ # @return [Contrast::Agent::Reporting::TraceEventSource, nil]
71
61
  def build_event_source
72
62
  # You can have a source w/o a name, but not w/o a type
73
63
  return unless source_type
@@ -89,6 +79,20 @@ module Contrast
89
79
  event_dtm.target = @policy_node.target_string
90
80
  @policy_node.targets[0]
91
81
  end
82
+
83
+ private
84
+
85
+ # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
86
+ # in propagation events, so we'll future proof this
87
+ def build_event_source_dtm
88
+ # You can have a source w/o a name, but not w/o a type
89
+ return unless source_type
90
+
91
+ dtm = Contrast::Api::Dtm::TraceEventSource.new
92
+ dtm.type = forced_source_type
93
+ dtm.name = forced_source_name
94
+ dtm
95
+ end
92
96
  end
93
97
  end
94
98
  end
@@ -14,6 +14,7 @@ module Contrast
14
14
  FROZEN_FINALIZED_IDS = Set.new
15
15
 
16
16
  def []= key, obj
17
+ return unless obj
17
18
  return unless ::Contrast::AGENT.enabled? && ::Contrast::ASSESS.enabled?
18
19
 
19
20
  # We can't finalize frozen things, so only act on those that went through .pre_freeze
@@ -5,6 +5,7 @@ require 'contrast/agent/patching/policy/policy_node'
5
5
  require 'contrast/api/decorators/trace_taint_range_tags'
6
6
  require 'contrast/utils/object_share'
7
7
  require 'contrast/agent/assess/policy/policy_node_utils'
8
+ require 'contrast/components/logger'
8
9
 
9
10
  module Contrast
10
11
  module Agent
@@ -13,6 +14,7 @@ module Contrast
13
14
  # This class functions to translate our policy.json into an actionable
14
15
  # Ruby object, allowing for dynamic patching over hardcoded patching.
15
16
  class PolicyNode < Contrast::Agent::Patching::Policy::PolicyNode
17
+ include Contrast::Components::Logger::InstanceMethods
16
18
  include PolicyNodeUtils
17
19
  JSON_TAGS = 'tags'
18
20
  JSON_DATAFLOW = 'dataflow'
@@ -107,12 +109,16 @@ module Contrast
107
109
  def validate
108
110
  super
109
111
  validate_tags
112
+ rescue ArgumentError => e
113
+ logger.debug('Validation of policy node failed with: ', e)
114
+ nil
110
115
  end
111
116
 
112
117
  # TeamServer is picky. The tags here match to ENUMs there. If there
113
118
  # isn't a matching ENUM in TS land, the database gets got. We really
114
119
  # don't want to get them, so we're going to prevent the node from being
115
120
  # made.
121
+ # @raise[ArgumentError] raises if any of the tags is invalid
116
122
  def validate_tags
117
123
  return unless tags
118
124
 
@@ -8,6 +8,7 @@ require 'contrast/components/logger'
8
8
  require 'contrast/utils/object_share'
9
9
  require 'contrast/utils/sha256_builder'
10
10
  require 'contrast/utils/assess/propagation_method_utils'
11
+ require 'contrast/utils/assess/event_limit_utils'
11
12
  require 'contrast/agent/assess/events/event_data'
12
13
  require 'contrast/utils/assess/object_store'
13
14
 
@@ -21,6 +22,7 @@ module Contrast
21
22
  module PropagationMethod
22
23
  extend Contrast::Components::Logger::InstanceMethods
23
24
  extend Contrast::Utils::Assess::PropagationMethodUtils
25
+ extend Contrast::Utils::Assess::EventLimitUtils
24
26
 
25
27
  @properties = Contrast::Utils::Assess::ObjectStore.new
26
28
 
@@ -38,6 +40,7 @@ module Contrast
38
40
  def apply_propagation method_policy, preshift, object, ret, args, block
39
41
  return unless (propagation_node = method_policy.propagation_node)
40
42
  return unless propagation_node.use_original_object? || preshift
43
+ return if event_limit?(method_policy)
41
44
 
42
45
  target = determine_target(propagation_node, ret, object, args)
43
46
  propagation_data = Contrast::Agent::Assess::Events::EventData.new(nil, nil, object, ret, args)
@@ -58,8 +61,6 @@ module Contrast
58
61
  # ret [Object] the Return of the invoked method
59
62
  # args [Array<Object>] the Arguments with which the method was invoked
60
63
  # @param block [Block] the Block passed to the original method
61
- # @return [Object, nil] the tracked Return or nil if no changes were made; will replace the return of the
62
- # original function if not nil
63
64
  def apply_propagator propagation_node, preshift, target, propagation_data, block
64
65
  return unless propagation_possible?(propagation_node, target)
65
66
 
@@ -133,16 +134,6 @@ module Contrast
133
134
  true
134
135
  end
135
136
 
136
- # Safely duplicate the target, or return nil
137
- #
138
- # @param target [Object] the thing to check for duplication
139
- # @return [Object, nil]
140
- def safe_dup target
141
- target.dup
142
- rescue StandardError => _e
143
- nil
144
- end
145
-
146
137
  # Iterate over each key and value in a hash to allow for propagation to each.
147
138
  #
148
139
  # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
@@ -196,28 +187,15 @@ module Contrast
196
187
  # @param _block [Block] the Block passed to the original method
197
188
  def handle_cs_properties_propagation propagation_node, preshift, target, propagation_data, _block
198
189
  return if propagation_node.action == NOOP_ACTION
199
- return unless can_propagate?(propagation_node, preshift, target)
190
+ return unless can_propagate?(propagation_node, preshift, target, propagation_data)
200
191
  return unless (propagation_class = find_propagation_class(propagation_node))
201
192
 
202
- restore_frozen_state = false
203
- if target.cs__frozen? && !Contrast::Agent::Assess::Tracker.trackable?(target)
204
- return unless can_handle_frozen?(propagation_node)
205
- return unless (dup = safe_dup(propagation_data.ret))
206
-
207
- restore_frozen_state = true
208
- ret = dup
209
- target = ret
210
- Contrast::Agent::Assess::Tracker.pre_freeze(ret)
211
- ret.cs__freeze
212
- # double check that we were able to finalize the replaced return
213
- return unless Contrast::Agent::Assess::Tracker.trackable?(target)
214
- end
215
-
216
193
  # If we are using the original object tracking, the preshift object is not created.
217
194
  # Instead identify the source as the original object itself and propagate with it.
218
195
  source = propagation_node.use_original_object? ? propagation_data.object : preshift
219
196
  handle_propagation(propagation_class, propagation_node, source, target)
220
- update_properties(restore_frozen_state, propagation_node, target, propagation_data, ret)
197
+ update_properties(propagation_node, target, propagation_data)
198
+ increment_event_count(propagation_node)
221
199
  end
222
200
 
223
201
  def handle_propagation propagation_class, propagation_node, source, target
@@ -228,7 +206,7 @@ module Contrast
228
206
  end
229
207
  end
230
208
 
231
- def update_properties restore_frozen_state, propagation_node, target, propagation_data, ret
209
+ def update_properties propagation_node, target, propagation_data
232
210
  if propagation_node.use_original_on_bang_method?
233
211
  properties = use_original_object_properties(propagation_data)
234
212
 
@@ -248,11 +226,10 @@ module Contrast
248
226
  event_data = Contrast::Agent::Assess::Events::EventData.new(propagation_node,
249
227
  target,
250
228
  propagation_data.object,
251
- ret,
229
+ propagation_data.ret,
252
230
  propagation_data.args)
253
231
  properties.build_event(event_data)
254
232
  logger.trace('Propagation detected', node_id: propagation_node.id, target_id: target.__id__)
255
- restore_frozen_state ? ret : nil
256
233
  end
257
234
 
258
235
  # Find the propagation class from the given node, if one exists.
@@ -269,17 +246,6 @@ module Contrast
269
246
  propagation_class
270
247
  end
271
248
 
272
- # We can handle frozen propagation iff we're allowed to, as determined by configuration, and the target of
273
- # the propagation is a return, as that's a replaceable value.
274
- #
275
- # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs a
276
- # propagation event.
277
- # @return [Boolean]
278
- def can_handle_frozen? propagation_node
279
- ::Contrast::ASSESS.track_frozen_sources? &&
280
- propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
281
- end
282
-
283
249
  # For certain bang methods we return the same object, no need to create expensive new properties.
284
250
  #
285
251
  # @param propagation_data [Contrast::Agent::Assess::Events::EventData] used to hold object, args
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'contrast/agent/assess/policy/policy_node'
5
5
  require 'contrast/api/decorators/trace_taint_range_tags'
6
+ require 'contrast/components/logger'
6
7
 
7
8
  module Contrast
8
9
  module Agent
@@ -14,6 +15,8 @@ module Contrast
14
15
  # untrusted data (indicate points in the application where user
15
16
  # controlled input is modified).
16
17
  class PropagationNode < PolicyNode
18
+ include Contrast::Components::Logger::InstanceMethods
19
+
17
20
  JSON_ACTION = 'action'
18
21
  JSON_UNTAGS = 'untags'
19
22
  JSON_PATCH_CLASS = 'patch_class'
@@ -41,6 +44,9 @@ module Contrast
41
44
  @patch_method = propagation_hash[JSON_PATCH_METHOD]
42
45
  @patch_method = @patch_method.to_sym if @patch_method
43
46
  validate
47
+ rescue ArgumentError => e
48
+ logger.error('Propagation Node Initialization failed with: ', e)
49
+ nil
44
50
  end
45
51
 
46
52
  def node_class
@@ -56,6 +62,7 @@ module Contrast
56
62
 
57
63
  # Standard validation + TS trace version two rules:
58
64
  # Must have source, target, and action
65
+ # @raise[ArgumentError] raises if any of the required propagation node field is not valid, or is missing
59
66
  def validate
60
67
  super
61
68
  raise(ArgumentError, "Propagator #{ id } did not have a proper action. Unable to create.") unless action
@@ -78,6 +85,7 @@ module Contrast
78
85
  validate_untags
79
86
  end
80
87
 
88
+ # @raise[ArgumentError] raises if any of the tags is invalid
81
89
  def validate_untags
82
90
  return unless untags
83
91
 
@@ -25,6 +25,8 @@ module Contrast
25
25
  Contrast::Agent::Assess::Tracker.tracked?(value)
26
26
  end
27
27
 
28
+ # @raise [NoMethodError] This is being raised if any of the implementing subclasses does not have
29
+ # that method implemented, but is being called on.
28
30
  def propagate _propagation_node, _preshift, _target
29
31
  raise(NoMethodError("Expected Base propagator subclass: #{ cs__class } to implement #propagate"))
30
32
  end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/extension/module'
5
+ require 'contrast/utils/assess/event_limit_utils'
5
6
 
6
7
  module Contrast
7
8
  module Agent
@@ -13,6 +14,8 @@ module Contrast
13
14
  # action knows the class and method it should call to preform this
14
15
  # action.
15
16
  module Custom
17
+ extend Contrast::Utils::Assess::EventLimitUtils
18
+
16
19
  class << self
17
20
  def propagate propagation_node, preshift, ret, block
18
21
  clazz = propagation_node.patch_class
@@ -26,6 +29,7 @@ module Contrast
26
29
  propagation_node.patch_class = clazz
27
30
  end
28
31
  clazz.send(method, propagation_node, preshift, ret, block)
32
+ increment_event_count(propagation_node)
29
33
  end
30
34
  end
31
35
  end
@@ -1,6 +1,8 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/utils/assess/event_limit_utils'
5
+
4
6
  module Contrast
5
7
  module Agent
6
8
  module Assess
@@ -11,6 +13,8 @@ module Contrast
11
13
  # results in new source nodes to track which columns in the database
12
14
  # have been tainted.
13
15
  class DatabaseWrite < Contrast::Agent::Assess::Policy::Propagator::Base
16
+ extend Contrast::Utils::Assess::EventLimitUtils
17
+
14
18
  class << self
15
19
  def propagate propagation_node, preshift, target
16
20
  return unless Contrast::ASSESS.require_dynamic_sources?
@@ -22,6 +26,7 @@ module Contrast
22
26
  known_tainted = ::Contrast::ASSESS.tainted_columns[class_name]
23
27
  propagation_node.sources.each do |source|
24
28
  handle_write(propagation_node, source, preshift, target, known_tainted, tainted_columns)
29
+ increment_event_count(propagation_node)
25
30
  end
26
31
  return if tainted_columns.empty?
27
32