cirron 0.3.1 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c007b251356de7d4d30dc444f70ce6440b1df51aca80292e1d4f1f6be1f282f
4
- data.tar.gz: 168cf0a7b01bf1bf59bcbeba407be5580dfe3f6634f676527284e912eb1e3f8b
3
+ metadata.gz: 28bb8894ef6331fcd6bae4aa768a71ce98fbf29b3870c83ec215c81dea120dd2
4
+ data.tar.gz: 54c4983a926fc03bfda415ef785b5ce0046c3a410ad92526c0ed9b8c98be4de8
5
5
  SHA512:
6
- metadata.gz: 10db47d299a3200ccf6f7e4b7d76825fd1d5433b865b5bdc73f3d0ac1a99198b0b1f2ea340545de3519d087aa42adf4d7dc87cb14bf2e580cdf05e8d3151fc48
7
- data.tar.gz: 4b4cbf8ffeb1c032cbd329eb7717d5caa878c2919010e227dac5bd06b78e9c81613052e8276bc98569af8bafdc3ca658223e27ee46f825f92812e39684e737cf
6
+ metadata.gz: 6a46bd52674c2dd8886521d6c90d93defbbcca383aaf5a685330e75e784060ee4dbeaa5c08f5b8e459950e9b1ba7f53c64e28565a174cb0601dae6ce3c6ba7d4
7
+ data.tar.gz: b058dab6e5657950507ad766dea5b6edfaa74107656a08cfcd38bc1e48a867f83966cbdc462484e982c42f827b941bf27f15cf290f2396be9036b1302911a7b8
data/README.md CHANGED
@@ -24,7 +24,7 @@ It can also trace syscalls using +strace+, Linux only!
24
24
  Hello
25
25
  => Counter(time_enabled_ns: 110260, instruction_count: 15406, branch_misses: 525, page_faults: 0)
26
26
 
27
- === Syscalls
27
+ === Tracing Syscalls
28
28
 
29
29
  $ sudo irb
30
30
  irb> require 'cirron'
@@ -38,6 +38,36 @@ It can also trace syscalls using +strace+, Linux only!
38
38
  irb> File.write("/tmp/trace", Cirron::to_tef(trace))
39
39
  => 267
40
40
 
