contrast-agent 4.11.0 → 4.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +1 -0
  3. data/ext/cs__assess_module/cs__assess_module.c +48 -0
  4. data/ext/cs__assess_module/cs__assess_module.h +7 -0
  5. data/ext/cs__common/cs__common.c +24 -7
  6. data/ext/cs__common/cs__common.h +12 -2
  7. data/ext/cs__contrast_patch/cs__contrast_patch.c +48 -11
  8. data/ext/cs__contrast_patch/cs__contrast_patch.h +5 -2
  9. data/ext/cs__os_information/cs__os_information.c +31 -0
  10. data/ext/cs__os_information/cs__os_information.h +7 -0
  11. data/ext/{cs__protect_kernel → cs__os_information}/extconf.rb +0 -0
  12. data/lib/contrast/agent/assess/contrast_event.rb +1 -1
  13. data/lib/contrast/agent/assess/contrast_object.rb +1 -1
  14. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +2 -0
  15. data/lib/contrast/agent/assess/policy/policy_node.rb +6 -6
  16. data/lib/contrast/agent/assess/policy/policy_scanner.rb +5 -0
  17. data/lib/contrast/agent/assess/policy/preshift.rb +19 -6
  18. data/lib/contrast/agent/assess/policy/propagation_method.rb +2 -116
  19. data/lib/contrast/agent/assess/policy/propagation_node.rb +4 -4
  20. data/lib/contrast/agent/assess/policy/propagator/center.rb +1 -1
  21. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +2 -0
  22. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +2 -154
  23. data/lib/contrast/agent/assess/policy/source_method.rb +2 -71
  24. data/lib/contrast/agent/assess/policy/trigger_method.rb +45 -110
  25. data/lib/contrast/agent/assess/policy/trigger_node.rb +62 -21
  26. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +1 -1
  27. data/lib/contrast/agent/assess/property/tagged.rb +66 -189
  28. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +40 -6
  29. data/lib/contrast/agent/deadzone/policy/policy.rb +6 -0
  30. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +1 -0
  31. data/lib/contrast/agent/metric_telemetry_event.rb +26 -0
  32. data/lib/contrast/agent/middleware.rb +14 -62
  33. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +0 -1
  34. data/lib/contrast/agent/patching/policy/method_policy.rb +3 -44
  35. data/lib/contrast/agent/patching/policy/method_policy_extend.rb +111 -0
  36. data/lib/contrast/agent/patching/policy/patch.rb +37 -238
  37. data/lib/contrast/agent/patching/policy/patcher.rb +15 -50
  38. data/lib/contrast/agent/reporting/report.rb +21 -0
  39. data/lib/contrast/agent/reporting/reporter.rb +142 -0
  40. data/lib/contrast/agent/reporting/reporting_events/finding.rb +90 -0
  41. data/lib/contrast/agent/reporting/reporting_events/preflight.rb +25 -0
  42. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +56 -0
  43. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +37 -0
  44. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +127 -0
  45. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +168 -0
  46. data/lib/contrast/agent/reporting/reporting_utilities/reporting_storage.rb +66 -0
  47. data/lib/contrast/agent/request.rb +2 -81
  48. data/lib/contrast/agent/request_context.rb +18 -126
  49. data/lib/contrast/agent/request_context_extend.rb +138 -0
  50. data/lib/contrast/agent/request_handler.rb +7 -3
  51. data/lib/contrast/agent/response.rb +2 -73
  52. data/lib/contrast/agent/rule_set.rb +2 -4
  53. data/lib/contrast/agent/startup_metrics_telemetry_event.rb +94 -0
  54. data/lib/contrast/agent/static_analysis.rb +5 -3
  55. data/lib/contrast/agent/telemetry.rb +137 -0
  56. data/lib/contrast/agent/telemetry_event.rb +33 -0
  57. data/lib/contrast/agent/thread_watcher.rb +66 -11
  58. data/lib/contrast/agent/version.rb +1 -1
  59. data/lib/contrast/agent.rb +21 -1
  60. data/lib/contrast/api/communication/connection_status.rb +10 -7
  61. data/lib/contrast/api/communication/messaging_queue.rb +37 -3
  62. data/lib/contrast/api/communication/response_processor.rb +15 -8
  63. data/lib/contrast/api/communication/service_lifecycle.rb +13 -3
  64. data/lib/contrast/api/communication/socket.rb +6 -8
  65. data/lib/contrast/api/communication/socket_client.rb +29 -12
  66. data/lib/contrast/api/communication/speedracer.rb +37 -1
  67. data/lib/contrast/api/communication/tcp_socket.rb +4 -3
  68. data/lib/contrast/api/communication/unix_socket.rb +1 -0
  69. data/lib/contrast/api/decorators/finding.rb +45 -0
  70. data/lib/contrast/components/api.rb +90 -0
  71. data/lib/contrast/components/app_context.rb +10 -41
  72. data/lib/contrast/components/app_context_extend.rb +78 -0
  73. data/lib/contrast/components/assess.rb +7 -0
  74. data/lib/contrast/components/base.rb +23 -0
  75. data/lib/contrast/components/config.rb +92 -13
  76. data/lib/contrast/components/contrast_service.rb +11 -0
  77. data/lib/contrast/components/sampling.rb +2 -2
  78. data/lib/contrast/config/agent_configuration.rb +1 -1
  79. data/lib/contrast/config/api_configuration.rb +27 -0
  80. data/lib/contrast/config/api_proxy_configuration.rb +14 -0
  81. data/lib/contrast/config/application_configuration.rb +2 -3
  82. data/lib/contrast/config/assess_configuration.rb +3 -2
  83. data/lib/contrast/config/base_configuration.rb +17 -28
  84. data/lib/contrast/config/certification_configuration.rb +15 -0
  85. data/lib/contrast/config/env_variables.rb +18 -0
  86. data/lib/contrast/config/heap_dump_configuration.rb +6 -6
  87. data/lib/contrast/config/inventory_configuration.rb +1 -5
  88. data/lib/contrast/config/protect_rule_configuration.rb +1 -1
  89. data/lib/contrast/config/request_audit_configuration.rb +18 -0
  90. data/lib/contrast/config/root_configuration.rb +1 -0
  91. data/lib/contrast/config/ruby_configuration.rb +6 -6
  92. data/lib/contrast/config/service_configuration.rb +2 -2
  93. data/lib/contrast/config.rb +1 -1
  94. data/lib/contrast/configuration.rb +4 -2
  95. data/lib/contrast/extension/assess/array.rb +5 -7
  96. data/lib/contrast/framework/manager.rb +22 -44
  97. data/lib/contrast/framework/manager_extend.rb +50 -0
  98. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +9 -6
  99. data/lib/contrast/framework/rails/patch/support.rb +31 -29
  100. data/lib/contrast/framework/rails/railtie.rb +1 -1
  101. data/lib/contrast/framework/sinatra/support.rb +2 -1
  102. data/lib/contrast/logger/application.rb +4 -0
  103. data/lib/contrast/logger/log.rb +8 -103
  104. data/lib/contrast/utils/assess/propagation_method_utils.rb +129 -0
  105. data/lib/contrast/utils/assess/property/tagged_utils.rb +165 -0
  106. data/lib/contrast/utils/assess/source_method_utils.rb +83 -0
  107. data/lib/contrast/utils/assess/tracking_util.rb +20 -15
  108. data/lib/contrast/utils/assess/trigger_method_utils.rb +138 -0
  109. data/lib/contrast/utils/class_util.rb +65 -54
  110. data/lib/contrast/utils/exclude_key.rb +20 -0
  111. data/lib/contrast/utils/findings.rb +62 -0
  112. data/lib/contrast/utils/hash_digest.rb +10 -73
  113. data/lib/contrast/utils/hash_digest_extend.rb +86 -0
  114. data/lib/contrast/utils/head_dump_utils_extend.rb +74 -0
  115. data/lib/contrast/utils/heap_dump_util.rb +2 -65
  116. data/lib/contrast/utils/invalid_configuration_util.rb +29 -0
  117. data/lib/contrast/utils/io_util.rb +1 -1
  118. data/lib/contrast/utils/log_utils.rb +108 -0
  119. data/lib/contrast/utils/lru_cache.rb +4 -2
  120. data/lib/contrast/utils/metrics_hash.rb +59 -0
  121. data/lib/contrast/utils/middleware_utils.rb +87 -0
  122. data/lib/contrast/utils/net_http_base.rb +158 -0
  123. data/lib/contrast/utils/object_share.rb +1 -0
  124. data/lib/contrast/utils/os.rb +23 -0
  125. data/lib/contrast/utils/patching/policy/patch_utils.rb +232 -0
  126. data/lib/contrast/utils/patching/policy/patcher_utils.rb +54 -0
  127. data/lib/contrast/utils/request_utils.rb +88 -0
  128. data/lib/contrast/utils/response_utils.rb +97 -0
  129. data/lib/contrast/utils/substitution_utils.rb +167 -0
  130. data/lib/contrast/utils/tag_util.rb +9 -9
  131. data/lib/contrast/utils/telemetry.rb +79 -0
  132. data/lib/contrast/utils/telemetry_client.rb +90 -0
  133. data/lib/contrast/utils/telemetry_identifier.rb +130 -0
  134. data/lib/contrast.rb +19 -1
  135. data/resources/assess/policy.json +12 -6
  136. data/resources/deadzone/policy.json +86 -5
  137. data/ruby-agent.gemspec +7 -6
  138. data/service_executables/VERSION +1 -1
  139. data/service_executables/linux/contrast-service +0 -0
  140. data/service_executables/mac/contrast-service +0 -0
  141. metadata +68 -26
  142. data/ext/cs__protect_kernel/cs__protect_kernel.c +0 -47
  143. data/ext/cs__protect_kernel/cs__protect_kernel.h +0 -12
  144. data/lib/contrast/config/default_value.rb +0 -17
  145. data/lib/contrast/extension/protect/kernel.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ad97d601b81e16e1d0263d86b60a3acd0e5a5ff9cb3f42598c262774a518169
