contrast-agent 6.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/ext/cs__assess_regexp/cs__assess_regexp.c +15 -2
  3. data/ext/cs__assess_regexp/cs__assess_regexp.h +2 -0
  4. data/ext/cs__assess_string/cs__assess_string.c +8 -0
  5. data/ext/cs__assess_test/cs__assess_test.h +9 -0
  6. data/ext/cs__assess_test/cs__assess_tests.c +22 -0
  7. data/ext/cs__assess_test/extconf.rb +5 -0
  8. data/ext/cs__common/cs__common.c +101 -0
  9. data/ext/cs__common/cs__common.h +29 -5
  10. data/ext/cs__contrast_patch/cs__contrast_patch.c +1 -1
  11. data/ext/cs__tests/cs__tests.c +12 -0
  12. data/ext/cs__tests/cs__tests.h +3 -0
  13. data/ext/cs__tests/extconf.rb +5 -0
  14. data/lib/contrast/agent/assess/contrast_object.rb +16 -16
  15. data/lib/contrast/agent/assess/events/source_event.rb +17 -19
  16. data/lib/contrast/agent/assess/policy/policy_scanner.rb +2 -16
  17. data/lib/contrast/agent/assess/policy/propagator/split.rb +15 -19
  18. data/lib/contrast/agent/assess/policy/trigger_method.rb +3 -11
  19. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +7 -2
  20. data/lib/contrast/agent/assess/rule/response/base_rule.rb +11 -3
  21. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +60 -36
  22. data/lib/contrast/agent/at_exit_hook.rb +1 -1
  23. data/lib/contrast/agent/inventory/database_config.rb +10 -3
  24. data/lib/contrast/agent/middleware.rb +3 -3
  25. data/lib/contrast/agent/patching/policy/after_load_patch.rb +0 -2
  26. data/lib/contrast/agent/patching/policy/patch.rb +13 -12
  27. data/lib/contrast/agent/patching/policy/patcher.rb +1 -1
  28. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +6 -2
  29. data/lib/contrast/agent/reporting/masker/masker.rb +8 -11
  30. data/lib/contrast/agent/reporting/masker/masker_utils.rb +8 -4
  31. data/lib/contrast/agent/reporting/reporter.rb +11 -16
  32. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +49 -0
  33. data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +6 -2
  34. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +53 -0
  35. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +48 -0
  36. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +64 -0
  37. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +70 -0
  38. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +57 -0
  39. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +56 -0
  40. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +5 -1
  41. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +58 -0
  42. data/lib/contrast/agent/reporting/reporting_events/application_reporting_event.rb +27 -0
  43. data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +20 -10
  44. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +7 -12
  45. data/lib/contrast/agent/reporting/reporting_events/finding.rb +9 -3
  46. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +2 -4
  47. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +3 -3
  48. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +6 -2
  49. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +7 -3
  50. data/lib/contrast/agent/reporting/reporting_events/poll.rb +6 -2
  51. data/lib/contrast/agent/reporting/reporting_events/preflight.rb +10 -8
  52. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +6 -10
  53. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +12 -20
  54. data/lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb +27 -0
  55. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +17 -27
  56. data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +38 -0
  57. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +8 -0
  58. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +6 -0
  59. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +9 -4
  60. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +54 -67
  61. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +17 -7
  62. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +8 -5
  63. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +10 -10
  64. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +32 -17
  65. data/lib/contrast/agent/reporting/settings/protect.rb +1 -1
  66. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +1 -1
  67. data/lib/contrast/agent/request.rb +3 -3
  68. data/lib/contrast/agent/request_context_extend.rb +1 -1
  69. data/lib/contrast/agent/request_handler.rb +3 -3
  70. data/lib/contrast/agent/response.rb +2 -0
  71. data/lib/contrast/agent/service_heartbeat.rb +6 -48
  72. data/lib/contrast/agent/static_analysis.rb +1 -1
  73. data/lib/contrast/agent/telemetry/base.rb +151 -0
  74. data/lib/contrast/agent/telemetry/events/event.rb +35 -0
  75. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +44 -36
  76. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +29 -21
  77. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +91 -73
  78. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +62 -44
  79. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +50 -33
  80. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +20 -0
  81. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +32 -0
  82. data/lib/contrast/agent/telemetry/events/metric_event.rb +28 -0
  83. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +123 -0
  84. data/lib/contrast/agent/thread_watcher.rb +52 -68
  85. data/lib/contrast/agent/version.rb +1 -1
  86. data/lib/contrast/agent/worker_thread.rb +8 -0
  87. data/lib/contrast/agent.rb +1 -3
  88. data/lib/contrast/api/communication/messaging_queue.rb +28 -11
  89. data/lib/contrast/api/communication/response_processor.rb +7 -10
  90. data/lib/contrast/api/communication/speedracer.rb +1 -1
  91. data/lib/contrast/api/decorators/activity.rb +33 -0
  92. data/lib/contrast/api/decorators/http_request.rb +1 -1
  93. data/lib/contrast/components/config.rb +13 -22
  94. data/lib/contrast/components/contrast_service.rb +9 -0
  95. data/lib/contrast/components/settings.rb +10 -0
  96. data/lib/contrast/config/agent_configuration.rb +21 -11
  97. data/lib/contrast/config/api_configuration.rb +12 -8
  98. data/lib/contrast/config/api_proxy_configuration.rb +7 -3
  99. data/lib/contrast/config/application_configuration.rb +15 -11
  100. data/lib/contrast/config/assess_configuration.rb +13 -9
  101. data/lib/contrast/config/assess_rules_configuration.rb +5 -1
  102. data/lib/contrast/config/base_configuration.rb +3 -35
  103. data/lib/contrast/config/certification_configuration.rb +9 -5
  104. data/lib/contrast/config/exception_configuration.rb +10 -7
  105. data/lib/contrast/config/heap_dump_configuration.rb +13 -9
  106. data/lib/contrast/config/inventory_configuration.rb +9 -6
  107. data/lib/contrast/config/logger_configuration.rb +9 -6
  108. data/lib/contrast/config/protect_configuration.rb +9 -6
  109. data/lib/contrast/config/protect_rule_configuration.rb +12 -8
  110. data/lib/contrast/config/protect_rules_configuration.rb +18 -17
  111. data/lib/contrast/config/request_audit_configuration.rb +10 -7
  112. data/lib/contrast/config/root_configuration.rb +28 -11
  113. data/lib/contrast/config/ruby_configuration.rb +14 -11
  114. data/lib/contrast/config/sampling_configuration.rb +11 -8
  115. data/lib/contrast/config/server_configuration.rb +13 -9
  116. data/lib/contrast/config/service_configuration.rb +14 -11
  117. data/lib/contrast/configuration.rb +19 -10
  118. data/lib/contrast/framework/rails/patch/support.rb +13 -45
  119. data/lib/contrast/logger/aliased_logging.rb +87 -0
  120. data/lib/contrast/logger/application.rb +0 -4
  121. data/lib/contrast/tasks/config.rb +22 -13
  122. data/lib/contrast/utils/class_util.rb +2 -6
  123. data/lib/contrast/utils/invalid_configuration_util.rb +1 -1
  124. data/lib/contrast/utils/log_utils.rb +2 -0
  125. data/lib/contrast/utils/middleware_utils.rb +1 -1
  126. data/lib/contrast/utils/object_share.rb +1 -1
  127. data/lib/contrast/utils/telemetry.rb +20 -2
  128. data/lib/contrast/utils/telemetry_client.rb +22 -10
  129. data/lib/contrast/utils/telemetry_hash.rb +41 -0
  130. data/lib/contrast/utils/telemetry_identifier.rb +16 -1
  131. data/lib/contrast.rb +9 -0
  132. data/ruby-agent.gemspec +1 -1
  133. data/service_executables/VERSION +1 -1
  134. data/service_executables/linux/contrast-service +0 -0
  135. data/service_executables/mac/contrast-service +0 -0
  136. metadata +39 -16
  137. data/lib/contrast/agent/telemetry/events/metric_telemetry_event.rb +0 -26
  138. data/lib/contrast/agent/telemetry/events/startup_metrics_telemetry_event.rb +0 -121
  139. data/lib/contrast/agent/telemetry/events/telemetry_event.rb +0 -33
  140. data/lib/contrast/agent/telemetry/telemetry.rb +0 -150
  141. data/lib/contrast/utils/exclude_key.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47aa135a205e4a74d64b778ae543f892213ca70e47be654032147a8bfe16dc82