41
+ === Tampering with Syscalls
42
+
43
+ Available tampering actions are:
44
+ error: Inject a fault with the specified errno.
45
+ retval: Inject a success with the specified return value.
46
+ signal: Deliver the specified signal on syscall entry.
47
+ delay_enter: Delay syscall entry by the specified time.
48
+ delay_exit: Delay syscall exit by the specified time.
49
+ poke_enter: Modify memory at argN on syscall entry.
50
+ poke_exit: Modify memory at argN on syscall exit.
51
+ syscall: Inject a different syscall instead.
52
+
53
+ The when argument can be used to specify when to perform the tampering.
54
+
55
+ See the Tampering section of the [strace manual page](https://man7.org/linux/man-pages/man1/strace.1.html) for more detailed explanaition of the arguments.
56
+
57
+ ```
58
+ $ sudo irb
59
+ irb> require 'cirron'
60
+
61
+ irb> injector = Cirron.injector
62
+ irb> injector.inject("openat", "error", "ENOSPC")
63
+ irb> injector.inject("openat", "delay_enter", "1s", when_condition="2+2")
64
+ irb> injector.run do
65
+ irb> # Open now fails with "No space left on device" and every
66
+ irb> # other call to `openat` will be delayed by 1s.
67
+ irb> File.open("test.txt", "w")
68
+ irb> end
69
+ ```
70
+
41
71
  == Additional Information
42
72
 
43
73
  For more detailed information, please visit the project's GitHub page: https://github.com/s7nfo/Cirron
data/cirron.gemspec CHANGED
@@ -6,7 +6,7 @@ require 'pathname'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = "cirron"
9
- spec.version = "0.3.1"
9
+ spec.version = "0.4.0"
10
10
  spec.authors = ["Matt Stuchlik"]
11
11
  spec.email = ["matej.stuchlik@gmail.com"]
12
12
 
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  "lib/cirronlib.cpp",
26
26
  "lib/collector.rb",
27
27
  "lib/tracer.rb",
28
+ "lib/injector.rb",
28
29
  "README.md",
29
30
  "LICENSE",
30
31
  "cirron.gemspec"
data/lib/cirron.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require_relative 'tracer'
2
2
  require_relative 'collector'
3
+ require_relative 'injector'
data/lib/injector.rb ADDED
@@ -0,0 +1,64 @@
1
+ require 'tempfile'
2
+ require 'open3'
3
+
4
+ Rule = Struct.new(:syscall, :action, :value, :when)
5
+
6
+ module Cirron
7
+ class Injector
8
+ VALID_ACTIONS = [
9
+ 'error', 'retval', 'signal', 'syscall', 'delay_enter', 'delay_exit',
10
+ 'poke_enter', 'poke_exit', 'when'
11
+ ].freeze
12
+
13
+ def initialize
14
+ @rules = []
15
+ end
16
+
17
+ def inject(syscall, action, value, when_condition = nil)
18
+ unless VALID_ACTIONS.include?(action)
19
+ raise ArgumentError, "Invalid action: #{action}. Valid actions are: #{VALID_ACTIONS.join(', ')}"
20
+ end
21
+
22
+ @rules << Rule.new(syscall, action, value, when_condition)
23
+ end
24
+
25
+ def run(timeout = 10)
26
+ trace_file = Tempfile.new('cirron_inject')
27
+ trace_file_path = trace_file.path
28
+ trace_file.close
29
+ trace_file.unlink
30
+ parent_pid = Process.pid
31
+
32
+ cmd = ["strace", "--quiet=attach,exit", "-f", "-o", trace_file_path, "-p", parent_pid.to_s]
33
+
34
+ @rules.each do |rule|
35
+ inject_arg = "inject=#{rule.syscall}:#{rule.action}=#{rule.value}"
36
+ inject_arg += ":when=#{rule.when}" if rule.when
37
+ cmd.concat(["-e", inject_arg])
38
+ end
39
+
40
+ strace_proc = spawn(*cmd, :out => "/dev/null", :err => "/dev/null")
41
+
42
+ begin
43
+ deadline = Time.now + timeout
44
+ until File.exist?(trace_file_path)
45
+ if Time.now > deadline
46
+ raise Timeout::Error, "Failed to start strace within #{timeout}s."
47
+ end
48
+ sleep 0.1
49
+ end
50
+
51
+ sleep 0.1
52
+
53
+ yield if block_given?
54
+ ensure
55
+ Process.kill('INT', strace_proc) rescue nil
56
+ Process.wait(strace_proc) rescue nil
57
+ end
58
+ end
59
+ end
60
+
61
+ def self.injector
62
+ Injector.new
63
+ end
64
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cirron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Stuchlik
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-07-09 00:00:00.000000000 Z
11
+ date: 2024-09-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "= Cirron\n\nCirron measures a piece of Ruby code and reports back several
14
14
  performance counters: \nCPU instruction count, branch misses, page faults and time
@@ -18,14 +18,28 @@ description: "= Cirron\n\nCirron measures a piece of Ruby code and reports back
18
18
  Usage\n\n=== Performance Counters\n $ sudo irb\n irb(main):001> require 'cirron'\n
19
19
  \ => true\n irb(main):002* c = Cirron::collector do\n irb(main):003* puts \"Hello\"\n
20
20
  \ irb(main):004> end\n Hello\n => Counter(time_enabled_ns: 110260, instruction_count:
21
- 15406, branch_misses: 525, page_faults: 0)\n\n=== Syscalls\n\n $ sudo irb\n irb>
22
- require 'cirron'\n => true\n irb> trace = Cirron::tracer do\n irb> # Your code
23
- here\n irb> puts \"Hello\"\n irb> end\n => [#<Syscall:0x00007c6c1a4b3608 @args=\"1,
24
- [{iov_base=\\\"Hello\\\", iov_len=5}, {iov_base=\\\"\\\\n\\\", iov_len=1}], 2\",
25
- @duration=\"0.000201\", @name=\"writev\", @pid=\"2261962\", @retval=\"6\", @timestamp=\"1720285300.334976\">]\n
26
- \ # Save the trace for ingesting to Perfetto\n irb> File.write(\"/tmp/trace\",
27
- Cirron::to_tef(trace))\n => 267\n\n== Additional Information\n\nFor more detailed
28
- information, please visit the project's GitHub page: https://github.com/s7nfo/Cirron"
21
+ 15406, branch_misses: 525, page_faults: 0)\n\n=== Tracing Syscalls\n\n $ sudo irb\n
22
+ \ irb> require 'cirron'\n => true\n irb> trace = Cirron::tracer do\n irb> #
23
+ Your code here\n irb> puts \"Hello\"\n irb> end\n => [#<Syscall:0x00007c6c1a4b3608
24
+ @args=\"1, [{iov_base=\\\"Hello\\\", iov_len=5}, {iov_base=\\\"\\\\n\\\", iov_len=1}],
25
+ 2\", @duration=\"0.000201\", @name=\"writev\", @pid=\"2261962\", @retval=\"6\",
26
+ @timestamp=\"1720285300.334976\">]\n # Save the trace for ingesting to Perfetto\n
27
+ \ irb> File.write(\"/tmp/trace\", Cirron::to_tef(trace))\n => 267\n\n=== Tampering
28
+ with Syscalls\n\nAvailable tampering actions are:\nerror: Inject a fault with the
29
+ specified errno.\nretval: Inject a success with the specified return value.\nsignal:
30
+ Deliver the specified signal on syscall entry.\ndelay_enter: Delay syscall entry
31
+ by the specified time.\ndelay_exit: Delay syscall exit by the specified time.\npoke_enter:
32
+ Modify memory at argN on syscall entry.\npoke_exit: Modify memory at argN on syscall
33
+ exit.\nsyscall: Inject a different syscall instead.\n\nThe when argument can be
34
+ used to specify when to perform the tampering.\n\nSee the Tampering section of the
35
+ [strace manual page](https://man7.org/linux/man-pages/man1/strace.1.html) for more
36
+ detailed explanaition of the arguments.\n\n```\n$ sudo irb\nirb> require 'cirron'\n\nirb>
37
+ injector = Cirron.injector\nirb> injector.inject(\"openat\", \"error\", \"ENOSPC\")\nirb>
38
+ injector.inject(\"openat\", \"delay_enter\", \"1s\", when_condition=\"2+2\")\nirb>
39
+ injector.run do\nirb> # Open now fails with \"No space left on device\" and
40
+ every\nirb> # other call to `openat` will be delayed by 1s.\nirb> File.open(\"test.txt\",
41
+ \"w\")\nirb> end\n```\n\n== Additional Information\n\nFor more detailed information,
42
+ please visit the project's GitHub page: https://github.com/s7nfo/Cirron"
29
43
  email:
30
44
  - matej.stuchlik@gmail.com
31
45
  executables: []
@@ -39,6 +53,7 @@ files:
39
53
  - lib/cirron.rb
40
54
  - lib/cirronlib.cpp
41
55
  - lib/collector.rb
56
+ - lib/injector.rb
42
57
  - lib/tracer.rb
43
58
  homepage: https://github.com/s7nfo/Cirron
44
59
  licenses: