vivarium 0.3.2 → 0.4.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/README.md +16 -0
- data/examples/drop_demo.rb +7 -9
- data/examples/env_access_external_demo.rb +52 -0
- data/examples/env_access_ruby_demo.rb +52 -0
- data/lib/vivarium/correlator.rb +1 -19
- data/lib/vivarium/tree_renderer.rb +28 -49
- data/lib/vivarium/version.rb +1 -1
- data/lib/vivarium.rb +218 -44
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be07034ab56d73e0aaa4fe9e124d67888ae2006cc5f6cb632cf4b93b20855422
|
|
4
|
+
data.tar.gz: 5f95cdaa111a56415f4fed08da0c638a87f5c08f01e51db2b5b818c04c256bc4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 49e166adbaca6231263d10255779ce4ff16a98ba9905a4afc48da012382d21fe1635b4f3bfff3990125bcb9718f7e1e5f3c5168a3a7f39b7fd8981be312bc3a4
|
|
7
|
+
data.tar.gz: a85783ba20a6eb866bd8215f55a4edb6890bef1b0b3e3e7af6d11bfcc0fda77adbfa2e7ea465e201c424d6fc9f883bcb20d7846e3c051c294560151ac0078d30
|
data/README.md
CHANGED
|
@@ -139,6 +139,22 @@ bundle exec ruby examples/privilege_event_demo.rb
|
|
|
139
139
|
|
|
140
140
|
This demo attempts setuid/setgid changes, sensitive file access, and `sudo` exec to trigger privilege-related events such as `setid_change`, `capable_check`, and `bprm_creds`.
|
|
141
141
|
|
|
142
|
+
8) Ruby internal ENV access demo client:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
bundle exec ruby examples/env_access_ruby_demo.rb
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
This demo triggers Ruby-side ENV methods (`[]`, `fetch`, `key?`, `[]=`, `store`, `delete`, `clear`, `replace`) and is intended to produce SPAN events.
|
|
149
|
+
|
|
150
|
+
9) External command ENV libc access demo client:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
bundle exec ruby examples/env_access_external_demo.rb
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This demo spawns an external process that directly calls libc `getenv`, `setenv`, `unsetenv`, `putenv`, and `clearenv`, intended to trigger `env_caccess` eBPF events.
|
|
157
|
+
|
|
142
158
|
You can also start top-level observation without a block (it keeps observing until process exit):
|
|
143
159
|
|
|
144
160
|
```ruby
|
data/examples/drop_demo.rb
CHANGED
|
@@ -14,16 +14,15 @@ require "vivarium"
|
|
|
14
14
|
require "vivarium/correlator"
|
|
15
15
|
require "vivarium/tree_renderer"
|
|
16
16
|
require "vivarium/display_filter"
|
|
17
|
-
require "vivarium_usdt"
|
|
18
17
|
|
|
19
|
-
t0
|
|
20
|
-
pid
|
|
21
|
-
tid
|
|
22
|
-
method_id = 0x0001_0001
|
|
18
|
+
t0 = 1_000_000_000 # base ktime_ns
|
|
19
|
+
pid = Process.pid
|
|
20
|
+
tid = Process.pid
|
|
23
21
|
|
|
24
|
-
# span_start payload:
|
|
25
|
-
span_start_payload =
|
|
26
|
-
|
|
22
|
+
# span_start payload: method_name (128B) + file_name (120B) + lineno (8B)
|
|
23
|
+
span_start_payload = "MyClass#my_method".ljust(Vivarium::SPAN_METHOD_SIZE, "\x00") +
|
|
24
|
+
"drop_demo.rb".ljust(Vivarium::SPAN_FILE_SIZE, "\x00") +
|
|
25
|
+
[10].pack("q<")
|
|
27
26
|
|
|
28
27
|
events = [
|
|
29
28
|
Vivarium::Correlator::RawEvent.new(
|
|
@@ -67,7 +66,6 @@ events = [
|
|
|
67
66
|
|
|
68
67
|
Vivarium::TreeRenderer.new(
|
|
69
68
|
events: events,
|
|
70
|
-
method_table: { method_id => "MyClass#my_method" },
|
|
71
69
|
observer_pid: pid,
|
|
72
70
|
main_tid: tid,
|
|
73
71
|
session_start_iso: "2026-06-02T00:00:00.000Z",
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "rbconfig"
|
|
5
|
+
require "vivarium"
|
|
6
|
+
|
|
7
|
+
# Usage:
|
|
8
|
+
# 1) In another shell (root): sudo bundle exec vivariumd
|
|
9
|
+
# 2) Run this script: bundle exec ruby examples/env_access_external_demo.rb
|
|
10
|
+
#
|
|
11
|
+
# This demo launches an external Ruby process and forces direct libc calls to
|
|
12
|
+
# getenv/setenv/unsetenv/putenv/clearenv through Fiddle.
|
|
13
|
+
# These should appear as eBPF events with event_name=env_caccess.
|
|
14
|
+
|
|
15
|
+
FILTER = {
|
|
16
|
+
include_events: %w[env_caccess proc_fork proc_exec]
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
CHILD_CODE = <<~RUBY
|
|
20
|
+
require "fiddle"
|
|
21
|
+
|
|
22
|
+
libc = begin
|
|
23
|
+
Fiddle.dlopen("libc.so.6")
|
|
24
|
+
rescue Fiddle::DLError
|
|
25
|
+
Fiddle.dlopen(nil)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
getenv = Fiddle::Function.new(libc["getenv"], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
|
|
29
|
+
setenv = Fiddle::Function.new(libc["setenv"], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT], Fiddle::TYPE_INT)
|
|
30
|
+
unsetenv = Fiddle::Function.new(libc["unsetenv"], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
|
31
|
+
putenv = Fiddle::Function.new(libc["putenv"], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
|
32
|
+
clearenv = Fiddle::Function.new(libc["clearenv"], [], Fiddle::TYPE_INT)
|
|
33
|
+
|
|
34
|
+
key = "VIVARIUM_ENV_EXT_DEMO"
|
|
35
|
+
putenv_buf = "VIVARIUM_ENV_EXT_PUT=from_putenv"
|
|
36
|
+
|
|
37
|
+
getenv.call("HOME")
|
|
38
|
+
setenv.call(key, "from_setenv", 1)
|
|
39
|
+
getenv.call(key)
|
|
40
|
+
putenv.call(putenv_buf)
|
|
41
|
+
unsetenv.call(key)
|
|
42
|
+
clearenv.call
|
|
43
|
+
RUBY
|
|
44
|
+
|
|
45
|
+
Vivarium.observe(filter: FILTER) do
|
|
46
|
+
puts "[env-external-demo] spawning external child"
|
|
47
|
+
pid = Process.spawn(RbConfig.ruby, "-e", CHILD_CODE)
|
|
48
|
+
Process.wait(pid)
|
|
49
|
+
puts "[env-external-demo] child exit status=#{Process.last_status.exitstatus}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
puts "[env-external-demo] done"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "vivarium"
|
|
5
|
+
|
|
6
|
+
# Usage:
|
|
7
|
+
# 1) In another shell (root): sudo bundle exec vivariumd
|
|
8
|
+
# 2) Run this script: bundle exec ruby examples/env_access_ruby_demo.rb
|
|
9
|
+
#
|
|
10
|
+
# This demo intentionally triggers Ruby-side ENV access methods so they are
|
|
11
|
+
# observed through TracePoint -> SPAN (USDT) path.
|
|
12
|
+
|
|
13
|
+
FILTER = {
|
|
14
|
+
include_events: %w[span_start span_stop env_caccess]
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def safe_fetch(key)
|
|
18
|
+
ENV.fetch(key)
|
|
19
|
+
rescue KeyError
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def demo_env_reads
|
|
24
|
+
ENV["HOME"]
|
|
25
|
+
safe_fetch("PATH")
|
|
26
|
+
ENV.key?("SHELL")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def demo_env_writes
|
|
30
|
+
ENV["VIVARIUM_ENV_DEMO_A"] = "1"
|
|
31
|
+
ENV.store("VIVARIUM_ENV_DEMO_B", "2")
|
|
32
|
+
ENV.delete("VIVARIUM_ENV_DEMO_A")
|
|
33
|
+
ENV.replace(ENV.to_h.merge("VIVARIUM_ENV_DEMO_C" => "3"))
|
|
34
|
+
ENV.delete("VIVARIUM_ENV_DEMO_B")
|
|
35
|
+
ENV.delete("VIVARIUM_ENV_DEMO_C")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Vivarium.observe(filter: FILTER) do
|
|
39
|
+
original_env = ENV.to_h
|
|
40
|
+
|
|
41
|
+
puts "[env-ruby-demo] read methods"
|
|
42
|
+
demo_env_reads
|
|
43
|
+
|
|
44
|
+
puts "[env-ruby-demo] write methods"
|
|
45
|
+
demo_env_writes
|
|
46
|
+
|
|
47
|
+
puts "[env-ruby-demo] clear"
|
|
48
|
+
ENV.clear
|
|
49
|
+
ENV.replace(original_env)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
puts "[env-ruby-demo] done"
|
data/lib/vivarium/correlator.rb
CHANGED
|
@@ -23,17 +23,15 @@ module Vivarium
|
|
|
23
23
|
|
|
24
24
|
POLL_TIMEOUT_MS = 200
|
|
25
25
|
|
|
26
|
-
def initialize(pin_dir:, observer_pid:, main_tid:,
|
|
26
|
+
def initialize(pin_dir:, observer_pid:, main_tid:, filter: nil, dest: $stdout)
|
|
27
27
|
@pin_dir = pin_dir
|
|
28
28
|
@observer_pid = observer_pid
|
|
29
29
|
@main_tid = main_tid
|
|
30
|
-
@method_id_queue = method_id_queue
|
|
31
30
|
@filter = filter
|
|
32
31
|
@dest = dest
|
|
33
32
|
|
|
34
33
|
@events = []
|
|
35
34
|
@events_mutex = Mutex.new
|
|
36
|
-
@method_table = {}
|
|
37
35
|
@stop_flag = false
|
|
38
36
|
@started = false
|
|
39
37
|
|
|
@@ -66,15 +64,12 @@ module Vivarium
|
|
|
66
64
|
@session_stop_ktime = Vivarium.monotonic_ktime_ns
|
|
67
65
|
|
|
68
66
|
3.times { safe_poll(50) }
|
|
69
|
-
drain_method_id_queue
|
|
70
67
|
|
|
71
68
|
events_snapshot = @events_mutex.synchronize { @events.dup }
|
|
72
|
-
method_table_snapshot = @method_table.dup
|
|
73
69
|
@stopped = true
|
|
74
70
|
|
|
75
71
|
TreeRenderer.new(
|
|
76
72
|
events: events_snapshot,
|
|
77
|
-
method_table: method_table_snapshot,
|
|
78
73
|
observer_pid: @observer_pid,
|
|
79
74
|
main_tid: @main_tid,
|
|
80
75
|
session_start_iso: @session_start_iso,
|
|
@@ -91,7 +86,6 @@ module Vivarium
|
|
|
91
86
|
def run
|
|
92
87
|
until @stop_flag
|
|
93
88
|
safe_poll(POLL_TIMEOUT_MS)
|
|
94
|
-
drain_method_id_queue
|
|
95
89
|
end
|
|
96
90
|
end
|
|
97
91
|
|
|
@@ -126,17 +120,5 @@ module Vivarium
|
|
|
126
120
|
warn "[vivarium correlator] capture error: #{e.class}: #{e.message}"
|
|
127
121
|
end
|
|
128
122
|
|
|
129
|
-
def drain_method_id_queue
|
|
130
|
-
loop do
|
|
131
|
-
msg = begin
|
|
132
|
-
@method_id_queue.pop(true)
|
|
133
|
-
rescue ThreadError
|
|
134
|
-
return
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
method_id, signature = msg
|
|
138
|
-
@method_table[method_id] = signature
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
123
|
end
|
|
142
124
|
end
|
|
@@ -28,7 +28,7 @@ module Vivarium
|
|
|
28
28
|
UNRESOLVED_METHOD_PREFIX = "<method_id="
|
|
29
29
|
|
|
30
30
|
Span = Struct.new(
|
|
31
|
-
:tid, :
|
|
31
|
+
:tid, :method_name, :file_name, :lineno, :start_ktime, :stop_ktime, :exit_kind,
|
|
32
32
|
:events, :descendant_pids, :synthetic, :raised,
|
|
33
33
|
keyword_init: true
|
|
34
34
|
) do
|
|
@@ -52,11 +52,10 @@ module Vivarium
|
|
|
52
52
|
EventNode = Struct.new(:kind, :name, :target, :offset_ns, :child_proc, keyword_init: true)
|
|
53
53
|
ProcNode = Struct.new(:pid, :comm, :parent_pid, :children, keyword_init: true)
|
|
54
54
|
|
|
55
|
-
def initialize(events:,
|
|
55
|
+
def initialize(events:, observer_pid:, main_tid:,
|
|
56
56
|
session_start_iso:, session_start_ktime:,
|
|
57
57
|
session_stop_iso:, session_stop_ktime:, filter: nil, dest:)
|
|
58
58
|
@events = events
|
|
59
|
-
@method_table = method_table
|
|
60
59
|
@observer_pid = observer_pid
|
|
61
60
|
@main_tid = main_tid
|
|
62
61
|
@session_start_iso = session_start_iso
|
|
@@ -68,7 +67,6 @@ module Vivarium
|
|
|
68
67
|
|
|
69
68
|
@pid_comm = { observer_pid => "ruby" }
|
|
70
69
|
@pid_parent = {}
|
|
71
|
-
@unresolved_method_ids = []
|
|
72
70
|
end
|
|
73
71
|
|
|
74
72
|
def render
|
|
@@ -101,11 +99,11 @@ module Vivarium
|
|
|
101
99
|
events.each do |ev|
|
|
102
100
|
case ev.event_name
|
|
103
101
|
when "span_start"
|
|
104
|
-
|
|
102
|
+
method_name, file_name, lno = read_span_payload(ev.payload)
|
|
105
103
|
span = Span.new(
|
|
106
104
|
tid: ev.tid,
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
method_name: method_name,
|
|
106
|
+
file_name: file_name,
|
|
109
107
|
lineno: lno,
|
|
110
108
|
start_ktime: ev.ktime_ns,
|
|
111
109
|
stop_ktime: nil,
|
|
@@ -195,8 +193,8 @@ module Vivarium
|
|
|
195
193
|
def synthetic_span(start_ktime, stop_ktime)
|
|
196
194
|
Span.new(
|
|
197
195
|
tid: @main_tid,
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
method_name: nil,
|
|
197
|
+
file_name: nil,
|
|
200
198
|
lineno: nil,
|
|
201
199
|
start_ktime: start_ktime,
|
|
202
200
|
stop_ktime: stop_ktime,
|
|
@@ -262,9 +260,6 @@ module Vivarium
|
|
|
262
260
|
end
|
|
263
261
|
|
|
264
262
|
def print_warnings
|
|
265
|
-
@unresolved_method_ids.uniq.each do |mid|
|
|
266
|
-
@dest.puts format("# warning method_id=0x%016X unresolved at render time", mid & 0xFFFF_FFFF_FFFF_FFFF)
|
|
267
|
-
end
|
|
268
263
|
end
|
|
269
264
|
|
|
270
265
|
def print_observer_proc(spans)
|
|
@@ -301,25 +296,17 @@ module Vivarium
|
|
|
301
296
|
|
|
302
297
|
def span_file_info(span)
|
|
303
298
|
return "" if span.synthetic
|
|
304
|
-
return ""
|
|
305
|
-
|
|
306
|
-
file_name = Vivarium::Usdt.get_file_name(span.file_id)
|
|
307
|
-
return "" unless file_name
|
|
299
|
+
return "" if span.file_name.nil? || span.file_name.empty?
|
|
308
300
|
|
|
309
301
|
lno = span.lineno && span.lineno > 0 ? ":#{span.lineno}" : ""
|
|
310
|
-
" at=#{File.basename(file_name)}#{lno}"
|
|
302
|
+
" at=#{File.basename(span.file_name)}#{lno}"
|
|
311
303
|
end
|
|
312
304
|
|
|
313
305
|
def span_display_name(span)
|
|
314
306
|
return SYNTHETIC_SPAN_NAME if span.synthetic
|
|
315
|
-
return SYNTHETIC_SPAN_NAME if span.
|
|
316
|
-
|
|
317
|
-
name = @method_table[span.method_id]
|
|
318
|
-
name ||= Vivarium::Usdt.get_method_name(span.method_id)
|
|
319
|
-
return name if name
|
|
307
|
+
return SYNTHETIC_SPAN_NAME if span.method_name.nil? || span.method_name.empty?
|
|
320
308
|
|
|
321
|
-
|
|
322
|
-
format("#{UNRESOLVED_METHOD_PREFIX}0x%016X>", span.method_id & 0xFFFF_FFFF_FFFF_FFFF)
|
|
309
|
+
span.method_name
|
|
323
310
|
end
|
|
324
311
|
|
|
325
312
|
def build_span_children(span)
|
|
@@ -548,28 +535,20 @@ module Vivarium
|
|
|
548
535
|
|
|
549
536
|
def render_raise_target(ev)
|
|
550
537
|
bytes = ev.payload.to_s.b
|
|
551
|
-
return "-" if bytes.
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
if message_id != -1
|
|
564
|
-
msg = Vivarium::Usdt.get_message_name(message_id)
|
|
565
|
-
parts << "message=#{msg.inspect}" if msg
|
|
566
|
-
end
|
|
567
|
-
|
|
568
|
-
if file_id != -1 && (file_name = Vivarium::Usdt.get_file_name(file_id))
|
|
569
|
-
lno = lineno && lineno > 0 ? ":#{lineno}" : ""
|
|
538
|
+
return "-" if bytes.empty?
|
|
539
|
+
|
|
540
|
+
slot = Vivarium::SPAN_RAISE_SLOT_SIZE
|
|
541
|
+
error_name = Vivarium.c_string(bytes[0, slot])
|
|
542
|
+
message = Vivarium.c_string(bytes[slot, slot])
|
|
543
|
+
file_name = Vivarium.c_string(bytes[slot * 2, slot])
|
|
544
|
+
lineno = bytes.bytesize > Vivarium::SPAN_RAISE_LINENO_OFFSET ? bytes[Vivarium::SPAN_RAISE_LINENO_OFFSET, 8].unpack1("q<") : -1
|
|
545
|
+
|
|
546
|
+
parts = ["error=#{error_name.empty? ? '?' : error_name}"]
|
|
547
|
+
parts << "message=#{message.inspect}" unless message.empty?
|
|
548
|
+
unless file_name.empty?
|
|
549
|
+
lno = lineno > 0 ? ":#{lineno}" : ""
|
|
570
550
|
parts << "at=#{File.basename(file_name)}#{lno}"
|
|
571
551
|
end
|
|
572
|
-
|
|
573
552
|
parts.join(" ")
|
|
574
553
|
end
|
|
575
554
|
|
|
@@ -589,12 +568,12 @@ module Vivarium
|
|
|
589
568
|
|
|
590
569
|
def read_span_payload(payload)
|
|
591
570
|
bytes = payload.to_s.b
|
|
592
|
-
return [
|
|
571
|
+
return [nil, nil, -1] if bytes.empty?
|
|
593
572
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
lineno
|
|
597
|
-
[
|
|
573
|
+
method_name = Vivarium.c_string(bytes[0, Vivarium::SPAN_METHOD_SIZE])
|
|
574
|
+
file_name = Vivarium.c_string(bytes[Vivarium::SPAN_METHOD_SIZE, Vivarium::SPAN_FILE_SIZE])
|
|
575
|
+
lineno = bytes.bytesize > Vivarium::SPAN_LINENO_OFFSET ? bytes[Vivarium::SPAN_LINENO_OFFSET, 8].unpack1("q<") : -1
|
|
576
|
+
[method_name, file_name, lineno]
|
|
598
577
|
end
|
|
599
578
|
|
|
600
579
|
def read_proc_fork_child_pid(payload)
|
data/lib/vivarium/version.rb
CHANGED
data/lib/vivarium.rb
CHANGED
|
@@ -33,6 +33,15 @@ module Vivarium
|
|
|
33
33
|
EVENT_DROPPED_OFFSET = 288
|
|
34
34
|
EVENTS_RINGBUF_PAGES = 256
|
|
35
35
|
|
|
36
|
+
SPAN_METHOD_SIZE = 128
|
|
37
|
+
SPAN_FILE_SIZE = 120
|
|
38
|
+
SPAN_LINENO_OFFSET = SPAN_METHOD_SIZE + SPAN_FILE_SIZE # 248
|
|
39
|
+
SPAN_FILE_ARG_MAX = SPAN_FILE_SIZE - 1
|
|
40
|
+
|
|
41
|
+
SPAN_RAISE_SLOT_SIZE = 80
|
|
42
|
+
SPAN_RAISE_LINENO_OFFSET = SPAN_RAISE_SLOT_SIZE * 3 # 240
|
|
43
|
+
SPAN_RAISE_FILE_ARG_MAX = SPAN_RAISE_SLOT_SIZE - 1
|
|
44
|
+
|
|
36
45
|
SSL_WRITE_PAYLOAD_DATA_LEN_OFFSET = 0
|
|
37
46
|
SSL_WRITE_PAYLOAD_CAP_LEN_OFFSET = 4
|
|
38
47
|
SSL_WRITE_PAYLOAD_DATA_OFFSET = 8
|
|
@@ -86,7 +95,20 @@ module Vivarium
|
|
|
86
95
|
"Kernel#eval",
|
|
87
96
|
"Object#instance_eval",
|
|
88
97
|
"Object#instance_exec",
|
|
98
|
+
"ENV#[]",
|
|
99
|
+
"ENV#fetch",
|
|
100
|
+
"ENV#key?",
|
|
101
|
+
"ENV#[]=",
|
|
102
|
+
"ENV#store",
|
|
103
|
+
"ENV#delete",
|
|
104
|
+
"ENV#clear",
|
|
105
|
+
"ENV#replace",
|
|
89
106
|
].freeze
|
|
107
|
+
|
|
108
|
+
ENV_PAYLOAD_OP_SIZE = 16
|
|
109
|
+
ENV_PAYLOAD_KEY_OFFSET = ENV_PAYLOAD_OP_SIZE
|
|
110
|
+
ENV_PAYLOAD_KEY_SIZE = EVENT_PAYLOAD_SIZE - ENV_PAYLOAD_KEY_OFFSET
|
|
111
|
+
|
|
90
112
|
EVENT_SEVERITY_HIGH = %w[
|
|
91
113
|
capable_check bprm_creds setid_change task_kill
|
|
92
114
|
ptrace_check sb_mount kernel_read_file
|
|
@@ -149,6 +171,16 @@ module Vivarium
|
|
|
149
171
|
str[0, nul]
|
|
150
172
|
end
|
|
151
173
|
|
|
174
|
+
def self.tail_fit_string(value, max_bytes, marker: "...")
|
|
175
|
+
str = value.to_s.b
|
|
176
|
+
return str if str.bytesize <= max_bytes
|
|
177
|
+
return str.byteslice(-max_bytes, max_bytes) || "" if max_bytes <= marker.bytesize
|
|
178
|
+
|
|
179
|
+
tail_size = max_bytes - marker.bytesize
|
|
180
|
+
tail = str.byteslice(-tail_size, tail_size) || ""
|
|
181
|
+
"#{marker}#{tail}"
|
|
182
|
+
end
|
|
183
|
+
|
|
152
184
|
def self.event_severity(event_name)
|
|
153
185
|
EVENT_SEVERITY_HIGH.include?(event_name.to_s) ? "high" : "medium"
|
|
154
186
|
end
|
|
@@ -388,6 +420,20 @@ module Vivarium
|
|
|
388
420
|
{ data_len: data_len, cap_len: cap_len, data: data }
|
|
389
421
|
end
|
|
390
422
|
|
|
423
|
+
def self.decode_env_payload(raw_payload)
|
|
424
|
+
bytes = raw_payload.to_s.b
|
|
425
|
+
return "" if bytes.bytesize < ENV_PAYLOAD_OP_SIZE
|
|
426
|
+
|
|
427
|
+
op = c_string(bytes[0, ENV_PAYLOAD_OP_SIZE])
|
|
428
|
+
key = c_string(bytes[ENV_PAYLOAD_KEY_OFFSET, ENV_PAYLOAD_KEY_SIZE])
|
|
429
|
+
|
|
430
|
+
return "" if op.empty?
|
|
431
|
+
return "op=#{op}" if key.empty?
|
|
432
|
+
|
|
433
|
+
key = key.split("=", 2).first if op == "putenv"
|
|
434
|
+
"op=#{op} key=#{key.inspect}"
|
|
435
|
+
end
|
|
436
|
+
|
|
391
437
|
def self.decode_span_raise_payload(raw_payload)
|
|
392
438
|
bytes = raw_payload.to_s.b
|
|
393
439
|
return "" if bytes.bytesize < 8
|
|
@@ -475,6 +521,9 @@ module Vivarium
|
|
|
475
521
|
when "ssl_write"
|
|
476
522
|
decoded = decode_ssl_write_payload(event.payload)
|
|
477
523
|
"data_len=#{decoded[:data_len]} cap_len=#{decoded[:cap_len]}"
|
|
524
|
+
when "env_caccess"
|
|
525
|
+
decoded = decode_env_payload(event.payload)
|
|
526
|
+
decoded.empty? ? event.payload.inspect : decoded
|
|
478
527
|
when "dlopen", "mmap_exec"
|
|
479
528
|
strip_to_first_null(event.payload).inspect
|
|
480
529
|
else
|
|
@@ -707,6 +756,26 @@ module Vivarium
|
|
|
707
756
|
events.ringbuf_submit(ev, 0);
|
|
708
757
|
}
|
|
709
758
|
|
|
759
|
+
static __always_inline void submit_env_event(u32 pid, const char *op, u32 op_len, const char *name_ptr)
|
|
760
|
+
{
|
|
761
|
+
struct event_t ev = {};
|
|
762
|
+
ev.pid = pid;
|
|
763
|
+
__builtin_memcpy(ev.event_name, "env_caccess", 12);
|
|
764
|
+
|
|
765
|
+
if (op && op_len > 0) {
|
|
766
|
+
if (op_len > #{ENV_PAYLOAD_OP_SIZE} - 1) {
|
|
767
|
+
op_len = #{ENV_PAYLOAD_OP_SIZE} - 1;
|
|
768
|
+
}
|
|
769
|
+
__builtin_memcpy(&ev.payload[0], op, op_len);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (name_ptr) {
|
|
773
|
+
bpf_probe_read_user_str(&ev.payload[#{ENV_PAYLOAD_KEY_OFFSET}], #{ENV_PAYLOAD_KEY_SIZE}, name_ptr);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
submit_event(&ev);
|
|
777
|
+
}
|
|
778
|
+
|
|
710
779
|
static __always_inline int is_dns_destination(void *addr)
|
|
711
780
|
{
|
|
712
781
|
u16 family = 0;
|
|
@@ -1394,19 +1463,19 @@ module Vivarium
|
|
|
1394
1463
|
return 0;
|
|
1395
1464
|
}
|
|
1396
1465
|
|
|
1397
|
-
u64
|
|
1398
|
-
u64
|
|
1399
|
-
|
|
1400
|
-
bpf_usdt_readarg(1, ctx, &
|
|
1401
|
-
bpf_usdt_readarg(2, ctx, &
|
|
1466
|
+
u64 method_str_ptr = 0;
|
|
1467
|
+
u64 file_str_ptr = 0;
|
|
1468
|
+
s64 lineno = 0;
|
|
1469
|
+
bpf_usdt_readarg(1, ctx, &method_str_ptr);
|
|
1470
|
+
bpf_usdt_readarg(2, ctx, &file_str_ptr);
|
|
1402
1471
|
bpf_usdt_readarg(3, ctx, &lineno);
|
|
1403
1472
|
|
|
1404
1473
|
struct event_t ev = {};
|
|
1405
1474
|
ev.pid = pid;
|
|
1406
1475
|
__builtin_memcpy(ev.event_name, "span_start", 11);
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
__builtin_memcpy(&ev.payload[
|
|
1476
|
+
bpf_probe_read_user_str(&ev.payload[0], #{SPAN_METHOD_SIZE}, (void*)method_str_ptr);
|
|
1477
|
+
bpf_probe_read_user_str(&ev.payload[#{SPAN_METHOD_SIZE}], #{SPAN_FILE_SIZE}, (void*)file_str_ptr);
|
|
1478
|
+
__builtin_memcpy(&ev.payload[#{SPAN_LINENO_OFFSET}], &lineno, sizeof(lineno));
|
|
1410
1479
|
submit_event(&ev);
|
|
1411
1480
|
return 0;
|
|
1412
1481
|
}
|
|
@@ -1421,19 +1490,19 @@ module Vivarium
|
|
|
1421
1490
|
return 0;
|
|
1422
1491
|
}
|
|
1423
1492
|
|
|
1424
|
-
u64
|
|
1425
|
-
u64
|
|
1426
|
-
|
|
1427
|
-
bpf_usdt_readarg(1, ctx, &
|
|
1428
|
-
bpf_usdt_readarg(2, ctx, &
|
|
1493
|
+
u64 method_str_ptr = 0;
|
|
1494
|
+
u64 file_str_ptr = 0;
|
|
1495
|
+
s64 lineno = 0;
|
|
1496
|
+
bpf_usdt_readarg(1, ctx, &method_str_ptr);
|
|
1497
|
+
bpf_usdt_readarg(2, ctx, &file_str_ptr);
|
|
1429
1498
|
bpf_usdt_readarg(3, ctx, &lineno);
|
|
1430
1499
|
|
|
1431
1500
|
struct event_t ev = {};
|
|
1432
1501
|
ev.pid = pid;
|
|
1433
1502
|
__builtin_memcpy(ev.event_name, "span_stop", 10);
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
__builtin_memcpy(&ev.payload[
|
|
1503
|
+
bpf_probe_read_user_str(&ev.payload[0], #{SPAN_METHOD_SIZE}, (void*)method_str_ptr);
|
|
1504
|
+
bpf_probe_read_user_str(&ev.payload[#{SPAN_METHOD_SIZE}], #{SPAN_FILE_SIZE}, (void*)file_str_ptr);
|
|
1505
|
+
__builtin_memcpy(&ev.payload[#{SPAN_LINENO_OFFSET}], &lineno, sizeof(lineno));
|
|
1437
1506
|
submit_event(&ev);
|
|
1438
1507
|
return 0;
|
|
1439
1508
|
}
|
|
@@ -1500,6 +1569,80 @@ module Vivarium
|
|
|
1500
1569
|
return 0;
|
|
1501
1570
|
}
|
|
1502
1571
|
|
|
1572
|
+
int on_getenv(struct pt_regs *ctx)
|
|
1573
|
+
{
|
|
1574
|
+
u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
1575
|
+
u32 pid = pid_tgid >> 32;
|
|
1576
|
+
u32 tid = (u32)pid_tgid;
|
|
1577
|
+
const char *name = (const char *)PT_REGS_PARM1(ctx);
|
|
1578
|
+
|
|
1579
|
+
if (!target_enabled(pid, tid) || !name) {
|
|
1580
|
+
return 0;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
submit_env_event(pid, "getenv", 6, name);
|
|
1584
|
+
return 0;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
int on_setenv(struct pt_regs *ctx)
|
|
1588
|
+
{
|
|
1589
|
+
u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
1590
|
+
u32 pid = pid_tgid >> 32;
|
|
1591
|
+
u32 tid = (u32)pid_tgid;
|
|
1592
|
+
const char *name = (const char *)PT_REGS_PARM1(ctx);
|
|
1593
|
+
|
|
1594
|
+
if (!target_enabled(pid, tid) || !name) {
|
|
1595
|
+
return 0;
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
submit_env_event(pid, "setenv", 6, name);
|
|
1599
|
+
return 0;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
int on_unsetenv(struct pt_regs *ctx)
|
|
1603
|
+
{
|
|
1604
|
+
u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
1605
|
+
u32 pid = pid_tgid >> 32;
|
|
1606
|
+
u32 tid = (u32)pid_tgid;
|
|
1607
|
+
const char *name = (const char *)PT_REGS_PARM1(ctx);
|
|
1608
|
+
|
|
1609
|
+
if (!target_enabled(pid, tid) || !name) {
|
|
1610
|
+
return 0;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
submit_env_event(pid, "unsetenv", 8, name);
|
|
1614
|
+
return 0;
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
int on_putenv(struct pt_regs *ctx)
|
|
1618
|
+
{
|
|
1619
|
+
u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
1620
|
+
u32 pid = pid_tgid >> 32;
|
|
1621
|
+
u32 tid = (u32)pid_tgid;
|
|
1622
|
+
const char *string = (const char *)PT_REGS_PARM1(ctx);
|
|
1623
|
+
|
|
1624
|
+
if (!target_enabled(pid, tid) || !string) {
|
|
1625
|
+
return 0;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
submit_env_event(pid, "putenv", 6, string);
|
|
1629
|
+
return 0;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
int on_clearenv(struct pt_regs *ctx)
|
|
1633
|
+
{
|
|
1634
|
+
u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
1635
|
+
u32 pid = pid_tgid >> 32;
|
|
1636
|
+
u32 tid = (u32)pid_tgid;
|
|
1637
|
+
|
|
1638
|
+
if (!target_enabled(pid, tid)) {
|
|
1639
|
+
return 0;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
submit_env_event(pid, "clearenv", 8, 0);
|
|
1643
|
+
return 0;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1503
1646
|
int on_span_raise(struct pt_regs *ctx)
|
|
1504
1647
|
{
|
|
1505
1648
|
u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
@@ -1510,33 +1653,34 @@ module Vivarium
|
|
|
1510
1653
|
return 0;
|
|
1511
1654
|
}
|
|
1512
1655
|
|
|
1513
|
-
u64
|
|
1514
|
-
u64
|
|
1515
|
-
u64
|
|
1516
|
-
|
|
1517
|
-
bpf_usdt_readarg(1, ctx, &
|
|
1518
|
-
bpf_usdt_readarg(2, ctx, &
|
|
1519
|
-
bpf_usdt_readarg(3, ctx, &
|
|
1656
|
+
u64 error_str_ptr = 0;
|
|
1657
|
+
u64 message_str_ptr = 0;
|
|
1658
|
+
u64 file_str_ptr = 0;
|
|
1659
|
+
s64 lineno = 0;
|
|
1660
|
+
bpf_usdt_readarg(1, ctx, &error_str_ptr);
|
|
1661
|
+
bpf_usdt_readarg(2, ctx, &message_str_ptr);
|
|
1662
|
+
bpf_usdt_readarg(3, ctx, &file_str_ptr);
|
|
1520
1663
|
bpf_usdt_readarg(4, ctx, &lineno);
|
|
1521
1664
|
|
|
1522
1665
|
struct event_t ev = {};
|
|
1523
1666
|
ev.pid = pid;
|
|
1524
1667
|
__builtin_memcpy(ev.event_name, "span_raise", 11);
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
__builtin_memcpy(&ev.payload[
|
|
1668
|
+
bpf_probe_read_user_str(&ev.payload[0], #{SPAN_RAISE_SLOT_SIZE}, (void*)error_str_ptr);
|
|
1669
|
+
bpf_probe_read_user_str(&ev.payload[#{SPAN_RAISE_SLOT_SIZE}], #{SPAN_RAISE_SLOT_SIZE}, (void*)message_str_ptr);
|
|
1670
|
+
bpf_probe_read_user_str(&ev.payload[#{SPAN_RAISE_SLOT_SIZE * 2}], #{SPAN_RAISE_SLOT_SIZE}, (void*)file_str_ptr);
|
|
1671
|
+
__builtin_memcpy(&ev.payload[#{SPAN_RAISE_LINENO_OFFSET}], &lineno, sizeof(lineno));
|
|
1529
1672
|
submit_event(&ev);
|
|
1530
1673
|
return 0;
|
|
1531
1674
|
}
|
|
1532
1675
|
CLANG
|
|
1533
1676
|
|
|
1534
1677
|
def initialize(pin_dir: Vivarium.bpf_pin_dir, ssl_trace: true, libssl_path: nil,
|
|
1535
|
-
dlopen_trace: true, libc_path: nil)
|
|
1678
|
+
dlopen_trace: true, env_trace: true, libc_path: nil)
|
|
1536
1679
|
@pin_dir = pin_dir
|
|
1537
1680
|
@ssl_trace = ssl_trace
|
|
1538
1681
|
@libssl_path = libssl_path
|
|
1539
1682
|
@dlopen_trace = dlopen_trace
|
|
1683
|
+
@env_trace = env_trace
|
|
1540
1684
|
@libc_path = libc_path
|
|
1541
1685
|
end
|
|
1542
1686
|
|
|
@@ -1561,6 +1705,7 @@ module Vivarium
|
|
|
1561
1705
|
|
|
1562
1706
|
attach_ssl_write_uprobe(bpf) if @ssl_trace
|
|
1563
1707
|
attach_dlopen_uprobe(bpf) if @dlopen_trace
|
|
1708
|
+
attach_env_uprobes(bpf) if @env_trace
|
|
1564
1709
|
|
|
1565
1710
|
config_root_targets = bpf["config_root_targets"]
|
|
1566
1711
|
config_spawned_targets = bpf["config_spawned_targets"]
|
|
@@ -1633,6 +1778,30 @@ module Vivarium
|
|
|
1633
1778
|
warn "[vivariumd] dlopen uprobe attach failed: #{e.class}: #{e.message}"
|
|
1634
1779
|
end
|
|
1635
1780
|
|
|
1781
|
+
def attach_env_uprobes(bpf)
|
|
1782
|
+
path = resolve_libc_path
|
|
1783
|
+
unless path
|
|
1784
|
+
warn "[vivariumd] libc not found; ENV uprobes disabled " \
|
|
1785
|
+
"(set --libc PATH or VIVARIUM_LIBC_PATH to override)"
|
|
1786
|
+
return
|
|
1787
|
+
end
|
|
1788
|
+
|
|
1789
|
+
{
|
|
1790
|
+
"getenv" => "on_getenv",
|
|
1791
|
+
"setenv" => "on_setenv",
|
|
1792
|
+
"unsetenv" => "on_unsetenv",
|
|
1793
|
+
"putenv" => "on_putenv",
|
|
1794
|
+
"clearenv" => "on_clearenv"
|
|
1795
|
+
}.each do |sym, fn_name|
|
|
1796
|
+
begin
|
|
1797
|
+
bpf.attach_uprobe(name: path, sym: sym, fn_name: fn_name)
|
|
1798
|
+
puts "[vivariumd] #{sym} uprobe attached via #{path}"
|
|
1799
|
+
rescue StandardError => e
|
|
1800
|
+
warn "[vivariumd] #{sym} uprobe attach failed: #{e.class}: #{e.message}"
|
|
1801
|
+
end
|
|
1802
|
+
end
|
|
1803
|
+
end
|
|
1804
|
+
|
|
1636
1805
|
def resolve_libc_path
|
|
1637
1806
|
if @libc_path
|
|
1638
1807
|
return @libc_path if File.exist?(@libc_path)
|
|
@@ -1806,20 +1975,18 @@ module Vivarium
|
|
|
1806
1975
|
pid = Process.pid
|
|
1807
1976
|
store.register_pid(pid)
|
|
1808
1977
|
|
|
1809
|
-
method_id_queue = Thread::Queue.new
|
|
1810
1978
|
main_tid = gettid
|
|
1811
1979
|
|
|
1812
1980
|
correlator = Correlator.new(
|
|
1813
1981
|
pin_dir: pin_dir,
|
|
1814
1982
|
observer_pid: pid,
|
|
1815
1983
|
main_tid: main_tid,
|
|
1816
|
-
method_id_queue: method_id_queue,
|
|
1817
1984
|
filter: filter,
|
|
1818
1985
|
dest: dest
|
|
1819
1986
|
)
|
|
1820
1987
|
correlator.start
|
|
1821
1988
|
|
|
1822
|
-
tracer = build_observe_tracepoint
|
|
1989
|
+
tracer = build_observe_tracepoint
|
|
1823
1990
|
tracer.enable
|
|
1824
1991
|
|
|
1825
1992
|
session = ObservationSession.new(
|
|
@@ -1836,20 +2003,18 @@ module Vivarium
|
|
|
1836
2003
|
pid = Process.pid
|
|
1837
2004
|
store.register_pid(pid)
|
|
1838
2005
|
|
|
1839
|
-
method_id_queue = Thread::Queue.new
|
|
1840
2006
|
main_tid = gettid
|
|
1841
2007
|
|
|
1842
2008
|
correlator = Correlator.new(
|
|
1843
2009
|
pin_dir: pin_dir,
|
|
1844
2010
|
observer_pid: pid,
|
|
1845
2011
|
main_tid: main_tid,
|
|
1846
|
-
method_id_queue: method_id_queue,
|
|
1847
2012
|
filter: filter,
|
|
1848
2013
|
dest: dest
|
|
1849
2014
|
)
|
|
1850
2015
|
correlator.start
|
|
1851
2016
|
|
|
1852
|
-
tracer = build_observe_tracepoint
|
|
2017
|
+
tracer = build_observe_tracepoint
|
|
1853
2018
|
tracer.enable
|
|
1854
2019
|
|
|
1855
2020
|
yield
|
|
@@ -1859,37 +2024,41 @@ module Vivarium
|
|
|
1859
2024
|
correlator&.stop
|
|
1860
2025
|
end
|
|
1861
2026
|
|
|
1862
|
-
def self.build_observe_tracepoint
|
|
2027
|
+
def self.build_observe_tracepoint
|
|
1863
2028
|
allow_classes = SPAN_ALLOWCLASSES
|
|
1864
2029
|
allowlist = SPAN_ALLOWLIST
|
|
1865
2030
|
TracePoint.new(:call, :c_call, :return, :c_return, :raise) do |tp|
|
|
1866
2031
|
if tp.event == :raise
|
|
1867
2032
|
# FIXME: handle threaded events in the future
|
|
1868
|
-
if tp.raised_exception.kind_of?(ThreadError)
|
|
1869
|
-
next
|
|
1870
|
-
end
|
|
2033
|
+
next if tp.raised_exception.kind_of?(ThreadError)
|
|
1871
2034
|
|
|
2035
|
+
file_arg = tail_fit_string(tp.path, SPAN_RAISE_FILE_ARG_MAX)
|
|
1872
2036
|
Vivarium::Usdt.raise(
|
|
1873
2037
|
tp.raised_exception.class.to_s,
|
|
1874
2038
|
tp.raised_exception.message.to_s,
|
|
1875
|
-
file:
|
|
2039
|
+
file: file_arg,
|
|
1876
2040
|
lineno: tp.lineno
|
|
1877
2041
|
)
|
|
1878
2042
|
next
|
|
1879
2043
|
end
|
|
1880
2044
|
|
|
1881
|
-
signature =
|
|
2045
|
+
signature = if tp.self.equal?(ENV)
|
|
2046
|
+
"ENV##{tp.method_id}"
|
|
2047
|
+
else
|
|
2048
|
+
"#{tp.defined_class}##{tp.method_id}"
|
|
2049
|
+
end
|
|
1882
2050
|
is_target = allowlist.include?(signature) || \
|
|
1883
2051
|
allow_classes.any? { |klass| tp.defined_class == klass } || \
|
|
1884
2052
|
allow_classes.any? { |klass| tp.defined_class == klass.singleton_class }
|
|
1885
2053
|
next unless is_target
|
|
1886
2054
|
|
|
2055
|
+
file_arg = tail_fit_string(tp.path, SPAN_FILE_ARG_MAX)
|
|
2056
|
+
span_class_name = tp.self.equal?(ENV) ? "ENV" : tp.defined_class.to_s
|
|
1887
2057
|
case tp.event
|
|
1888
2058
|
when :call, :c_call
|
|
1889
|
-
|
|
1890
|
-
method_id_queue << [method_id, signature]
|
|
2059
|
+
Vivarium::Usdt.start(span_class_name, tp.method_id.to_s, file: file_arg, lineno: tp.lineno)
|
|
1891
2060
|
when :return, :c_return
|
|
1892
|
-
Vivarium::Usdt.stop(
|
|
2061
|
+
Vivarium::Usdt.stop(span_class_name, tp.method_id.to_s, file: file_arg, lineno: tp.lineno)
|
|
1893
2062
|
end
|
|
1894
2063
|
end
|
|
1895
2064
|
end
|
|
@@ -1921,10 +2090,11 @@ module Vivarium
|
|
|
1921
2090
|
|
|
1922
2091
|
def self.run_daemon!(argv = ARGV)
|
|
1923
2092
|
options = { pin_dir: bpf_pin_dir, ssl_trace: true, libssl_path: nil,
|
|
2093
|
+
env_trace: true,
|
|
1924
2094
|
dlopen_trace: true, libc_path: nil }
|
|
1925
2095
|
OptionParser.new do |opts|
|
|
1926
2096
|
opts.banner = "Usage: vivariumd [--pin-dir PATH] [--no-ssl-trace] [--libssl PATH] " \
|
|
1927
|
-
"[--no-dlopen-trace] [--libc PATH]"
|
|
2097
|
+
"[--no-dlopen-trace] [--no-env-trace] [--libc PATH]"
|
|
1928
2098
|
opts.on("--pin-dir PATH", "Pinned map directory") { |v| options[:pin_dir] = v }
|
|
1929
2099
|
opts.on("--[no-]ssl-trace", "Attach OpenSSL SSL_write uprobe (default: enabled)") do |v|
|
|
1930
2100
|
options[:ssl_trace] = v
|
|
@@ -1935,6 +2105,9 @@ module Vivarium
|
|
|
1935
2105
|
opts.on("--[no-]dlopen-trace", "Attach libc dlopen uprobe (default: enabled)") do |v|
|
|
1936
2106
|
options[:dlopen_trace] = v
|
|
1937
2107
|
end
|
|
2108
|
+
opts.on("--[no-]env-trace", "Attach libc getenv/setenv uprobes (default: enabled)") do |v|
|
|
2109
|
+
options[:env_trace] = v
|
|
2110
|
+
end
|
|
1938
2111
|
opts.on("--libc PATH", "Path to libc.so for dlopen uprobe") do |v|
|
|
1939
2112
|
options[:libc_path] = v
|
|
1940
2113
|
end
|
|
@@ -1945,6 +2118,7 @@ module Vivarium
|
|
|
1945
2118
|
ssl_trace: options[:ssl_trace],
|
|
1946
2119
|
libssl_path: options[:libssl_path],
|
|
1947
2120
|
dlopen_trace: options[:dlopen_trace],
|
|
2121
|
+
env_trace: options[:env_trace],
|
|
1948
2122
|
libc_path: options[:libc_path]
|
|
1949
2123
|
).run
|
|
1950
2124
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: vivarium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Uchio Kondo
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.4.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.
|
|
39
|
+
version: 0.4.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: ostruct
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -66,6 +66,8 @@ files:
|
|
|
66
66
|
- Rakefile
|
|
67
67
|
- examples/dlopen_demo.rb
|
|
68
68
|
- examples/drop_demo.rb
|
|
69
|
+
- examples/env_access_external_demo.rb
|
|
70
|
+
- examples/env_access_ruby_demo.rb
|
|
69
71
|
- examples/execve_demo.rb
|
|
70
72
|
- examples/file_operation_demo.rb
|
|
71
73
|
- examples/network_client_demo.rb
|