4
- data.tar.gz: 60f0de0e2675578bfb735c4f90303748bdc5e2053f2722dac4907bf84364d2f9
3
+ metadata.gz: 456cd00d5b3c07ec1a845a6dbcb26d6d5b2891b03a352f06d290d405ff695596
4
+ data.tar.gz: 06ce1572dc8403fdf57ab6cbaa9ea51d8b7e52c4090d64badda5001aabb608ac
5
5
  SHA512:
6
- metadata.gz: fdd2d1209de7366f810cb1d7355700a54cd7d7749d94736213cf96c47b8e5cedad449ec0dc2ab09753c0ecc3d064498d18d1d001edc5d998c6c615c4cd05b571
7
- data.tar.gz: 888016b33c67e7f2f77f320affcd1e945a7cc6e1c01c87d559d231cbed3309bbd4fff74833a5296f21680492955977d042594a39d807d4cb91eecd6adc4b4636
6
+ metadata.gz: 8ab067665857065d8325547faa13c3f41679e9a9a9de9a70245e310a2229b1d1097ee2198ae45ab9be5804835764c9004372ec03c8a7f2e2ce8ee3bafda332b1
7
+ data.tar.gz: cda25e738349d4ba06e6ada4fbb146341f883b92a444b9179dcb8e1e21d21d5c6fcd50503a599a9a55248e40078213f521dac5bdd610480650034455dce90f03
@@ -3,8 +3,20 @@
3
3
 
4
4
  #include "cs__assess_regexp.h"
5
5
  #include "../cs__common/cs__common.h"
6
+ #include "../cs__contrast_patch/cs__contrast_patch.h"
6
7
  #include <ruby.h>
7
8
 
9
+ extern VALUE contrast_force_patch(const int argc, VALUE *argv) {
10
+ return contrast_check_and_register_instance_patch(
11
+ "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
12
+ }
13
+
14
+ /* check if method is prepended and register instance alias or prepend patch */
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));
19
+
8
20
  void contrast_alias_method(const VALUE target, const char *to,
9
21
  const char *from);
10
22
 
@@ -46,7 +58,8 @@ void Init_cs__assess_regexp(void) {
46
58
  rb_global_variable(&rb_sym_string);
47
59
  rb_sym_back_ref = ID2SYM(rb_intern("back_ref"));
48
60
  rb_global_variable(&rb_sym_back_ref);
61
+ rb_define_singleton_method(assess, "contrast_force_repatch_regexp", contrast_force_patch, 0);
49
62
 
50
- rb_sym_assess_regexp_equal_squiggle = contrast_register_patch(
51
- "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
63
+ rb_sym_assess_regexp_equal_squiggle = contrast_check_and_register_instance_patch(
64
+ "Regexp", "=~", contrast_assess_regexp_equal_squiggle);
52
65
  }
@@ -20,4 +20,6 @@ static VALUE contrast_assess_regexp_equal_squiggle(const int argc,
20
20
  const VALUE *argv,
21
21
  const VALUE regexp);
22
22
 
23
+ extern VALUE contrast_force_patch(const int argc, VALUE *argv);
24
+
23
25
  void Init_cs__assess_regexp(void);
@@ -17,6 +17,13 @@
17
17
  * return rb_fstring(str);
18
18
  * }
19
19
  */
