contrast-agent 4.10.0 → 4.13.1
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.
- checksums.yaml +4 -4
- data/ext/cs__assess_module/cs__assess_module.c +48 -0
- data/ext/cs__assess_module/cs__assess_module.h +7 -0
- data/ext/cs__common/cs__common.c +24 -7
- data/ext/cs__common/cs__common.h +12 -2
- data/ext/cs__contrast_patch/cs__contrast_patch.c +48 -11
- data/ext/cs__contrast_patch/cs__contrast_patch.h +5 -2
- data/ext/cs__os_information/cs__os_information.c +31 -0
- data/ext/cs__os_information/cs__os_information.h +7 -0
- data/ext/{cs__protect_kernel → cs__os_information}/extconf.rb +0 -0
- data/lib/contrast/agent/assess/contrast_event.rb +1 -1
- data/lib/contrast/agent/assess/contrast_object.rb +1 -4
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +2 -0
- data/lib/contrast/agent/assess/policy/preshift.rb +25 -11
- data/lib/contrast/agent/assess/policy/propagation_method.rb +2 -116
- data/lib/contrast/agent/assess/policy/propagation_node.rb +4 -4
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +2 -0
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +4 -4
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +4 -9
- data/lib/contrast/agent/assess/policy/source_method.rb +2 -71
- data/lib/contrast/agent/assess/policy/trigger_method.rb +4 -107
- data/lib/contrast/agent/assess/policy/trigger_node.rb +52 -19
- data/lib/contrast/agent/assess/property/tagged.rb +15 -132
- data/lib/contrast/agent/deadzone/policy/policy.rb +6 -0
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +2 -1
- data/lib/contrast/agent/metric_telemetry_event.rb +26 -0
- data/lib/contrast/agent/middleware.rb +22 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +0 -1
- data/lib/contrast/agent/patching/policy/method_policy.rb +54 -9
- data/lib/contrast/agent/patching/policy/patch.rb +37 -238
- data/lib/contrast/agent/patching/policy/patcher.rb +3 -42
- data/lib/contrast/agent/request.rb +5 -3
- data/lib/contrast/agent/request_context.rb +32 -11
- data/lib/contrast/agent/request_handler.rb +7 -3
- data/lib/contrast/agent/rule_set.rb +2 -4
- data/lib/contrast/agent/scope.rb +32 -20
- data/lib/contrast/agent/startup_metrics_telemetry_event.rb +71 -0
- data/lib/contrast/agent/static_analysis.rb +4 -2
- data/lib/contrast/agent/telemetry.rb +129 -0
- data/lib/contrast/agent/telemetry_event.rb +34 -0
- data/lib/contrast/agent/thread_watcher.rb +43 -14
- data/lib/contrast/agent/tracepoint_hook.rb +11 -3
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent.rb +6 -1
- data/lib/contrast/components/api.rb +34 -0
- data/lib/contrast/components/app_context.rb +24 -0
- data/lib/contrast/components/assess.rb +7 -0
- data/lib/contrast/components/config.rb +90 -11
- data/lib/contrast/components/contrast_service.rb +6 -0
- data/lib/contrast/config/api_configuration.rb +22 -0
- data/lib/contrast/config/assess_configuration.rb +1 -0
- data/lib/contrast/config/env_variables.rb +25 -0
- data/lib/contrast/config/root_configuration.rb +1 -0
- data/lib/contrast/config/service_configuration.rb +2 -1
- data/lib/contrast/config.rb +1 -0
- data/lib/contrast/configuration.rb +3 -0
- data/lib/contrast/framework/manager.rb +14 -12
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +9 -6
- data/lib/contrast/framework/rails/patch/support.rb +31 -29
- data/lib/contrast/logger/application.rb +4 -0
- data/lib/contrast/utils/assess/propagation_method_utils.rb +129 -0
- data/lib/contrast/utils/assess/property/tagged_utils.rb +142 -0
- data/lib/contrast/utils/assess/source_method_utils.rb +83 -0
- data/lib/contrast/utils/assess/trigger_method_utils.rb +138 -0
- data/lib/contrast/utils/class_util.rb +58 -44
- data/lib/contrast/utils/exclude_key.rb +20 -0
- data/lib/contrast/utils/io_util.rb +42 -34
- data/lib/contrast/utils/lru_cache.rb +45 -0
- data/lib/contrast/utils/metrics_hash.rb +59 -0
- data/lib/contrast/utils/os.rb +23 -0
- data/lib/contrast/utils/patching/policy/patch_utils.rb +232 -0
- data/lib/contrast/utils/patching/policy/patcher_utils.rb +54 -0
- data/lib/contrast/utils/requests_client.rb +150 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +1 -1
- data/lib/contrast/utils/telemetry.rb +77 -0
- data/lib/contrast/utils/telemetry_identifier.rb +137 -0
- data/lib/contrast.rb +19 -1
- data/resources/assess/policy.json +12 -6
- data/resources/deadzone/policy.json +86 -5
- data/ruby-agent.gemspec +2 -1
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +32 -14
- data/ext/cs__protect_kernel/cs__protect_kernel.c +0 -47
- data/ext/cs__protect_kernel/cs__protect_kernel.h +0 -12
- data/lib/contrast/extension/protect/kernel.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96cff410085a542c1003dda242268f349bc20f738b82bde70725b695661a79bc
|
4
|
+
data.tar.gz: 2a5d703693f697785034df1f602ef0f61241ae16edf11dbd174ad9a8da01b72c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 409632acc3352b7c172a1aa12c9f5de482b5e5c3c0307b0732c48c7b8cf8d56c5ef5a4c039a0c866dd0c1ea31340b21ee8e4bcc0f2c4c4fdea9cd4fffcbaa212
|
7
|
+
data.tar.gz: 17b56ee4355a472b637cf1f9059f1bfce01319351713fc3b35e744bc3afad3d4f068cf77dd474032193249cb8f178141d7d7da2aa7b4d2f3a0cc2158e1c55d0c
|
@@ -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);
|
data/ext/cs__common/cs__common.c
CHANGED
@@ -73,11 +73,20 @@ VALUE contrast_register_singleton_patch(const char *module_name,
|
|
73
73
|
IMPL_ALIAS_SINGLETON);
|
74
74
|
}
|
75
75
|
|
76
|
-
VALUE
|
77
|
-
|
78
|
-
|
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
|
-
|
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
|
126
|
-
impl = ID2SYM(
|
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
|
-
|
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");
|
data/ext/cs__common/cs__common.h
CHANGED
@@ -6,7 +6,8 @@
|
|
6
6
|
typedef enum {
|
7
7
|
IMPL_ALIAS_INSTANCE,
|
8
8
|
IMPL_ALIAS_SINGLETON,
|
9
|
-
|
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
|
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
|
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
|
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
|
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
|
347
|
+
VALUE contrast_prepend_instance_patch(const int argc, const VALUE *argv,
|
342
348
|
const VALUE object) {
|
343
|
-
return contrast_patch_dispatch(argc, argv,
|
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
|
-
|
413
|
-
|
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
|
-
|
442
|
+
contrast_prepend_instance_patch, -1);
|
421
443
|
} else {
|
422
|
-
rb_define_method(module, cMethodName,
|
444
|
+
rb_define_method(module, cMethodName, contrast_prepend_instance_patch, -1);
|
423
445
|
}
|
424
446
|
} else {
|
425
|
-
rb_define_singleton_method(module, cMethodName,
|
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
|
150
|
-
|
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
|
+
}
|
File without changes
|
@@ -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)&.
|
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,10 +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
|
-
|
39
|
-
# restore immutability. For instance, if these tags were on a
|
40
|
-
# String that was then #reverse!'d, would our tags be wrong?
|
41
|
-
@tags = Contrast::Agent::Assess::Tracker.properties(object)&.tags
|
38
|
+
@tags = Contrast::Agent::Assess::Tracker.properties(object)&.get_tags
|
42
39
|
else
|
43
40
|
@object = Contrast::Utils::ObjectShare::NIL_STRING
|
44
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)
|
@@ -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,32 +72,44 @@ module Contrast
|
|
70
72
|
|
71
73
|
def append_object_details preshift, initializing, object
|
72
74
|
can = can_dup?(initializing, object)
|
73
|
-
preshift.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
|
86
|
-
|
95
|
+
args_length = args.length
|
96
|
+
preshift.args = Array.new(args_length)
|
97
|
+
preshift.arg_lengths = Array.new(args_length)
|
87
98
|
idx = 0
|
88
|
-
while idx <
|
89
|
-
|
90
|
-
p_arg =
|
99
|
+
while idx < args_length
|
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
|
106
|
+
preshift.args[idx] = p_arg
|
107
|
+
preshift.arg_lengths[idx] = Contrast::Utils::DuckUtils.quacks_to?(p_arg, :length) ? p_arg.length : 0
|
91
108
|
idx += 1
|
92
|
-
next if p_arg.__id__ ==
|
93
|
-
next unless Contrast::Agent::Assess::Tracker.tracked?(original_arg)
|
109
|
+
next if p_arg.__id__ == or_arg.__id__
|
94
110
|
|
95
|
-
Contrast::Agent::Assess::Tracker.copy(
|
96
|
-
|
97
|
-
preshift.arg_lengths = preshift.args.map do |preshift_arg|
|
98
|
-
Contrast::Utils::DuckUtils.quacks_to?(preshift_arg, :length) ? preshift_arg.length : 0
|
111
|
+
Contrast::Agent::Assess::Tracker.copy(or_arg, p_arg)
|
112
|
+
@lru_cache[p_arg.__id__] = p_arg
|
99
113
|
end
|
100
114
|
end
|
101
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::
|
99
|
-
action == Contrast::
|
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::
|
109
|
-
action == Contrast::
|
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
|
@@ -13,6 +13,8 @@ module Contrast
|
|
13
13
|
class DatabaseWrite < Contrast::Agent::Assess::Policy::Propagator::Base
|
14
14
|
class << self
|
15
15
|
def propagate propagation_node, preshift, target
|
16
|
+
return unless Contrast::ASSESS.require_dynamic_sources?
|
17
|
+
|
16
18
|
class_type = preshift.object.cs__class
|
17
19
|
class_name = class_type.cs__name
|
18
20
|
tainted_columns = {}
|