4
- data.tar.gz: 749f87aefffd1e1504834dc7f919d45280cf560a20805184757dd9f6bda97477
3
+ metadata.gz: 2fd48ab0d63bb36fd51e032c360b2ffebe0c387a57e2b70a5e025c1af9667bfb
4
+ data.tar.gz: 7aaf091b2e3fd2ced8c8b11708db4a8e216bf55b7499fc235940e93ebff2ef1a
5
5
  SHA512:
6
- metadata.gz: cfa15549565b4f17c431332c7bc7c6fe84bd5bea321860db84f24a2df5e2d5241675200ed6e50ebe53fc319d94ade6ebfed26fe664fc297dde54a1fc9f645fda
7
- data.tar.gz: 017f02883faee2d281b7b052844653ddbb744fa27f02cf5739c38e50256eb054effb966c5b35b79b05e7d3af62f35d90509352f5c4327c9474e936c7e740ef19
6
+ metadata.gz: 56fbdd193cc27bcd7e21fe5c4f237276c616e4633344db18b6f27e7e73c99979131cbb9922a2d0cf947c0b666dd3a0d5098b120a805d8cf7b52bc73c6becc535
7
+ data.tar.gz: dce071438c0f996567c9867b4ab59900d2225fc3afc59887ffbd850705981f59f228360899084711fe88c9d566e33cdb20f3d5a9127b30efaa0c689274c84159
data/.simplecov CHANGED
@@ -4,5 +4,6 @@
4
4
  SimpleCov.minimum_coverage line: 94.75
5
5
  SimpleCov.start do
6
6
  add_filter '/spec/'
7
+ add_filter '/lib/contrast/extension/assess/erb.rb'
7
8
  enable_coverage :branch
8
9
  end
@@ -57,6 +57,45 @@ contrast_assess_module_module_eval(const int argc, const VALUE *argv,
57
57
  return ret;
58
58
  }
59
59
 
60
+ VALUE
61
+ contrast_assess_module_prepend(const int argc, const VALUE *argv,
62
+ const VALUE self) {
63
+
64
+ rb_prepend_module(self, argv[0]);
65
+
66
+ VALUE module_at;
67
+ VALUE rb_incl_in_mod_ary = rb_funcall(self, rb_intern("included_in"), 0);
68
+
69
+ if (RB_TYPE_P(rb_incl_in_mod_ary, T_ARRAY)) {
70
+ int i = 0;
71
+ int size = rb_funcall(rb_incl_in_mod_ary, rb_intern("length"), 0);
72
+ for (i = 0; i < size; ++i) {
73
+ module_at = rb_ary_entry(rb_incl_in_mod_ary, i);
74
+ if (RB_TYPE_P(module_at, T_MODULE)) {
75
+ rb_include_module(module_at, argv[0]);
76
+ }
77
+ }
78
+ }
79
+ return self;
80
+ }
81
+
82
+ VALUE
83
+ contrast_assess_module_included(const int argc, const VALUE *argv,
84
+ const VALUE self) {
85
+ VALUE frozen;
86
+ if (RB_TYPE_P(self, T_MODULE)) {
87
+ // check if frozen
88
+ frozen = rb_funcall(self, rb_intern("cs__frozen?"), 0);
89
+ if (frozen == Qfalse) {
90
+ VALUE ary = rb_funcall(self, rb_intern("included_in"), 0);
91
+ if (RB_TYPE_P(ary, T_ARRAY)) {
92
+ rb_ary_push(ary, argv[0]);
93
+ }
94
+ }
95
+ }
96
+ return self;
97
+ }
98
+
60
99
  void Init_cs__assess_module(void) {
61
100
  module_eval_trigger =
62
101
  rb_define_class_under(core_assess, "EvalTrigger", rb_cObject);
@@ -76,4 +115,13 @@ void Init_cs__assess_module(void) {
76
115
 
77
116
  contrast_register_patch("Module", "module_eval",
78
117
  contrast_assess_module_module_eval);
118
+ /*
119
+ * We patch these for better ancestors handling, and only for older ruby versions.
120
+ */
121
+ if (rb_ver_below_three()) {
122
+ contrast_register_patch("Module", "included",
123
+ contrast_assess_module_included);
124
+ contrast_register_patch("Module", "prepend",
125
+ contrast_assess_module_prepend);
126
+ }
79
127
  }
@@ -24,5 +24,12 @@ contrast_assess_module_class_eval(const int argc, const VALUE *argv,
24
24
  VALUE
25
25
  contrast_assess_module_module_eval(const int argc, const VALUE *argv,
26
26
  const VALUE mod);
27
+ VALUE
28
+ contrast_assess_module_prepend(const int argc, const VALUE *argv,
29
+ const VALUE self);
30
+
31
+ VALUE
32
+ contrast_assess_module_included(const int argc, const VALUE *argv,
33
+ const VALUE mod);
27
34
 
28
35
  void Init_cs__assess_module(void);
@@ -73,11 +73,20 @@ VALUE contrast_register_singleton_patch(const char *module_name,
73
73
  IMPL_ALIAS_SINGLETON);
74
74
  }
75
75
 
76
- VALUE contrast_register_singleton_prepend_patch(
77
- const char *module_name, const char *method_name,
78
- VALUE(c_fn)(const int, VALUE *, const VALUE)) {
76
+ VALUE contrast_register_prepend_patch(const char *module_name,
77
+ const char *method_name,
78
+ VALUE(c_fn)(const int, VALUE *,
79
+ const VALUE)) {
79
80
  return _contrast_register_patch(module_name, method_name, c_fn,
80
- IMPL_PREPEND);
81
+ IMPL_PREPEND_INSTANCE);
82
+ }
83
+
84
+ VALUE contrast_register_singleton_prepend_patch(const char *module_name,
85
+ const char *method_name,
86
+ VALUE(c_fn)(const int, VALUE *,
87
+ const VALUE)) {
88
+ return _contrast_register_patch(module_name, method_name, c_fn,
89
+ IMPL_PREPEND_SINGLETON);
81
90
  }
82
91
 
83
92
  static VALUE
@@ -122,8 +131,10 @@ _contrast_register_patch(const char *module_name, const char *method_name,
122
131
  case IMPL_ALIAS_SINGLETON:
123
132
  impl = ID2SYM(rb_sym_alias_singleton);
124
133
  break;
125
- case IMPL_PREPEND:
126
- impl = ID2SYM(rb_sym_prepend);
134
+ case IMPL_PREPEND_INSTANCE:
135
+ impl = ID2SYM(rb_sym_prepend_instance);
136
+ case IMPL_PREPEND_SINGLETON:
137
+ impl = ID2SYM(rb_sym_prepend_singleton);
127
138
  break;
128
139
  }
129
140
 
@@ -133,6 +144,11 @@ _contrast_register_patch(const char *module_name, const char *method_name,
133
144
  return SYM2ID(underlying_method_name);
134
145
  }
135
146
 
147
+ int rb_ver_below_three() {
148
+ int ruby_version = FIX2INT(rb_funcall(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")), rb_intern("to_i"), 0));
149
+ return ruby_version < 3;
150
+ }
151
+
136
152
  void Init_cs__common(void) {
137
153
  cs__send_method = rb_intern("send");
138
154
  cs__alias_method_sym = ID2SYM(rb_intern("alias_method"));
@@ -152,7 +168,8 @@ void Init_cs__common(void) {
152
168
  rb_sym_register_c_patch = rb_intern("register_c_patch");
153
169
  rb_sym_alias_instance = rb_intern("alias_instance");
154
170
  rb_sym_alias_singleton = rb_intern("alias_singleton");
155
- rb_sym_prepend = rb_intern("prepend");
171
+ rb_sym_prepend_instance = rb_intern("prepend_instance");
172
+ rb_sym_prepend_singleton = rb_intern("prepend_singleton");
156
173
 
157
174
  /* Ensure definition of core Contrast instrumentation modules */
158
175
  contrast = rb_define_module("Contrast");
@@ -6,7 +6,8 @@
6
6
  typedef enum {
7
7
  IMPL_ALIAS_INSTANCE,
8
8
  IMPL_ALIAS_SINGLETON,
9
- IMPL_PREPEND
9
+ IMPL_PREPEND_INSTANCE,
10
+ IMPL_PREPEND_SINGLETON,
10
11
  } patch_impl;
11
12
 
12
13
  static VALUE cs__send_method;
@@ -30,7 +31,16 @@ static VALUE rb_sym_instance_method;
30
31
  static VALUE rb_sym_register_c_patch;
31
32
  static VALUE rb_sym_alias_instance;
32
33
  static VALUE rb_sym_alias_singleton;
33
- static VALUE rb_sym_prepend;
34
+ static VALUE rb_sym_prepend_instance;
35
+ static VALUE rb_sym_prepend_singleton;
36
+
37
+ /*
38
+ * Check if ruby version is < 3.0.0.
39
+ * We are using this for handling ancestors of included modules.
40
+ * Since this is fixed after Ruby 3.0.0 we should remove this after
41
+ * dropping support for older versions, as no longer needed.
42
+ */
43
+ int rb_ver_below_three();
34
44
 
35
45
  void patch_via_funchook(void *original_function, void *hook_function);
36
46
 
@@ -43,7 +43,7 @@ VALUE contrast_patch_call_original(const VALUE *args) {
43
43
  if (rb_block_given_p()) {
44
44
  return rb_funcall_with_block_kw(object, method_id, argc, params, rb_block_proc(), RB_PASS_CALLED_KEYWORDS);
45
45
  } else {
46
- return rb_funcallv_kw(object, method_id, argc, params, RB_PASS_CALLED_KEYWORDS);
46
+ return rb_funcallv_kw(object, method_id, argc, params, RB_PASS_CALLED_KEYWORDS);
47
47
  }
48
48
  /* Ruby < 2.7 */
49
49
  #else
@@ -182,7 +182,8 @@ VALUE contrast_run_patches(const VALUE *wrapped_args) {
182
182
  contrast_patch_call_rescue,
183
183
  (VALUE)rescue_args, rb_eException, 0);
184
184
  break;
185
- case IMPL_PREPEND:
185
+ case IMPL_PREPEND_INSTANCE:
186
+ case IMPL_PREPEND_SINGLETON:
186
187
  original_ret = rb_rescue2(contrast_call_super, original_args,
187
188
  contrast_patch_call_rescue,
188
189
  (VALUE)rescue_args, rb_eException, 0);
@@ -247,10 +248,14 @@ VALUE contrast_patch_dispatch(const int argc, const VALUE *argv,
247
248
  */
248
249
  switch (impl) {
249
250
  case IMPL_ALIAS_INSTANCE:
250
- case IMPL_PREPEND:
251
+ case IMPL_PREPEND_INSTANCE:
251
252
  known =
252
253
  rb_funcall(patch_status, rb_sym_info_for, 3, object, method, Qtrue);
253
254
  break;
255
+ case IMPL_PREPEND_SINGLETON:
256
+ known =
257
+ rb_funcall(patch_status, rb_sym_info_for, 3, object, method, Qfalse);
258
+ break;
254
259
  case IMPL_ALIAS_SINGLETON:
255
260
  known = rb_funcall(patch_status, rb_sym_info_for, 3, object, method,
256
261
  Qfalse);
@@ -323,7 +328,8 @@ call_original:
323
328
  case IMPL_ALIAS_INSTANCE:
324
329
  case IMPL_ALIAS_SINGLETON:
325
330
  return contrast_patch_call_original(original_args);
326
- case IMPL_PREPEND:
331
+ case IMPL_PREPEND_INSTANCE:
332
+ case IMPL_PREPEND_SINGLETON:
327
333
  return contrast_call_super(original_args);
328
334
  };
329
335
  }
@@ -338,9 +344,14 @@ VALUE contrast_alias_singleton_patch(const int argc, const VALUE *argv,
338
344
  return contrast_patch_dispatch(argc, argv, IMPL_ALIAS_SINGLETON, object);
339
345
  }
340
346
 
341
- VALUE contrast_prepend_patch(const int argc, const VALUE *argv,
347
+ VALUE contrast_prepend_instance_patch(const int argc, const VALUE *argv,
342
348
  const VALUE object) {
343
- return contrast_patch_dispatch(argc, argv, IMPL_PREPEND, object);
349
+ return contrast_patch_dispatch(argc, argv, IMPL_PREPEND_INSTANCE, object);
350
+ }
351
+
352
+ VALUE contrast_prepend_singleton_patch(const int argc, const VALUE *argv,
353
+ const VALUE object) {
354
+ return contrast_patch_dispatch(argc, argv, IMPL_PREPEND_SINGLETON, object);
344
355
  }
345
356
 
346
357
  VALUE contrast_patch_define_method(const VALUE self, const VALUE clazz, const VALUE method_policy,
@@ -403,29 +414,55 @@ VALUE contrast_patch_define_method(const VALUE self, const VALUE clazz, const VA
403
414
  VALUE contrast_patch_prepend(const VALUE self, const VALUE originalModule,
404
415
  const VALUE method_policy) {
405
416
 
417
+ const VALUE instance = Qtrue;
418
+ const VALUE singleton = Qfalse;
406
419
  const VALUE original_method_name =
407
420
  rb_funcall(method_policy, rb_sym_method_name, 0);
408
421
  const VALUE is_private =
409
422
  rb_funcall(method_policy, rb_sym_private_method, 0);
410
423
  const VALUE is_instance_method =
411
424
  rb_funcall(method_policy, rb_sym_instance_method, 0);
412
- rb_funcall(patch_status, rb_sym_set_info_for, 5, originalModule,
413
- original_method_name, method_policy, Qtrue, Qnil);
425
+
426
+ // Set the value for instance or singleton method
427
+ if (RTEST(is_instance_method)){
428
+ rb_funcall(patch_status, rb_sym_set_info_for, 5, originalModule,
429
+ original_method_name, method_policy, instance, Qnil);
430
+
431
+ } else {
432
+ rb_funcall(patch_status, rb_sym_set_info_for, 5, originalModule,
433
+ original_method_name, method_policy, singleton, Qnil);
434
+ }
435
+
414
436
  VALUE module = rb_define_module_under(originalModule, "ContrastPrepend");
415
437
  VALUE str = rb_funcall(original_method_name, rb_sym_cs_to_s, 0);
416
438
  char *cMethodName = StringValueCStr(str);
417
439
  if (RTEST(is_instance_method)) {
418
440
  if (RTEST(is_private)) {
419
441
  rb_define_private_method(module, cMethodName,
420
- contrast_prepend_patch, -1);
442
+ contrast_prepend_instance_patch, -1);
421
443
  } else {
422
- rb_define_method(module, cMethodName, contrast_prepend_patch, -1);
444
+ rb_define_method(module, cMethodName, contrast_prepend_instance_patch, -1);
423
445
  }
424
446
  } else {
425
- rb_define_singleton_method(module, cMethodName, contrast_prepend_patch,
447
+ rb_define_singleton_method(module, cMethodName, contrast_prepend_singleton_patch,
426
448
  -1);
427
449
  }
428
450
  rb_prepend_module(originalModule, module);
451
+
452
+ if (rb_ver_below_three()) {
453
+ VALUE module_at;
454
+ VALUE rb_incl_in_mod_ary = rb_funcall(originalModule, rb_intern("included_in"), 0);
455
+ if (RB_TYPE_P(rb_incl_in_mod_ary, T_ARRAY)) {
456
+ int i = 0;
457
+ int size = rb_funcall(rb_incl_in_mod_ary, rb_intern("length"), 0);
458
+ for (i = 0; i < size; ++i) {
459
+ module_at = rb_ary_entry(rb_incl_in_mod_ary, i);
460
+ if (RB_TYPE_P(module_at, T_MODULE)) {
461
+ rb_include_module(module_at, module);
462
+ }
463
+ }
464
+ }
465
+ }
429
466
  return Qtrue;
430
467
  }
431
468
 
@@ -146,8 +146,11 @@ VALUE contrast_alias_instance_patch(const int argc, const VALUE *argv,
146
146
  VALUE contrast_alias_singleton_patch(const int argc, const VALUE *argv,
147
147
  const VALUE object);
148
148
 
149
- VALUE contrast_prepend_patch(const int argc, const VALUE *argv,
150
- const VALUE object);
149
+ VALUE contrast_prepend_instance_patch(const int argc, const VALUE *argv,
150
+ const VALUE object);
151
+
152
+ VALUE contrast_prepend_singleton_patch(const int argc, const VALUE *argv,
153
+ const VALUE object);
151
154
 
152
155
  /*
153
156
  * Patches a module's method by prepend:
@@ -0,0 +1,31 @@
1
+ /* Copyright (c) 2021 Contrast Security, Inc. See
2
+ * https://www.contrastsecurity.com/enduser-terms-0317a for more details. */
3
+
4
+ #include "cs__os_information.h"
5
+ #include <dlfcn.h>
6
+ #include <ruby.h>
7
+ #include <sys/utsname.h>
8
+
9
+ VALUE contrast, utils, os;
10
+
11
+ VALUE contrast_get_system_information()
12
+ {
13
+ struct utsname uname_pointer;
14
+
15
+ uname (&uname_pointer);
16
+
17
+ VALUE rb_data_hash = rb_hash_new();
18
+ rb_hash_aset(rb_data_hash, rb_str_new2("os_type"), rb_str_new2(uname_pointer.sysname));
19
+ rb_hash_aset(rb_data_hash, rb_str_new2("os_version"), rb_str_new2(uname_pointer.release));
20
+ rb_hash_aset(rb_data_hash, rb_str_new2("os_complete_version"), rb_str_new2(uname_pointer.version));
21
+ rb_hash_aset(rb_data_hash, rb_str_new2("os_arch"), rb_str_new2(uname_pointer.machine));
22
+ return rb_data_hash;
23
+ }
24
+
25
+ void Init_cs__os_information(void)
26
+ {
27
+ contrast = rb_define_module("Contrast");
28
+ utils = rb_define_module_under(contrast, "Utils");
29
+ os = rb_define_module_under(utils, "OS");
30
+ rb_define_module_function(os, "get_system_information", contrast_get_system_information, 0);
31
+ }
@@ -0,0 +1,7 @@
1
+ #include <ruby.h>
2
+
3
+ extern VALUE contrast, utils, os;
4
+
5
+ VALUE contrast_get_system_information();
6
+
7
+ void Init_cs__os_information(void);
@@ -54,7 +54,7 @@ module Contrast
54
54
 
55
55
  # These methods rely on the above being set. Don't move them!
56
56
  @event_id = Contrast::Agent::Assess::ContrastEvent.next_atomic_id
57
- @tags = Contrast::Agent::Assess::Tracker.properties(tagged)&.tags
57
+ @tags = Contrast::Agent::Assess::Tracker.properties(tagged)&.get_tags
58
58
  find_parent_events!(policy_node, object, ret, args)
59
59
  snapshot!(object, ret, args)
60
60
  capture_stacktrace!
@@ -35,7 +35,7 @@ module Contrast
35
35
  if object
36
36
  @object = Contrast::Utils::ClassUtil.to_contrast_string(object)
37
37
  @object_type = object.cs__class.cs__name
38
- @tags = Contrast::Agent::Assess::Tracker.properties(object)&.tags
38
+ @tags = Contrast::Agent::Assess::Tracker.properties(object)&.get_tags
39
39
  else
40
40
  @object = Contrast::Utils::ObjectShare::NIL_STRING
41
41
  @object_type = nil.cs__class.cs__name
@@ -24,6 +24,8 @@ module Contrast
24
24
  # the name of the method to taint, mapped to the properties it
25
25
  # should apply
26
26
  def create_sources klass, tainted_columns
27
+ return unless Contrast::ASSESS.require_dynamic_sources?
28
+
27
29
  class_name = klass.cs__name
28
30
  instance_methods = klass.instance_methods
29
31
  instance_methods.concat(klass.private_instance_methods)
@@ -135,14 +135,14 @@ module Contrast
135
135
 
136
136
  converted = []
137
137
  markers.split(Contrast::Utils::ObjectShare::COMMA).each do |t|
138
- case t
139
- when Contrast::Utils::ObjectShare::OBJECT_KEY,
138
+ converted << case t
139
+ when Contrast::Utils::ObjectShare::OBJECT_KEY,
140
140
  Contrast::Utils::ObjectShare::RETURN_KEY
141
141
 
142
- converted << t
143
- else
144
- converted << Integer(t[1..-1])
145
- end
142
+ t
143
+ else
144
+ Integer(t[1..-1])
145
+ end
146
146
  end
147
147
  converted
148
148
  end
@@ -32,8 +32,13 @@ 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
35
39
  # TODO: RUBY-1014 - remove non-AST approach
36
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.
37
42
  ast = RubyVM::AbstractSyntaxTree.parse_file(trace_point.path)
38
43
  provider_values.each do |provider|
39
44
  provider.parse(trace_point, ast)
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/components/logger'
5
+ require 'contrast/utils/lru_cache'
5
6
 
6
7
  module Contrast
7
8
  module Agent
@@ -12,6 +13,7 @@ module Contrast
12
13
  include Contrast::Components::Logger::InstanceMethods
13
14
  extend Contrast::Components::Logger::InstanceMethods
14
15
 
16
+ @lru_cache = Contrast::Utils::LRUCache.new
15
17
  UNDUPLICABLE_MODULES = [
16
18
  Enumerator # dup'ing results in 'can't copy execution context'
17
19
  ].cs__freeze
@@ -70,16 +72,23 @@ module Contrast
70
72
 
71
73
  def append_object_details preshift, initializing, object
72
74
  can = can_dup?(initializing, object)
73
- preshift.object = can ? object.dup : object
75
+ preshift.object = if @lru_cache.key?(object.__id__) && !Contrast::Agent::Assess::Tracker.tracked?(object)
76
+ @lru_cache[object.__id__]
77
+ else
78
+ can ? object.dup : object
79
+ end
74
80
  preshift.object_length = if Contrast::Utils::DuckUtils.quacks_to?(preshift.object, :length)
75
81
  object.length
76
82
  else
77
83
  0
78
84
  end
85
+
79
86
  return unless can
87
+
80
88
  return unless Contrast::Agent::Assess::Tracker.tracked?(object)
81
89
 
82
90
  Contrast::Agent::Assess::Tracker.copy(object, preshift.object)
91
+ @lru_cache[object.__id__] = object
83
92
  end
84
93
 
85
94
  def append_arg_details preshift, args
@@ -88,15 +97,19 @@ module Contrast
88
97
  preshift.arg_lengths = Array.new(args_length)
89
98
  idx = 0
90
99
  while idx < args_length
91
- original_arg = args[idx]
92
- p_arg = can_dup?(false, original_arg) ? original_arg.dup : original_arg
100
+ or_arg = args[idx]
101
+ p_arg = if @lru_cache.key?(or_arg.__id__)
102
+ @lru_cache[or_arg.__id__]
103
+ else
104
+ can_dup?(false, or_arg) ? or_arg.dup : or_arg
105
+ end
93
106
  preshift.args[idx] = p_arg
94
107
  preshift.arg_lengths[idx] = Contrast::Utils::DuckUtils.quacks_to?(p_arg, :length) ? p_arg.length : 0
95
108
  idx += 1
96
- next if p_arg.__id__ == original_arg.__id__
97
- next unless Contrast::Agent::Assess::Tracker.tracked?(original_arg)
109
+ next if p_arg.__id__ == or_arg.__id__
98
110
 
99
- Contrast::Agent::Assess::Tracker.copy(original_arg, p_arg)
111
+ Contrast::Agent::Assess::Tracker.copy(or_arg, p_arg)
112
+ @lru_cache[p_arg.__id__] = p_arg
100
113
  end
101
114
  end
102
115
  end
@@ -7,6 +7,7 @@ require 'contrast/agent/assess/policy/propagator'
7
7
  require 'contrast/components/logger'
8
8
  require 'contrast/utils/object_share'
9
9
  require 'contrast/utils/sha256_builder'
10
+ require 'contrast/utils/assess/propagation_method_utils'
10
11
 
11
12
  module Contrast
12
13
  module Agent
@@ -16,35 +17,9 @@ module Contrast
16
17
  # untrusted value. In general, these methods work on the String class or a holder of Strings.
17
18
  module PropagationMethod
18
19
  extend Contrast::Components::Logger::InstanceMethods
19
-
20
- APPEND_ACTION = 'APPEND'
21
- CENTER_ACTION = 'CENTER'
22
- INSERT_ACTION = 'INSERT'
23
- KEEP_ACTION = 'KEEP'
24
- NEXT_ACTION = 'NEXT'
25
- NOOP_ACTION = 'NOOP'
26
- PREPEND_ACTION = 'PREPEND'
27
- REPLACE_ACTION = 'REPLACE'
28
- REMOVE_ACTION = 'REMOVE'
29
- REVERSE_ACTION = 'REVERSE'
30
- SPLAT_ACTION = 'SPLAT'
31
- SPLIT_ACTION = 'SPLIT'
32
- DB_WRITE_ACTION = 'DB_WRITE'
33
- CUSTOM_ACTION = 'CUSTOM'
20
+ extend Contrast::Utils::Assess::PropagationMethodUtils
34
21
 
35
22
  class << self
36
- def determine_target propagation_node, ret, object, args
37
- target = propagation_node.targets[0]
38
- case target
39
- when Contrast::Utils::ObjectShare::OBJECT_KEY
40
- object
41
- when Contrast::Utils::ObjectShare::RETURN_KEY
42
- ret
43
- else
44
- args[target]
45
- end
46
- end
47
-
48
23
  # @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] the policy that governs the
49
24
  # patches to this method
50
25
  # @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
@@ -65,21 +40,6 @@ module Contrast
65
40
  PropagationMethod.apply_propagator(propagation_node, preshift, target, object, ret, args, block)
66
41
  end
67
42
 
68
- PROPAGATION_ACTIONS = {
69
- APPEND_ACTION => Contrast::Agent::Assess::Policy::Propagator::Append,
70
- CENTER_ACTION => Contrast::Agent::Assess::Policy::Propagator::Center,
71
- INSERT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Insert,
72
- KEEP_ACTION => Contrast::Agent::Assess::Policy::Propagator::Keep,
73
- NEXT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Next,
74
- NOOP_ACTION => nil,
75
- PREPEND_ACTION => Contrast::Agent::Assess::Policy::Propagator::Prepend,
76
- REPLACE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Replace,
77
- REMOVE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Remove,
78
- REVERSE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Reverse,
79
- SPLAT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Splat,
80
- SPLIT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Split
81
- }.cs__freeze
82
-
83
43
  # I lied above. We had to figure out what the target of the propagation was. Now that we know, we'll
84
44
  # actually do things to it. Note that the return of this method will replace the original return of the
85
45
  # patched function unless it is nil, so be sure you're returning what you intend.
@@ -116,80 +76,6 @@ module Contrast
116
76
  nil
117
77
  end
118
78
 
119
- # Custom actions tend to be the more complex of our propagations. Often, the method has to make decisions
120
- # about the target based on the context with which the method was called. As such, defer determining if the
121
- # target is valid to that method.
122
- #
123
- # In all other cases, a target is valid for propagation if it is not nil
124
- #
125
- # @param target [Object] the thing to which to propagate
126
- # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
127
- # propagation event.
128
- # @return [Boolean]
129
- def valid_target? target, propagation_node
130
- return true if propagation_node.action == CUSTOM_ACTION
131
-
132
- !!target
133
- end
134
-
135
- ZERO_LENGTH_ACTIONS = [DB_WRITE_ACTION, CUSTOM_ACTION, KEEP_ACTION, REPLACE_ACTION, SPLAT_ACTION].cs__freeze
136
- # If the action required needs a length and the target does not have one, the length is not valid
137
- #
138
- # @param target [Object] the thing to which to propagate
139
- # @param action [String] the name of the action taken during this propagation
140
- # @return [Boolean]
141
- def valid_length? target, action
142
- return true if ZERO_LENGTH_ACTIONS.include?(action)
143
-
144
- if Contrast::Utils::DuckUtils.quacks_to?(target, :length)
145
- target.length != 0 # rubocop:disable Style/ZeroLengthPredicate
146
- else
147
- !target.to_s.empty?
148
- end
149
- end
150
-
151
- # Before we do any work, we should check if we even need to. If the source and target of this patcher are
152
- # not tracked, there's no need to do anything. A copy of nothing is still nothing.
153
- #
154
- # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
155
- # propagation event.
156
- # @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
157
- # the invocation of the patched method.
158
- # @param target [Object] the thing to which to propagate
159
- # @return [Boolean]
160
- def can_propagate? propagation_node, preshift, target
161
- return false unless appropriate_target?(propagation_node, target)
162
- return true if Contrast::Utils::Assess::TrackingUtil.tracked?(target)
163
- return false unless preshift
164
-
165
- propagation_node.sources.each do |source|
166
- case source
167
- when Contrast::Utils::ObjectShare::OBJECT_KEY
168
- return true if Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.object)
169
- else
170
- # has to be P, there's no ret source type (yet? ever?)
171
- return true if preshift.args && Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.args[source])
172
- end
173
- end
174
- false
175
- end
176
-
177
- # We cannot propagate to frozen things that have not been updated to work with our property tracking,
178
- # unless they're duplicable and the return. We probably shouldn't propagate to frozen things at all, as
179
- # they're supposed to be immutable, but third parties do jenky things, so allow it as long as it is safe to
180
- # do.
181
- #
182
- # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
183
- # propagation event.
184
- # @param target [Object] the Target to which to propagate.
185
- # @return [Boolean] if the target can be propagated to
186
- def appropriate_target? propagation_node, target
187
- # special handle Returns b/c we can do unfreezing magic during propagation
188
- return true if propagation_node.targets[0] == Contrast::Utils::ObjectShare::RETURN_KEY
189
-
190
- Contrast::Agent::Assess::Tracker.trackable?(target)
191
- end
192
-
193
79
  # If this patcher has tags, apply them to the entire target
194
80
  # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
195
81
  # propagation event.
@@ -95,8 +95,8 @@ module Contrast
95
95
 
96
96
  def needs_object?
97
97
  if @_needs_object.nil?
98
- @_needs_object = action == Contrast::Agent::Assess::Policy::PropagationMethod::CUSTOM_ACTION ||
99
- action == Contrast::Agent::Assess::Policy::PropagationMethod::DB_WRITE_ACTION ||
98
+ @_needs_object = action == Contrast::Utils::Assess::PropagationMethodUtils::CUSTOM_ACTION ||
99
+ action == Contrast::Utils::Assess::PropagationMethodUtils::DB_WRITE_ACTION ||
100
100
  sources.any?(Contrast::Utils::ObjectShare::OBJECT_KEY) ||
101
101
  targets.any?(Contrast::Utils::ObjectShare::OBJECT_KEY)
102
102
  end
@@ -105,8 +105,8 @@ module Contrast
105
105
 
106
106
  def needs_args?
107
107
  if @_needs_args.nil?
108
- @_needs_args = action == Contrast::Agent::Assess::Policy::PropagationMethod::CUSTOM_ACTION ||
109
- action == Contrast::Agent::Assess::Policy::PropagationMethod::DB_WRITE_ACTION ||
108
+ @_needs_args = action == Contrast::Utils::Assess::PropagationMethodUtils::CUSTOM_ACTION ||
109
+ action == Contrast::Utils::Assess::PropagationMethodUtils::DB_WRITE_ACTION ||
110
110
  sources.any? { |source| source.is_a?(Integer) || source.is_a?(Symbol) } ||
111
111
  targets.any? { |target| target.is_a?(Integer) || target.is_a?(Symbol) }
112
112
  end