contrast-agent 3.14.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +18 -15
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +1 -0
- data/ext/cs__assess_string/cs__assess_string.c +24 -25
- data/ext/cs__assess_string/cs__assess_string.h +3 -1
- data/ext/cs__common/cs__common.c +4 -2
- data/ext/cs__common/cs__common.h +1 -1
- data/lib/contrast.rb +1 -1
- data/lib/contrast/agent.rb +4 -12
- data/lib/contrast/agent/assess.rb +1 -0
- data/lib/contrast/agent/assess/contrast_event.rb +143 -79
- data/lib/contrast/agent/assess/events/source_event.rb +1 -1
- data/lib/contrast/agent/assess/finalizers/freeze.rb +3 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +45 -1
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +10 -3
- data/lib/contrast/agent/assess/policy/patcher.rb +1 -1
- data/lib/contrast/agent/assess/policy/policy.rb +0 -2
- data/lib/contrast/agent/assess/policy/policy_node.rb +15 -10
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +19 -3
- data/lib/contrast/agent/assess/policy/preshift.rb +7 -11
- data/lib/contrast/agent/assess/policy/propagation_method.rb +50 -33
- data/lib/contrast/agent/assess/policy/propagator/append.rb +8 -5
- data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/center.rb +9 -5
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -3
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +7 -4
- data/lib/contrast/agent/assess/policy/propagator/keep.rb +4 -1
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +4 -7
- data/lib/contrast/agent/assess/policy/propagator/next.rb +7 -5
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +8 -5
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +8 -4
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -2
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +7 -5
- data/lib/contrast/agent/assess/policy/propagator/select.rb +13 -7
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +10 -9
- data/lib/contrast/agent/assess/policy/propagator/split.rb +24 -19
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +47 -31
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +11 -5
- data/lib/contrast/agent/assess/policy/source_method.rb +85 -58
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -12
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +76 -28
- data/lib/contrast/agent/assess/policy/trigger_node.rb +38 -43
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +2 -1
- data/lib/contrast/agent/assess/properties.rb +2 -0
- data/lib/contrast/agent/assess/property/evented.rb +5 -18
- data/lib/contrast/agent/assess/property/tagged.rb +9 -3
- data/lib/contrast/agent/assess/property/updated.rb +131 -0
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +58 -5
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +23 -8
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +83 -14
- data/lib/contrast/agent/assess/tag.rb +1 -1
- data/lib/contrast/agent/assess/tracker.rb +66 -0
- data/lib/contrast/agent/at_exit_hook.rb +5 -5
- data/lib/contrast/agent/class_reopener.rb +7 -5
- data/lib/contrast/agent/inventory.rb +15 -0
- data/lib/contrast/agent/inventory/dependencies.rb +50 -0
- data/lib/contrast/agent/inventory/dependency_analysis.rb +37 -0
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +104 -0
- data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +38 -0
- data/lib/contrast/agent/middleware.rb +1 -3
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +5 -5
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +20 -20
- data/lib/contrast/agent/patching/policy/module_policy.rb +10 -10
- data/lib/contrast/agent/patching/policy/patch.rb +6 -0
- data/lib/contrast/agent/patching/policy/patcher.rb +13 -22
- data/lib/contrast/agent/patching/policy/policy.rb +17 -6
- data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +3 -5
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +4 -3
- data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +9 -25
- data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +1 -0
- data/lib/contrast/agent/request.rb +34 -34
- data/lib/contrast/agent/request_handler.rb +1 -1
- data/lib/contrast/agent/response.rb +17 -6
- data/lib/contrast/agent/rewriter.rb +1 -3
- data/lib/contrast/agent/scope.rb +59 -53
- data/lib/contrast/agent/static_analysis.rb +7 -7
- data/lib/contrast/agent/tracepoint_hook.rb +1 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +1 -4
- data/lib/contrast/api/communication/socket_client.rb +36 -1
- data/lib/contrast/api/decorators.rb +3 -0
- data/lib/contrast/api/decorators/address.rb +13 -14
- data/lib/contrast/api/decorators/application_update.rb +2 -4
- data/lib/contrast/api/decorators/library.rb +53 -0
- data/lib/contrast/api/decorators/library_usage_update.rb +30 -0
- data/lib/contrast/api/decorators/message.rb +1 -0
- data/lib/contrast/api/decorators/trace_event.rb +25 -23
- data/lib/contrast/common_agent_configuration.rb +2 -1
- data/lib/contrast/components/agent.rb +6 -5
- data/lib/contrast/components/app_context.rb +49 -38
- data/lib/contrast/components/config.rb +30 -48
- data/lib/contrast/components/contrast_service.rb +9 -9
- data/lib/contrast/components/interface.rb +25 -3
- data/lib/contrast/components/inventory.rb +6 -1
- data/lib/contrast/components/scope.rb +49 -6
- data/lib/contrast/components/settings.rb +23 -23
- data/lib/contrast/config/application_configuration.rb +5 -2
- data/lib/contrast/config/inventory_configuration.rb +2 -2
- data/lib/contrast/config/service_configuration.rb +8 -0
- data/lib/contrast/configuration.rb +88 -47
- data/lib/contrast/extension/assess.rb +0 -2
- data/lib/contrast/extension/assess/array.rb +15 -8
- data/lib/contrast/extension/assess/erb.rb +11 -3
- data/lib/contrast/extension/assess/eval_trigger.rb +6 -6
- data/lib/contrast/extension/assess/exec_trigger.rb +1 -4
- data/lib/contrast/extension/assess/fiber.rb +12 -12
- data/lib/contrast/extension/assess/hash.rb +5 -6
- data/lib/contrast/extension/assess/kernel.rb +28 -23
- data/lib/contrast/extension/assess/marshal.rb +11 -6
- data/lib/contrast/extension/assess/regexp.rb +8 -7
- data/lib/contrast/extension/assess/string.rb +21 -21
- data/lib/contrast/extension/protect/kernel.rb +3 -3
- data/lib/contrast/framework/base_support.rb +1 -1
- data/lib/contrast/framework/manager.rb +3 -3
- data/lib/contrast/framework/rack/patch/session_cookie.rb +22 -28
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +13 -13
- data/lib/contrast/framework/rails/patch/assess_configuration.rb +5 -11
- data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +10 -10
- data/lib/contrast/framework/rails/patch/support.rb +1 -1
- data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +11 -11
- data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +12 -12
- data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -3
- data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +12 -12
- data/lib/contrast/framework/rails/support.rb +5 -0
- data/lib/contrast/framework/sinatra/patch/base.rb +11 -11
- data/lib/contrast/framework/sinatra/support.rb +4 -4
- data/lib/contrast/logger/application.rb +11 -3
- data/lib/contrast/logger/log.rb +7 -2
- data/lib/contrast/utils/assess/tracking_util.rb +48 -3
- data/lib/contrast/utils/duck_utils.rb +0 -10
- data/lib/contrast/utils/env_configuration_item.rb +2 -1
- data/lib/contrast/utils/invalid_configuration_util.rb +20 -21
- data/lib/contrast/utils/inventory_util.rb +0 -7
- data/lib/contrast/utils/sha256_builder.rb +0 -12
- data/lib/contrast/utils/string_utils.rb +10 -5
- data/resources/assess/policy.json +31 -22
- data/ruby-agent.gemspec +21 -18
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +71 -30
- data/lib/contrast/agent/assess/finalizers/finalize.rb +0 -21
- data/lib/contrast/extension/assess/assess_extension.rb +0 -145
- data/lib/contrast/utils/boolean_util.rb +0 -30
- data/lib/contrast/utils/freeze_util.rb +0 -32
- data/lib/contrast/utils/gemfile_reader.rb +0 -193
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 713e0f9cd16184d4b5da094f0d05b006870f557edfa0fc0ac199bf1035acfe45
|
|
4
|
+
data.tar.gz: f37a1ab7901a7c42bf5dce897c6dd0218f4df40d057c8719e3027f802ecd3c52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1bcf5495957815fbe1acc801e9cdc9567a1a25f657b425a335cfa1412054ecdf4f92662d0eef0b19bdc2a1c5295b758d19ed4adf4cb7f37ef67bfaf4b67262f
|
|
7
|
+
data.tar.gz: bd3e6f02d68c7eaa9385f6626e52b3fe16cecbac10d53f8c82dd01b733c9f39666183afd21df601318ed95c482338b786e13cb8f087c8076872cd5fb3f4cfad8
|
|
@@ -14,20 +14,19 @@ static VALUE contrast_assess_marshal_module_load(const int argc,
|
|
|
14
14
|
if (argc >= 1) {
|
|
15
15
|
source_string = argv[0];
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
17
|
+
VALUE tracked =
|
|
18
|
+
rb_funcall(properties_hash, rb_sym_hash_tracked, 1, source_string);
|
|
19
|
+
|
|
20
|
+
if (tracked == Qtrue) {
|
|
21
|
+
VALUE skip =
|
|
22
|
+
rb_funcall(contrast_patcher(), rb_sym_skip_assess_analysis, 0);
|
|
23
|
+
|
|
24
|
+
if (skip == Qfalse) {
|
|
25
|
+
VALUE scope =
|
|
26
|
+
rb_funcall(contrast_patcher(), rb_sym_enter_scope, 0);
|
|
27
|
+
rb_funcall(marshal_module, rb_sym_assess_load_trigger_check, 2,
|
|
28
|
+
source_string, result);
|
|
29
|
+
rb_funcall(contrast_patcher(), rb_sym_exit_scope, 0);
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
32
|
}
|
|
@@ -35,7 +34,11 @@ static VALUE contrast_assess_marshal_module_load(const int argc,
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
void Init_cs__assess_marshal_module(void) {
|
|
38
|
-
|
|
37
|
+
// Contrast::Agent::Assess::Tracker::PROPERTIES_HASH
|
|
38
|
+
VALUE tracker = rb_define_class_under(assess, "Tracker", rb_cObject);
|
|
39
|
+
properties_hash = rb_const_get(tracker, rb_intern("PROPERTIES_HASH"));
|
|
40
|
+
marshal_module =
|
|
41
|
+
rb_define_class_under(core_assess, "MarshalPropagator", rb_cObject);
|
|
39
42
|
rb_sym_assess_load_trigger_check = rb_intern("cs__load_trigger_check");
|
|
40
43
|
|
|
41
44
|
contrast_register_singleton_prepend_patch(
|
|
@@ -5,44 +5,43 @@
|
|
|
5
5
|
#include "../cs__common/cs__common.h"
|
|
6
6
|
#include <ruby.h>
|
|
7
7
|
|
|
8
|
-
static VALUE
|
|
8
|
+
static VALUE contrast_assess_string_freeze(const int argc, VALUE *argv,
|
|
9
9
|
const VALUE obj) {
|
|
10
|
-
VALUE dup, tracked;
|
|
11
10
|
if (!OBJ_FROZEN(obj)) {
|
|
12
|
-
|
|
13
|
-
if (RTEST(tracked)) {
|
|
14
|
-
/*
|
|
15
|
-
* If the object is not frozen and the object is tracked, we cheat.
|
|
16
|
-
* We dup and then freeze to replicate the behavior of str_uminus in
|
|
17
|
-
* string.c, but we ignore any other monkey patches on String#-@
|
|
18
|
-
*/
|
|
19
|
-
dup = rb_funcall(obj, rb_sym_dup, 0);
|
|
20
|
-
rb_funcall(obj, rb_intern("cs__transfer_properties"), 1, dup);
|
|
21
|
-
rb_funcall(dup, rb_sym_freeze, 0);
|
|
22
|
-
return dup;
|
|
23
|
-
}
|
|
11
|
+
rb_funcall(properties_hash, rb_sym_pre_freeze, 1, obj);
|
|
24
12
|
}
|
|
25
|
-
|
|
26
|
-
return rb_funcall(obj, rb_sym_assess_string_uminus, 0);
|
|
13
|
+
return rb_funcall(obj, rb_sym_assess_string_freeze, 0);
|
|
27
14
|
}
|
|
28
15
|
|
|
29
|
-
static VALUE
|
|
16
|
+
static VALUE contrast_assess_string_uminus(const int argc, VALUE *argv,
|
|
30
17
|
const VALUE obj) {
|
|
31
18
|
if (!OBJ_FROZEN(obj)) {
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
/* We're doing something intentionally different here. Ruby, for -@,
|
|
20
|
+
* attempts to de-duplicate the String and use an "interned" copy of
|
|
21
|
+
* the String. We cannot allow that to happen for a couple reasons:
|
|
22
|
+
* - prior to Ruby 2.7, this would cause us to track ALL instances of
|
|
23
|
+
* that interned copy.
|
|
24
|
+
* - 2.7 and later, this action is actually missed because of a change
|
|
25
|
+
* to the str_uminus method in Ruby, which dups the String in a way
|
|
26
|
+
* that we cannot see.
|
|
27
|
+
* B/c we cannot track this in 2.7, rather than having a version check
|
|
28
|
+
* and two approaches, we'll instead directly call the #freeze method,
|
|
29
|
+
* so the end result is that this String itself is frozen and never
|
|
30
|
+
* deduplicated.
|
|
31
|
+
*/
|
|
32
|
+
return contrast_assess_string_freeze(argc, argv, obj);
|
|
34
33
|
}
|
|
35
|
-
|
|
34
|
+
/* in all other cases, preserve monkey patching and c call */
|
|
35
|
+
return rb_funcall(obj, rb_sym_assess_string_uminus, 0);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
void Init_cs__assess_string(void) {
|
|
39
39
|
rb_sym_dup = rb_intern("dup");
|
|
40
40
|
rb_sym_freeze = rb_intern("freeze");
|
|
41
|
-
|
|
42
|
-
// Contrast::Agent::Assess::
|
|
43
|
-
VALUE
|
|
44
|
-
|
|
45
|
-
properties_hash = rb_const_get(finalize, rb_intern("PROPERTIES_HASH"));
|
|
41
|
+
rb_sym_pre_freeze = rb_intern("pre_freeze");
|
|
42
|
+
// Contrast::Agent::Assess::Tracker::PROPERTIES_HASH
|
|
43
|
+
VALUE tracker = rb_define_class_under(assess, "Tracker", rb_cObject);
|
|
44
|
+
properties_hash = rb_const_get(tracker, rb_intern("PROPERTIES_HASH"));
|
|
46
45
|
|
|
47
46
|
rb_sym_assess_string_uminus =
|
|
48
47
|
contrast_register_patch("String", "-@", &contrast_assess_string_uminus);
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
static VALUE rb_sym_assess_string_uminus;
|
|
4
4
|
static VALUE rb_sym_assess_string_freeze;
|
|
5
|
-
// Contrast::Agent::Assess::
|
|
5
|
+
// Contrast::Agent::Assess::Tracker::PROPERTIES_HASH
|
|
6
6
|
static VALUE properties_hash;
|
|
7
7
|
static VALUE rb_sym_dup;
|
|
8
8
|
static VALUE rb_sym_freeze;
|
|
9
|
+
static VALUE rb_sym_pre_freeze;
|
|
10
|
+
static VALUE properties_hash;
|
|
9
11
|
|
|
10
12
|
/*
|
|
11
13
|
* The String#-@ method calls to the str_uminus method in String.C. This method
|
data/ext/cs__common/cs__common.c
CHANGED
|
@@ -18,7 +18,7 @@ VALUE rb_sym_in_scope;
|
|
|
18
18
|
VALUE rb_sym_skip_contrast_analysis;
|
|
19
19
|
VALUE rb_sym_skip_assess_analysis;
|
|
20
20
|
VALUE rb_sym_method;
|
|
21
|
-
VALUE
|
|
21
|
+
VALUE rb_sym_hash_get, rb_sym_hash_set, rb_sym_hash_tracked;
|
|
22
22
|
/* end globals */
|
|
23
23
|
|
|
24
24
|
void patch_via_funchook(void *original_function, void *hook_function) {
|
|
@@ -144,7 +144,9 @@ void Init_cs__common(void) {
|
|
|
144
144
|
rb_sym_skip_contrast_analysis = rb_intern("skip_contrast_analysis?");
|
|
145
145
|
rb_sym_skip_assess_analysis = rb_intern("skip_assess_analysis?");
|
|
146
146
|
rb_sym_method = rb_intern("__method__");
|
|
147
|
-
|
|
147
|
+
rb_sym_hash_get = rb_intern("[]");
|
|
148
|
+
rb_sym_hash_set = rb_intern("[]=");
|
|
149
|
+
rb_sym_hash_tracked = rb_intern("tracked?");
|
|
148
150
|
|
|
149
151
|
/* Used for returning unbound C functions */
|
|
150
152
|
rb_sym_register_c_patch = rb_intern("register_c_patch");
|
data/ext/cs__common/cs__common.h
CHANGED
|
@@ -23,7 +23,7 @@ extern VALUE rb_sym_in_scope;
|
|
|
23
23
|
extern VALUE rb_sym_skip_contrast_analysis;
|
|
24
24
|
extern VALUE rb_sym_skip_assess_analysis;
|
|
25
25
|
extern VALUE rb_sym_method;
|
|
26
|
-
extern VALUE
|
|
26
|
+
extern VALUE rb_sym_hash_get, rb_sym_hash_set, rb_sym_hash_tracked;
|
|
27
27
|
|
|
28
28
|
static VALUE patcher;
|
|
29
29
|
static VALUE rb_sym_instance_method;
|
data/lib/contrast.rb
CHANGED
data/lib/contrast/agent.rb
CHANGED
|
@@ -23,7 +23,6 @@ require 'contrast/extension/protect'
|
|
|
23
23
|
require 'contrast/extension/protect/kernel'
|
|
24
24
|
|
|
25
25
|
require 'contrast/utils/object_share'
|
|
26
|
-
require 'contrast/utils/boolean_util'
|
|
27
26
|
require 'contrast/utils/string_utils'
|
|
28
27
|
require 'contrast/utils/io_util'
|
|
29
28
|
require 'contrast/utils/os'
|
|
@@ -88,18 +87,11 @@ require 'contrast/agent/assess'
|
|
|
88
87
|
# protect rules
|
|
89
88
|
require 'contrast/agent/protect/rule'
|
|
90
89
|
|
|
91
|
-
# application libraries
|
|
92
|
-
require 'contrast/
|
|
90
|
+
# application libraries and technologies
|
|
91
|
+
require 'contrast/agent/inventory'
|
|
93
92
|
|
|
94
93
|
# rack event monitoring
|
|
95
94
|
require 'contrast/agent/middleware'
|
|
96
95
|
|
|
97
|
-
#
|
|
98
|
-
|
|
99
|
-
# Contrast::Framework::Manager.before_load_patches!
|
|
100
|
-
if defined?(::Rails)
|
|
101
|
-
require 'contrast/framework/rails/patch/support'
|
|
102
|
-
require 'contrast/framework/rails/patch/rails_application_configuration'
|
|
103
|
-
Contrast::Framework::Rails::Patch::RailsApplicationConfiguration.instrument
|
|
104
|
-
require 'contrast/agent/railtie' if ::Rails::VERSION::MAJOR.to_i >= 3
|
|
105
|
-
end
|
|
96
|
+
# Install the patches we need before the application has a chance to initialize
|
|
97
|
+
Contrast::Agent.framework_manager.before_load_patches!
|
|
@@ -8,6 +8,7 @@ module Contrast
|
|
|
8
8
|
# class under this namespace should be required here, providing a single
|
|
9
9
|
# point of require for this functionality.
|
|
10
10
|
module Assess
|
|
11
|
+
require 'contrast/agent/assess/tracker'
|
|
11
12
|
require 'contrast/agent/module_data'
|
|
12
13
|
require 'contrast/agent/rewriter'
|
|
13
14
|
require 'contrast/agent/assess/policy/preshift'
|
|
@@ -16,10 +16,32 @@ module Contrast
|
|
|
16
16
|
# This class holds the data about an event in the application
|
|
17
17
|
# We'll use it to build an event that TeamServer can consume if
|
|
18
18
|
# the object to which this event belongs ends in a trigger.
|
|
19
|
+
#
|
|
20
|
+
# @attr_reader event_id [Integer] the atomic id of this event
|
|
21
|
+
# @attr_reader policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
|
|
22
|
+
# the node that governs this event.
|
|
23
|
+
# @attr_reader stack_trace [Array<String>] the execution stack at the
|
|
24
|
+
# time the method for this event was invoked
|
|
25
|
+
# @attr_reader time [Integer] the time, in epoch ms, when this event was
|
|
26
|
+
# created
|
|
27
|
+
# @attr_reader thread [Integer] the object id of the thread on which this
|
|
28
|
+
# event was generated
|
|
29
|
+
# @attr_reader object [String] the safe representation of the Object on
|
|
30
|
+
# which the method was invoked
|
|
31
|
+
# @attr_reader ret [String] the safe representation of the Return of the
|
|
32
|
+
# invoked method
|
|
33
|
+
# @attr_reader args [Array<Object>] the safe representation of the
|
|
34
|
+
# Arguments with which the method was invoked
|
|
19
35
|
class ContrastEvent
|
|
20
36
|
include Contrast::Utils::PreventSerialization
|
|
21
37
|
|
|
22
38
|
class << self
|
|
39
|
+
# Given an array of arguments, copy them into a safe, meaning String,
|
|
40
|
+
# format that we can use to send to SR and TS for rendering.
|
|
41
|
+
#
|
|
42
|
+
# @param args [Array<Object>] the arguments to translate
|
|
43
|
+
# @return [Array<String>] the String forms of those Objects, as
|
|
44
|
+
# determined by Contrast::Utils::ClassUtil.to_contrast_string
|
|
23
45
|
def safe_args_representation args
|
|
24
46
|
return nil unless args
|
|
25
47
|
return Contrast::Utils::ObjectShare::EMPTY_ARRAY if args.empty?
|
|
@@ -36,32 +58,31 @@ module Contrast
|
|
|
36
58
|
rep
|
|
37
59
|
end
|
|
38
60
|
|
|
39
|
-
def safe_arg_hash_representation hash
|
|
40
|
-
# since this is the named hash for arguments, only the value is
|
|
41
|
-
# suspect here
|
|
42
|
-
hash.transform_values { |v| Contrast::Utils::ClassUtil.to_contrast_string(v) }
|
|
43
|
-
end
|
|
44
|
-
|
|
45
61
|
# if given an object that can be duped, duplicate it. otherwise just
|
|
46
62
|
# return the original object. swallow all exceptions from
|
|
47
63
|
# non-duplicable things.
|
|
48
64
|
#
|
|
49
65
|
# we can't just check respond_to? though b/c dup exists on the
|
|
50
66
|
# base Object class
|
|
67
|
+
#
|
|
68
|
+
# @param original [Object, nil] the thing to duplicate
|
|
69
|
+
# @return [Object, nil] a copy of that thing
|
|
51
70
|
def safe_dup original
|
|
52
71
|
return nil unless original
|
|
53
72
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
73
|
+
Contrast::Agent::Assess::Tracker.duplicate(original)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def safe_arg_hash_representation hash
|
|
79
|
+
# since this is the named hash for arguments, only the value is
|
|
80
|
+
# suspect here
|
|
81
|
+
hash.transform_values { |v| Contrast::Utils::ClassUtil.to_contrast_string(v) }
|
|
61
82
|
end
|
|
62
83
|
end
|
|
63
84
|
|
|
64
|
-
attr_reader :event_id, :
|
|
85
|
+
attr_reader :event_id, :policy_node, :stack_trace, :time, :thread, :object, :ret, :args
|
|
65
86
|
|
|
66
87
|
# We need this to track the parent id's of events to build up a flow
|
|
67
88
|
# chart of the finding
|
|
@@ -76,6 +97,13 @@ module Contrast
|
|
|
76
97
|
end
|
|
77
98
|
end
|
|
78
99
|
|
|
100
|
+
# @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
|
|
101
|
+
# the node that governs this event.
|
|
102
|
+
# @param tagged [Object] the Target to which this event pertains.
|
|
103
|
+
# @param object [Object] the Object on which the method was invoked
|
|
104
|
+
# @param ret [Object] the Return of the invoked method
|
|
105
|
+
# @param args [Array<Object>] the Arguments with which the method
|
|
106
|
+
# was invoked
|
|
79
107
|
def initialize policy_node, tagged, object, ret, args
|
|
80
108
|
@policy_node = policy_node
|
|
81
109
|
# so long as this event is built in a factory, we know Contrast Code
|
|
@@ -86,28 +114,110 @@ module Contrast
|
|
|
86
114
|
|
|
87
115
|
# These methods rely on the above being set. Don't move them!
|
|
88
116
|
@event_id = Contrast::Agent::Assess::ContrastEvent.next_atomic_id
|
|
89
|
-
|
|
90
|
-
snapshot(tagged, object, ret, args)
|
|
117
|
+
find_parent_events!(policy_node, object, ret, args)
|
|
118
|
+
snapshot!(tagged, object, ret, args)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def parent_events
|
|
122
|
+
@_parent_events ||= []
|
|
91
123
|
end
|
|
92
124
|
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
125
|
+
# We have to do a little work to figure out what our TS appropriate
|
|
126
|
+
# target is. To break this down, the logic is as follows:
|
|
127
|
+
# 1) If my policy_node has a target, work on targets. Else, work on sources.
|
|
128
|
+
# Per TS law, each policy_node must have at least a source or a target.
|
|
129
|
+
# The only type of policy_node w/o targets is a Trigger, but that may
|
|
130
|
+
# change.
|
|
131
|
+
# 2) If I have a highlight, it means that I have a P target that is
|
|
132
|
+
# not in integer form (it was a named / keyword type for which I had
|
|
133
|
+
# to find the index). I need to address this so that TS can process
|
|
134
|
+
# it.
|
|
135
|
+
# 3) I'll set the event's source and target to TS values.
|
|
136
|
+
# 4) Return the highlight or the first source/target as the taint
|
|
137
|
+
# target.
|
|
138
|
+
def determine_taint_target event_dtm
|
|
139
|
+
if @policy_node&.targets&.any?
|
|
140
|
+
event_dtm.source = @policy_node.source_string if @policy_node.source_string
|
|
141
|
+
event_dtm.target = @highlight ? "P#{ @highlight }" : @policy_node.target_string
|
|
142
|
+
@highlight || @policy_node.targets[0]
|
|
143
|
+
elsif policy_node&.sources&.any?
|
|
144
|
+
event_dtm.source = @highlight ? "P#{ @highlight }" : @policy_node.source_string
|
|
145
|
+
event_dtm.target = @policy_node.target_string if @policy_node.target_string
|
|
146
|
+
@highlight || @policy_node.sources[0]
|
|
98
147
|
end
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Convert this event into a DTM that TeamServer can consume
|
|
151
|
+
def to_dtm_event
|
|
152
|
+
Contrast::Api::Dtm::TraceEvent.build(self)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private
|
|
156
|
+
|
|
157
|
+
# Parent events are the events of all the sources of this event which
|
|
158
|
+
# were tracked prior to this event occurring. Depending on which, if
|
|
159
|
+
# any of the sources were tracked, there may be more than one parent.
|
|
160
|
+
#
|
|
161
|
+
# All events except for [Contrast::Agent::Assess::Events::SourceEvent]
|
|
162
|
+
# will have at least one parent.
|
|
163
|
+
#
|
|
164
|
+
# We set those events to this event's instance variables.
|
|
165
|
+
#
|
|
166
|
+
# @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode]
|
|
167
|
+
# the node that governs this event.
|
|
168
|
+
# @param object [Object] the Object on which the method was invoked
|
|
169
|
+
# @param ret [Object] the Return of the invoked method
|
|
170
|
+
# @param args [Array<Object>] the Arguments with which the method
|
|
171
|
+
# was invoked
|
|
172
|
+
def find_parent_events! policy_node, object, ret, args
|
|
173
|
+
policy_node.sources.each do |source_marker|
|
|
174
|
+
source = value_of_source(source_marker, object, ret, args)
|
|
175
|
+
next unless source
|
|
176
|
+
|
|
177
|
+
event = Contrast::Agent::Assess::Tracker.properties(source)&.event
|
|
178
|
+
parent_events << event if event
|
|
104
179
|
end
|
|
105
|
-
|
|
106
|
-
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# @param source [String] the marker for the source type
|
|
183
|
+
# @param object [Object] the Object on which the method was invoked
|
|
184
|
+
# @param ret [Object] the Return of the invoked method
|
|
185
|
+
# @param args [Array<Object>] the Arguments with which the method
|
|
186
|
+
# was invoked
|
|
187
|
+
# @return [Object,nil] the literal value of the source indicated by the
|
|
188
|
+
# given marker
|
|
189
|
+
def value_of_source source, object, ret, args
|
|
190
|
+
case source
|
|
191
|
+
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
|
192
|
+
object
|
|
193
|
+
when Contrast::Utils::ObjectShare::RETURN_KEY
|
|
194
|
+
ret
|
|
195
|
+
else
|
|
196
|
+
if source.is_a?(Integer)
|
|
197
|
+
args[source]
|
|
198
|
+
else
|
|
199
|
+
args.each do |search|
|
|
200
|
+
next unless search.is_a?(Hash)
|
|
201
|
+
|
|
202
|
+
s = search[source]
|
|
203
|
+
return s if s
|
|
204
|
+
end
|
|
205
|
+
end
|
|
107
206
|
end
|
|
108
207
|
end
|
|
109
208
|
|
|
110
|
-
|
|
209
|
+
# Everything* is mutable in Ruby. As such, to ensure we can accurately
|
|
210
|
+
# report the application state at the time of this method's invocation,
|
|
211
|
+
# we have to snapshot the given values, making safe representations of
|
|
212
|
+
# them for our later use. We set those safe values to this event's
|
|
213
|
+
# instance variables.
|
|
214
|
+
#
|
|
215
|
+
# @param tagged [Object] the Target to which this event pertains.
|
|
216
|
+
# @param object [Object] the Object on which the method was invoked
|
|
217
|
+
# @param ret [Object] the Return of the invoked method
|
|
218
|
+
# @param args [Array<Object>] the Arguments with which the method
|
|
219
|
+
# was invoked
|
|
220
|
+
def snapshot! tagged, object, ret, args
|
|
111
221
|
target = @policy_node.target
|
|
112
222
|
case target
|
|
113
223
|
# If the target is nil, this rule was violated simply by a method
|
|
@@ -141,6 +251,10 @@ module Contrast
|
|
|
141
251
|
# I know we're creating an extra string here since we replace the safe
|
|
142
252
|
# one w/ a dup, but good enough for now. Trying not to make this too
|
|
143
253
|
# complicated. - HM 8/8/19
|
|
254
|
+
#
|
|
255
|
+
# @param target [String,Integer] the marker for the target index
|
|
256
|
+
# @param tagged [Object] the actual Object that we're acting on which
|
|
257
|
+
# has tags
|
|
144
258
|
def save_target_arg target, tagged
|
|
145
259
|
return if @args.cs__frozen?
|
|
146
260
|
|
|
@@ -158,56 +272,6 @@ module Contrast
|
|
|
158
272
|
break
|
|
159
273
|
end
|
|
160
274
|
end
|
|
161
|
-
|
|
162
|
-
# We have to do a little work to figure out what our TS appropriate
|
|
163
|
-
# target is. To break this down, the logic is as follows:
|
|
164
|
-
# 1) If my policy_node has a target, work on targets. Else, work on sources.
|
|
165
|
-
# Per TS law, each policy_node must have at least a source or a target.
|
|
166
|
-
# The only type of policy_node w/o targets is a Trigger, but that may
|
|
167
|
-
# change.
|
|
168
|
-
# 2) If I have a highlight, it means that I have a P target that is
|
|
169
|
-
# not in integer form (it was a named / keyword type for which I had
|
|
170
|
-
# to find the index). I need to address this so that TS can process
|
|
171
|
-
# it.
|
|
172
|
-
# 3) I'll set the event's source and target to TS values.
|
|
173
|
-
# 4) Return the highlight or the first source/target as the taint
|
|
174
|
-
# target.
|
|
175
|
-
def determine_taint_target event_dtm
|
|
176
|
-
if @policy_node&.targets&.any?
|
|
177
|
-
event_dtm.source = @policy_node.source_string if @policy_node.source_string
|
|
178
|
-
event_dtm.target = @highlight ? "P#{ @highlight }" : @policy_node.target_string
|
|
179
|
-
@highlight || @policy_node.targets[0]
|
|
180
|
-
elsif policy_node&.sources&.any?
|
|
181
|
-
event_dtm.source = @highlight ? "P#{ @highlight }" : @policy_node.source_string
|
|
182
|
-
event_dtm.target = @policy_node.target_string if @policy_node.target_string
|
|
183
|
-
@highlight || @policy_node.sources[0]
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def value_of_source source, object, ret, args
|
|
188
|
-
case source
|
|
189
|
-
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
|
190
|
-
object
|
|
191
|
-
when Contrast::Utils::ObjectShare::RETURN_KEY
|
|
192
|
-
ret
|
|
193
|
-
else
|
|
194
|
-
if source.is_a?(Integer)
|
|
195
|
-
args[source]
|
|
196
|
-
else
|
|
197
|
-
args.each do |search|
|
|
198
|
-
next unless search.is_a?(Hash)
|
|
199
|
-
|
|
200
|
-
s = search[source]
|
|
201
|
-
return s if s
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
# Convert this event into a DTM that TeamServer can consume
|
|
208
|
-
def to_dtm_event
|
|
209
|
-
Contrast::Api::Dtm::TraceEvent.build(self)
|
|
210
|
-
end
|
|
211
275
|
end
|
|
212
276
|
end
|
|
213
277
|
end
|