contrast-agent 6.2.0 → 6.5.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 (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