20
+
21
+ /*
22
+ * This patch won't do the Prepend. We would call to the String instance'
23
+ * uminus directly and skip other propagation from prepended modules.
24
+ * We could come back to this one and rethink it's prepend patching.
25
+ */
26
+
20
27
  static VALUE contrast_assess_string_freeze(const int argc, VALUE *argv,
21
28
  const VALUE obj) {
22
29
  if (!OBJ_FROZEN(obj)) {
@@ -55,6 +62,7 @@ void Init_cs__assess_string(void) {
55
62
  VALUE tracker = rb_define_class_under(assess, "Tracker", rb_cObject);
56
63
  properties_hash = rb_const_get(tracker, rb_intern("PROPERTIES_HASH"));
57
64
 
65
+ /* We only do alias for this one */
58
66
  rb_sym_assess_string_uminus =
59
67
  contrast_register_patch("String", "-@", &contrast_assess_string_uminus);
60
68
  rb_sym_assess_string_freeze = contrast_register_patch(
@@ -0,0 +1,9 @@
1
+ #include <ruby.h>
2
+
3
+ static VALUE dummy_regexp;
4
+ static VALUE test_regexp;
5
+
6
+ VALUE rb_equal_squiggle(const int argc, const VALUE *argv)
7
+ void rb_force_prepend(void);
8
+
9
+ void Init_cs__assess_test(void)
@@ -0,0 +1,22 @@
1
+ #include "../cs__common/cs__common.h";
2
+ #include "ruby.h"
3
+ #include <ruby/re.h>
4
+
5
+ static VALUE dummy_regexp;
6
+ static VALUE test_regexp;
7
+
8
+ VALUE rb_equal_squiggle(const int argc, const VALUE *argv) {
9
+ return rb_call_super(argc, argv);
10
+ }
11
+
12
+ void rb_force_prepend(void) {
13
+ rb_prepend_module(rb_cRegexp, dummy_regexp);
14
+ }
15
+
16
+ void Init_cs__assess_test(void) {
17
+ test_regexp = rb_define_module("ForcePrepend");
18
+ rb_define_singleton_method(test_regexp, "cs__force_prepend",
19
+ rb_force_prepend, 0);
20
+ dummy_regexp = rb_define_module("DummyMod");
21
+ rb_define_method(dummy_regexp, "=~", rb_equal_squiggle, -1);
22
+ }
@@ -0,0 +1,5 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ $TO_MAKE = File.basename(__dir__)
5
+ require_relative '../extconf_common'
@@ -59,12 +59,14 @@ VALUE contrast_patcher() {
59
59
  return patcher;
60
60
  }
61
61
 
62
+ /* register instance alias patch */
62
63
  VALUE contrast_register_patch(const char *module_name, const char *method_name,
63
64
  VALUE(c_fn)(const int, VALUE *, const VALUE)) {
64
65
  return _contrast_register_patch(module_name, method_name, c_fn,
65
66
  IMPL_ALIAS_INSTANCE);
66
67
  }
67
68
 
69
+ /* register singleton alias patch */
68
70
  VALUE contrast_register_singleton_patch(const char *module_name,
69
71
  const char *method_name,
70
72
  VALUE(c_fn)(const int, VALUE *,
@@ -73,6 +75,7 @@ VALUE contrast_register_singleton_patch(const char *module_name,
73
75
  IMPL_ALIAS_SINGLETON);
74
76
  }
75
77
 
78
+ /* register instance prepend patch */
76
79
  VALUE contrast_register_prepend_patch(const char *module_name,
77
80
  const char *method_name,
78
81
  VALUE(c_fn)(const int, VALUE *,
@@ -81,6 +84,7 @@ VALUE contrast_register_prepend_patch(const char *module_name,
81
84
  IMPL_PREPEND_INSTANCE);
82
85
  }
83
86
 
87
+ /* register singleton prepend patch */
84
88
  VALUE contrast_register_singleton_prepend_patch(const char *module_name,
85
89
  const char *method_name,
86
90
  VALUE(c_fn)(const int, VALUE *,
@@ -89,6 +93,31 @@ VALUE contrast_register_singleton_prepend_patch(const char *module_name,
89
93
  IMPL_PREPEND_SINGLETON);
90
94
  }
91
95
 
96
+ /* check if method is prepended and register instance alias or prepend patch */
97
+ /* module name c_char "Module"; */
98
+ /* method name c_char "method"; */
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)) {
103
+
104
+ VALUE object, method, is_prepended, patch_type;
105
+ /* check if method is prepended */
106
+ object = rb_const_get(rb_cObject, rb_intern(module_name));
107
+ method = ID2SYM(rb_intern(method_name));
108
+ is_prepended = contrast_check_prepended(object, method, Qtrue);
109
+
110
+ if (is_prepended == Qtrue) {
111
+ /* prepend patch */
112
+ return _contrast_register_patch(module_name, method_name, c_fn,
113
+ IMPL_PREPEND_INSTANCE);
114
+ } else {
115
+ /* alias patch */
116
+ return _contrast_register_patch(module_name, method_name, c_fn,
117
+ IMPL_ALIAS_INSTANCE);
118
+ }
119
+ }
120
+
92
121
  static VALUE
93
122
  _contrast_register_patch(const char *module_name, const char *method_name,
94
123
  VALUE(c_fn)(const int, VALUE *, const VALUE),
@@ -133,6 +162,7 @@ _contrast_register_patch(const char *module_name, const char *method_name,
133
162
  break;
134
163
  case IMPL_PREPEND_INSTANCE:
135
164
  impl = ID2SYM(rb_sym_prepend_instance);
165
+ break;
136
166
  case IMPL_PREPEND_SINGLETON:
137
167
  impl = ID2SYM(rb_sym_prepend_singleton);
138
168
  break;
@@ -151,6 +181,71 @@ int rb_ver_below_three() {
151
181
  return ruby_version < 3;
152
182
  }
153
183
 
184
+ /* used for direct check on object: String.cs__prepended? *args */
185
+ extern VALUE contrast_check_prepended(VALUE self, VALUE method_name,
186
+ VALUE is_instance) {
187
+ return _contrast_check_prepended(self, method_name, is_instance);
188
+ }
189
+
190
+ /* used for passing object to look if not called on itself.
191
+ Contrast::Agent::Assess.cs__object_method_prepended? object, :method_name,
192
+ true/false */
193
+ extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name,
194
+ VALUE method_name, VALUE is_instance) {
195
+ /* object_name must be the object, the self value is needed to prevent
196
+ lookout for self, since is always passed first we skip it */
197
+ VALUE result =
198
+ _contrast_check_prepended(object_name, method_name, is_instance);
199
+ return result;
200
+ }
201
+
202
+ static VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
203
+ VALUE is_instance) {
204
+ VALUE entry, ancestors, object_idx, entry_methods;
205
+ VALUE result = Qfalse;
206
+ int i;
207
+ int y;
208
+
209
+ /* get self ancestors */
210
+ ancestors = rb_mod_ancestors(object);
211
+ /* get the size of the array */
212
+ int length = RARRAY_LEN(ancestors);
213
+ /* Locate self in ancestors: */
214
+ for (i = 0; i < length; ++i) {
215
+ entry = rb_ary_entry(ancestors, i);
216
+ if (entry == object) {
217
+ object_idx = i;
218
+ break;
219
+ }
220
+ }
221
+
222
+ /* find all the prepended modules */
223
+ /* we have the object place in ancestors: */
224
+ /* [suspect, suspect, object, ...] */
225
+ for (i = 0; i < object_idx; ++i) {
226
+ entry = rb_ary_entry(ancestors, i);
227
+ if (is_instance == Qtrue) {
228
+ entry_methods = rb_class_instance_methods(1, entry, entry);
229
+ } else {
230
+ entry_methods = rb_obj_singleton_methods(1, entry, entry);
231
+ }
232
+
233
+ /* Loop through the instance/singleton methods of the prepended modules
234
+ */
235
+ int entry_methods_length = RARRAY_LEN(entry_methods);
236
+ for (y = 0; y <= entry_methods_length; ++y) {
237
+ if (rb_ary_entry(entry_methods, y) == method_name) {
238
+ result = Qtrue;
239
+ break;
240
+ }
241
+ }
242
+ if (result == Qtrue) {
243
+ break;
244
+ }
245
+ }
246
+ return result;
247
+ }
248
+
154
249
  void Init_cs__common(void) {
155
250
  cs__send_method = rb_intern("send");
156
251
  cs__alias_method_sym = ID2SYM(rb_intern("alias_method"));
@@ -191,4 +286,10 @@ void Init_cs__common(void) {
191
286
 
192
287
  core_extensions = rb_define_module_under(contrast, "Extension");
193
288
  core_assess = rb_define_module_under(core_extensions, "Assess");
289
+ /* defined for direct object check */
290
+ rb_define_singleton_method(rb_cObject, "cs__prepended?",
291
+ contrast_check_prepended, 2);
292
+ /* defined for object lookout */
293
+ rb_define_singleton_method(assess, "cs__object_method_prepended?",
294
+ contrast_lookout_prepended, 4);
194
295
  }
@@ -57,15 +57,39 @@ VALUE contrast_register_singleton_patch(const char *module_name,
57
57
  VALUE(c_fn)(const int, VALUE *,
58
58
  const VALUE));
59
59
 
60
- VALUE contrast_register_singleton_prepend_patch(
61
- const char *module_name, const char *method_name,
62
- VALUE(c_fn)(const int, VALUE *, const VALUE));
60
+ VALUE contrast_register_prepend_patch(const char *module_name,
61
+ const char *method_name,
62
+ VALUE(c_fn)(const int, VALUE *,
63
+ const VALUE));
63
64
 
64
- static VALUE
65
- _contrast_register_patch(const char *module_name, const char *method_name,
65
+
66
+ VALUE contrast_register_singleton_prepend_patch(const char *module_name,
67
+ const char *method_name,
68
+ VALUE(c_fn)(const int, VALUE *,
69
+ const VALUE));
70
+
71
+ VALUE contrast_register_prepend_patch(const char *module_name,
72
+ const char *method_name,
73
+ VALUE(c_fn)(const int, VALUE *,
74
+ const VALUE));
75
+
76
+ static VALUE _contrast_register_patch(const char *module_name, const char *method_name,
66
77
  VALUE(c_fn)(const int, VALUE *, const VALUE),
67
78
  patch_impl patch_impl);
68
79
 
80
+ static VALUE _contrast_check_prepended(VALUE self, VALUE method_name, VALUE is_instance);
81
+
82
+ extern VALUE contrast_check_prepended(VALUE self, VALUE method_name, VALUE is_instance);
83
+
84
+ extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name, VALUE method_name,
85
+ VALUE is_instance);
86
+
87
+ /* check if method is prepended and register instance alias or prepend patch */
88
+ VALUE contrast_check_and_register_instance_patch(const char *module_name,
89
+ const char *method_name,
90
+ VALUE(c_fn)(const int, VALUE *,
91
+ const VALUE));
92
+
69
93
  VALUE contrast_patcher();
70
94
 
71
95
  void Init_cs__common(void);
@@ -488,7 +488,7 @@ VALUE contrast_patch_prepend(const VALUE self, const VALUE originalModule,
488
488
  rb_funcall(originalModule, rb_intern("included_in"), 0);
489
489
  if (RB_TYPE_P(rb_incl_in_mod_ary, T_ARRAY)) {
490
490
  int i = 0;
491
- int size = rb_funcall(rb_incl_in_mod_ary, rb_intern("length"), 0);
491
+ int size = RARRAY_LEN(rb_incl_in_mod_ary);
492
492
  for (i = 0; i < size; ++i) {
493
493
  module_at = rb_ary_entry(rb_incl_in_mod_ary, i);
494
494
  if (RB_TYPE_P(module_at, T_MODULE)) {
@@ -0,0 +1,12 @@
1
+ /* Copyright (c) 2022 Contrast Security, Inc. See
2
+ * https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
3
+
4
+ #include "cs__tests.h"
5
+ #include "../cs__common/cs__common.h"
6
+ #include <ruby.h>
7
+
8
+ /* Define any tests functions here, you could call a patch function and define
9
+ * it in Ruby */
10
+
11
+ void Init_cs__tests(void) {
12
+ }
@@ -0,0 +1,3 @@
1
+ #include <ruby.h>
2
+
3
+ void Init_cs__tests(void);
@@ -0,0 +1,5 @@
1
+ # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
+ # frozen_string_literal: true
3
+
4
+ $TO_MAKE = File.basename(__dir__)
5
+ require_relative '../extconf_common'
@@ -8,24 +8,22 @@ require 'contrast/agent/assess/tracker'
8
8
  module Contrast
9
9
  module Agent
10
10
  module Assess
11
- # This class is a convenient holder of our version of an Object. It
12
- # creates a String version of the Object from the original provided
13
- # and keeps reference to the original's Tags, letting us determine if it
14
- # was tracked when we try to report to TeamServer.
11
+ # This class is a convenient holder of our version of an Object. It creates a String version of the Object from
12
+ # the original provided and keeps reference to the original's Tags, letting us determine if it was tracked when
13
+ # we try to report to TeamServer.
15
14
  #
16
- # @attr_reader object [String, nil] the Contrast string representing the
17
- # object.
18
- # @attr_reader object_type [String] the name of the object's module.
19
- # @attr_reader tags [Hash{String => Contrast::Agent::Assess::Tag}, nil]
20
- # the tags on the object before it was captured.
21
- #
22
- # TODO: RUBY-1083 determine if this is expensive and/or worth not storing
23
- # these values directly on ContrastEvent and passing them around. Args
24
- # probably make the argument for wrapping them b/c otherwise we'll have
25
- # to keep two arrays in synch or make an array of arrays, at which
26
- # point, we may as well make this.
15
+ # TODO: RUBY-1083 determine if this is expensive and/or worth not storing these values directly on ContrastEvent
16
+ # and passing them around. Args probably make the argument for wrapping them b/c otherwise we'll have to keep
17
+ # two arrays in synch or make an array of arrays, at which point, we may as well make this.
27
18
  class ContrastObject
28
- attr_reader :object, :object_type, :tags
19
+ # @return [String] the Contrast String representation of the Object.
20
+ attr_reader :object
21
+ # @return [Integer] the __id__ of the original Object.
22
+ attr_reader :tracked_object_id
23
+ # @return [String] the name of the Class/Module of the Object.
24
+ attr_reader :object_type
25
+ # @return [Hash<Contrast::Agent::Assess::Tag>] the tags on the original Object.
26
+ attr_reader :tags
29
27
 
30
28
  # Capture the details about the object which we need to render it in
31
29
  # TeamServer.
@@ -34,10 +32,12 @@ module Contrast
34
32
  def initialize object
35
33
  if object
36
34
  @object = Contrast::Utils::ClassUtil.to_contrast_string(object)
35
+ @tracked_object_id = object.__id__
37
36
  @object_type = object.cs__class.cs__name
38
37
  @tags = Contrast::Agent::Assess::Tracker.properties(object)&.get_tags
39
38
  else
40
39
  @object = Contrast::Utils::ObjectShare::NIL_STRING
40
+ @tracked_object_id = nil.__id__
41
41
  @object_type = nil.cs__class.cs__name
42
42
  end
43
43
  end
@@ -9,22 +9,22 @@ module Contrast
9
9
  module Agent
10
10
  module Assess
11
11
  module Events
12
- # This class holds the data about an event in the application
13
- # We'll use it to build an event that TeamServer can consume if
14
- # the object to which this event belongs ends in a trigger.
15
- #
16
- # @attr_reader request [Contrast::Agent::Request] our wrapper around the Rack::Request at the time this source
17
- # was created
18
- # @attr_reader source_name [String] the name of the source if it comes from a map-like entity
19
- # @attr_reader source_type [String] the TeamServer understood type of source; i.e. parameter
12
+ # This class holds the data about an event in the application. We'll use it to build an event that TeamServer
13
+ # can consume if the object to which this event belongs ends in a trigger.
20
14
  class SourceEvent < Contrast::Agent::Assess::ContrastEvent
21
- attr_reader :request, :source_name, :source_type
15
+ # @return [Contrast::Agent::Request] our wrapper around the Rack::Request at the time this source
16
+ # was created
17
+ attr_reader :request
18
+ # @return [String] the name of the source if it comes from a map-like entity
19
+ attr_reader :source_name
20
+ # @return [String] the TeamServer understood type of source; i.e. parameter
21
+ attr_reader :source_type
22
22
 
23
23
  # @param event_data [Contrast::Agent::Assess::Events::EventData]
24
- # @param source_type [String] the type of this source, from the
25
- # source_node, or a KEY_TYPE if invoked for a map,
26
- # @param source_name [String, nil] the name of this source, i.e.
27
- # the key used to accessed if from a map or nil if a type like,
24
+ # @param source_type [String] the type of this source, from the source_node, or a KEY_TYPE if invoked for a
25
+ # Hash
26
+ # @param source_name [String, nil] the name of this source, i.e. the key used to accessed if from a Hash or
27
+ # nil if a type like
28
28
  def initialize event_data, source_type = nil, source_name = nil
29
29
  super(event_data)
30
30
  @source_type = source_type
@@ -54,8 +54,7 @@ module Contrast
54
54
  @_forced_source_name ||= Contrast::Utils::StringUtils.force_utf8(source_name)
55
55
  end
56
56
 
57
- # Probably only for source events, but we'll go
58
- # with source_type instead. java & .net support source_type
57
+ # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
59
58
  # in propagation events, so we'll future proof this
60
59
  def build_event_source_dtm
61
60
  # You can have a source w/o a name, but not w/o a type
@@ -67,8 +66,7 @@ module Contrast
67
66
  dtm
68
67
  end
69
68
 
70
- # Probably only for source events, but we'll go
71
- # with source_type instead. java & .net support source_type
69
+ # Probably only for source events, but we'll go with source_type instead. java & .net support source_type
72
70
  # in propagation events, so we'll future proof this
73
71
  def build_event_source
74
72
  # You can have a source w/o a name, but not w/o a type
@@ -80,8 +78,8 @@ module Contrast
80
78
  trace_event_source
81
79
  end
82
80
 
83
- # We have to do a little work to figure out what our TS appropriate
84
- # target is. To break this down, the logic is as follows:
81
+ # We have to do a little work to figure out what our TS appropriate target is. To break this down, the logic
82
+ # is as follows:
85
83
  # 1) I'll set the event's source and target to TS values.
86
84
  # 2) Return the first source/target as the taint target.
87
85
  def determine_taint_target event_dtm
@@ -32,22 +32,8 @@ module Contrast
32
32
  mod = trace_point.self
33
33
  return if mod.cs__frozen? || mod.singleton_class?
34
34
 
35
- different_ruby_version trace_point, provider_values, mod
36
- end
37
-
38
- def different_ruby_version trace_point, provider_values, mod
39
- # TODO: RUBY-1014 - remove non-AST approach
40
- if RUBY_VERSION >= '2.6.0'
41
- # TODO: RUBY-714 EOL 2.5. That check will be removed and the code will be brought back in here.
42
- ast = RubyVM::AbstractSyntaxTree.parse_file(trace_point.path)
43
- provider_values.each do |provider|
44
- provider.parse(trace_point, ast)
45
- end
46
- else
47
- provider_values.each do |provider|
48
- provider.analyze(mod)
49
- end
50
- end
35
+ ast = RubyVM::AbstractSyntaxTree.parse_file(trace_point.path)
36
+ provider_values.each { |provider| provider.parse(trace_point, ast) }
51
37
  end
52
38
 
53
39
  def policy
@@ -178,27 +178,23 @@ module Contrast
178
178
  end
179
179
  end
180
180
 
181
- if RUBY_VERSION >= '2.6.0'
182
- # Special class to handle String#split in 2.6 which, when given a block,
183
- # propagates each split piece directly
184
- class String
185
- alias_method :cs__patched_string_split_special, :split
186
-
187
- # Override of the the standard split method to handle the 2.6 direct yield case.
188
- #
189
- # Note: because this patch is applied before our standard propagation, this
190
- # call is wrapped in it. As such, any call here happens in scope, so there is
191
- # no need to manage it on our own.
192
- def split *args, &block
193
- if block
194
- Contrast::Agent::Assess::Policy::Propagator::Split.wrap_split(self, args) do
195
- cs__patched_string_split_special(*args, &block)
196
- end
197
- else
181
+ # Special class to handle String#split in which, when given a block, propagates each split piece directly.
182
+ class String
183
+ alias_method :cs__patched_string_split_special, :split
184
+
185
+ # Override of the the standard split method to handle the direct yield case.
186
+ #
187
+ # Note: because this patch is applied before our standard propagation, this call is wrapped in it. As such, any call
188
+ # here happens in scope, so there is no need to manage it on our own.
189
+ def split *args, &block
190
+ if block
191
+ Contrast::Agent::Assess::Policy::Propagator::Split.wrap_split(self, args) do
198
192
  cs__patched_string_split_special(*args, &block)
199
193
  end
194
+ else
195
+ cs__patched_string_split_special(*args, &block)
200
196
  end
201
197
  end
202
-
203
- Contrast::Agent::Assess::Policy::Propagator::Split.instrument_string_split
204
198
  end
199
+
200
+ Contrast::Agent::Assess::Policy::Propagator::Split.instrument_string_split
@@ -12,6 +12,7 @@ require 'contrast/agent/reporting/reporting_events/preflight'
12
12
  require 'contrast/agent/reporting/reporting_events/preflight_message'
13
13
  require 'contrast/agent/reporting/reporting_events/route_discovery'
14
14
  require 'contrast/agent/reporting/reporting_utilities/reporting_storage'
15
+ require 'contrast/agent/reporting/reporting_utilities/build_preflight'
15
16
 
16
17
  module Contrast
17
18
  module Agent
@@ -152,18 +153,9 @@ module Contrast
152
153
  ruby_finding.attach_data trigger_node, source, object, ret, request, *args
153
154
  hash_code = Contrast::Utils::HashDigest.generate_event_hash(ruby_finding, source, request)
154
155
  ruby_finding.hash_code = hash_code
155
- # save the current finding
156
- Contrast::Agent::Reporting::ReportingStorage[hash_code] = ruby_finding
157
156
 
158
- new_preflight = Contrast::Agent::Reporting::Preflight.new
159
- new_preflight_message = Contrast::Agent::Reporting::PreflightMessage.new
160
- if request.route
161
- new_preflight_message.routes << Contrast::Agent::Reporting::RouteDiscovery.convert(request.route)
162
- end
163
- new_preflight_message.hash_code = hash_code
164
- new_preflight_message.data = "#{ trigger_node.rule_id },#{ hash_code }"
165
- new_preflight.messages << new_preflight_message
166
- Contrast::Agent.reporter&.send_event_immediately(new_preflight)
157
+ new_preflight = Contrast::Agent::Reporting::BuildPreflight.build(ruby_finding, request)
158
+ Contrast::Agent.reporter&.send_event(new_preflight)
167
159
  end
168
160
 
169
161
  private
@@ -113,12 +113,17 @@ module Contrast
113
113
  class_name = clazz.cs__name
114
114
 
115
115
  finding = assign_finding class_name, constant_string
116
- Contrast::Agent::Assess::Policy::TriggerMethod.report_finding(finding)
116
+ activity = Contrast::Api::Dtm::Activity.new
117
+ activity.findings << finding
118
+ Contrast::Agent.messaging_queue.send_event_eventually(activity, force: true)
117
119
  rescue StandardError => e
118
120
  logger.error('Unable to build a finding for Hardcoded Rule', e)
119
121
  nil
120
122
  end
121
123
 
124
+ # @param class_name [String] the name of the class in which the hardcoded value is present
125
+ # @param constant_string [String] the name of the constant
126
+ # @return [Contrast::Api::Dtm::Finding]
122
127
  def assign_finding class_name, constant_string
123
128
  finding = Contrast::Api::Dtm::Finding.new
124
129
  finding.rule_id = Contrast::Utils::StringUtils.protobuf_safe_string(rule_id)
@@ -158,7 +163,7 @@ module Contrast
158
163
 
159
164
  def save_and_report_finding ruby_finding, new_preflight
160
165
  Contrast::Agent::Reporting::ReportingStorage[hash] = ruby_finding
161
- Contrast::Agent.reporter&.send_event_immediately(new_preflight)
166
+ Contrast::Agent.reporter&.send_event(new_preflight)
162
167
  end
163
168
  end
164
169
  end
@@ -4,6 +4,7 @@
4
4
  require 'rack'
5
5
  require 'json'
6
6
  require 'contrast/agent/reporting/reporting_utilities/dtm_message'
7
+ require 'contrast/agent/reporting/reporting_utilities/build_preflight'
7
8
  require 'contrast/utils/hash_digest'
8
9
  require 'contrast/utils/preflight_util'
9
10
  require 'contrast/utils/string_utils'
@@ -32,8 +33,13 @@ module Contrast
32
33
 
33
34
  if Contrast::Agent::Reporter.enabled?
34
35
  report = Contrast::Agent::Reporting::DtmMessage.dtm_to_event(finding)
35
- # TODO: RUBY-99999 preflight
36
- Contrast::Agent.reporter.send_event(report)
36
+ if report.is_a?(Contrast::Agent::Reporting::Finding)
37
+ request = Contrast::Agent::REQUEST_TRACKER.current&.request
38
+ preflight = Contrast::Agent::Reporting::BuildPreflight.build(report, request)
39
+ Contrast::Agent.reporter&.send_event(preflight)
40
+ else
41
+ Contrast::Agent.reporter&.send_event(report)
42
+ end
37
43
  else
38
44
  Contrast::Agent::REQUEST_TRACKER.current.activity.findings << finding
39
45
  end
@@ -58,7 +64,7 @@ module Contrast
58
64
 
59
65
  # Determine if the Response violates the Rule or not. If it does, return the evidence that proves it so.
60
66
  #
61
- # @param response [Contrast::Agent::Response] the response of the application
67
+ # @param _response [Contrast::Agent::Response] the response of the application
62
68
  # @return [Hash, nil] the evidence required to prove the violation of the rule
63
69
  def violated? _response; end
64
70
 
@@ -92,6 +98,8 @@ module Contrast
92
98
  evidence.each_pair do |key, value|
93
99
  finding.properties[key] = if value.cs__is_a?(Hash)
94
100
  Contrast::Utils::StringUtils.protobuf_format(value.to_json)
101
+ elsif value.cs__is_a?(Array)
102
+ value.map { Contrast::Utils::StringUtils.protobuf_format(_1) }.to_s
95
103
  else
96
104
  Contrast::Utils::StringUtils.protobuf_format(value)
97
105
  end