ruzzy 0.6.0 → 0.7.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: 0abba0ffb63d4c50fbbb33fb3624299f8421293a02d65e199525c75b4dbd5f46
4
- data.tar.gz: 4787489da1373bb820cd66d62a913a4c9c33c49bda68f251dae25745ccac3679
3
+ metadata.gz: 64fa385ff3dca5a231ebc02511f7240143838b4cf4314a8ced35a57127ac2dc2
4
+ data.tar.gz: 1cd94db1a0b30debdc03caddf39394b3759b11f85d0b2ef78037e5769b0761ed
5
5
  SHA512:
6
- metadata.gz: c029eca231fbeb0d8b19b469a6cb2de99117a939e35c9f42622f803d06a0b4ad85ceacc25dff1bba9e56b1179358ec8fff054a35d894faa11398727891697216
7
- data.tar.gz: cb761ff27a1fa8d462295d9022d03490338d2608d94cddc8454fb2919fd308e8ee7ea18b4735e601574ca1366de266607c2966be18e27af21ab1c3e243f60237
6
+ metadata.gz: ed77800fbbe359a7b2be3e215b00d052b2bf8f1038da0e2ad88c6a8ea9d66bcf2d875ed5658592262ef35a18a23c4b1f5fcc9d44e7f669fc81817310dda96122
7
+ data.tar.gz: 80ef311558dd4c4aa88697014e08a6b06a164d182a16d5c4718ce9355bc6b2f82c52bce11d3eaa1d1071df2a900eef9ef46148013ad7099ed1fbf07df173b6c3
data/ext/cruzzy/cruzzy.c CHANGED
@@ -194,11 +194,11 @@ static void event_hook_branch(VALUE counter_hash, rb_trace_arg_t *tracearg) {
194
194
 
195
195
  static void enable_branch_coverage_hooks()
196
196
  {
197
- // Call Coverage.setup(branches: true) to activate branch coverage hooks.
197
+ // Call Coverage.start(branches: true) to activate branch coverage hooks.
198
198
  // Branch coverage hooks will not be activated without this call despite
199
199
  // adding the event hooks. I suspect rb_set_coverages must be called
200
200
  // first, which initializes some global state that we do not have direct
201
- // access to. Calling setup initializes coverage state here:
201
+ // access to. Calling start initializes coverage state here:
202
202
  // https://github.com/ruby/ruby/blob/v3_3_0/ext/coverage/coverage.c#L112-L120
203
203
  // If rb_set_coverages is not called, then rb_get_coverages returns a NULL
204
204
  // pointer, which appears to effectively disable coverage collection here:
@@ -207,10 +207,10 @@ static void enable_branch_coverage_hooks()
207
207
  VALUE coverage_mod = rb_const_get(rb_cObject, rb_intern("Coverage"));
208
208
  VALUE hash_arg = rb_hash_new();
209
209
  rb_hash_aset(hash_arg, ID2SYM(rb_intern("branches")), Qtrue);
210
- rb_funcall(coverage_mod, rb_intern("setup"), 1, hash_arg);
210
+ rb_funcall(coverage_mod, rb_intern("start"), 1, hash_arg);
211
211
  }
212
212
 
213
- static VALUE c_trace_branch(VALUE self)
213
+ static VALUE c_trace(VALUE self, VALUE harness_path)
214
214
  {
215
215
  VALUE counter_hash = rb_hash_new();
216
216
 
@@ -230,7 +230,7 @@ static VALUE c_trace_branch(VALUE self)
230
230
 
231
231
  enable_branch_coverage_hooks();
232
232
 
233
- return Qnil;
233
+ return rb_require(StringValueCStr(harness_path));
234
234
  }
235
235
 
236
236
  void Init_cruzzy()
@@ -245,5 +245,5 @@ void Init_cruzzy()
245
245
  rb_define_module_function(ruzzy, "c_libfuzzer_is_loaded", &c_libfuzzer_is_loaded, 0);
246
246
  rb_define_module_function(ruzzy, "c_trace_cmp8", &c_trace_cmp8, 2);
247
247
  rb_define_module_function(ruzzy, "c_trace_div8", &c_trace_div8, 1);
248
- rb_define_module_function(ruzzy, "c_trace_branch", &c_trace_branch, 0);
248
+ rb_define_module_function(ruzzy, "c_trace", &c_trace, 1);
249
249
  }
@@ -64,6 +64,7 @@ def merge_sanitizer_libfuzzer_lib(sanitizer_lib, fuzzer_no_main_lib, merged_outp
64
64
  '-Wl,--no-whole-archive',
65
65
  '-lpthread',
66
66
  '-ldl',
67
+ '-lstdc++',
67
68
  '-shared',
68
69
  '-o',
69
70
  merged_output
@@ -137,4 +138,6 @@ merge_sanitizer_libfuzzer_lib(
137
138
  # For more information, see https://github.com/ruby/ruby/blob/master/lib/mkmf.rb.
138
139
  $LOCAL_LIBS = fuzzer_no_main_lib
139
140
 
141
+ $LIBS << ' -lstdc++'
142
+
140
143
  create_makefile('cruzzy/cruzzy')
data/ext/dummy/dummy.c CHANGED
@@ -6,17 +6,18 @@
6
6
  // https://llvm.org/docs/LibFuzzer.html#toy-example
7
7
  static int _c_dummy_test_one_input(const uint8_t *data, size_t size)
8
8
  {
9
- char test[] = {'a', 'b', 'c'};
9
+ volatile char boom = 'x';
10
10
 
11
- if (size > 0 && data[0] == 'H') {
12
- if (size > 1 && data[1] == 'I') {
13
- // This code exists specifically to test the driver and ensure
14
- // libFuzzer is functioning as expected, so we can safely ignore
15
- // the warning.
16
- #pragma clang diagnostic push
17
- #pragma clang diagnostic ignored "-Warray-bounds"
18
- test[1024] = 'd';
19
- #pragma clang diagnostic pop
11
+ if (size == 2) {
12
+ if (data[0] == 'H') {
13
+ if (data[1] == 'I') {
14
+ // Intentional heap-use-after-free for testing purposes
15
+ char * volatile ptr = malloc(128);
16
+ ptr[0] = 'x';
17
+ free(ptr);
18
+ boom = ptr[0];
19
+ (void) boom;
20
+ }
20
21
  }
21
22
  }
22
23
 
data/lib/ruzzy.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
 
5
- # A Ruby C extension fuzzer
5
+ # A coverage-guided fuzzer for pure Ruby code and Ruby C extensions
6
6
  module Ruzzy
7
7
  require 'cruzzy/cruzzy'
8
8
 
@@ -15,10 +15,6 @@ module Ruzzy
15
15
  c_fuzz(test_one_input, args)
16
16
  end
17
17
 
18
- def dummy
19
- fuzz(->(data) { Ruzzy.dummy_test_one_input(data) })
20
- end
21
-
22
18
  def dummy_test_one_input(data)
23
19
  # This 'require' depends on LD_PRELOAD, so it's placed inside the function
24
20
  # scope. This allows us to access EXT_PATH for LD_PRELOAD and not have a
@@ -28,9 +24,28 @@ module Ruzzy
28
24
  c_dummy_test_one_input(data)
29
25
  end
30
26
 
27
+ def dummy
28
+ fuzz(->(data) { dummy_test_one_input(data) })
29
+ end
30
+
31
+ def trace(harness_script)
32
+ harness_path = Pathname.new(harness_script)
33
+
34
+ # Mimic require_relative. If harness script is provided as an absolute path,
35
+ # then use that. If not, then assume the script is in the same directory as
36
+ # as the tracer script, i.e. the caller.
37
+ if !harness_path.absolute?
38
+ caller_path = Pathname.new(caller_locations.first.path)
39
+ harness_path = (caller_path.parent / harness_path).realpath
40
+ end
41
+
42
+ c_trace(harness_path.to_s)
43
+ end
44
+
31
45
  module_function :fuzz
32
- module_function :dummy
33
46
  module_function :dummy_test_one_input
47
+ module_function :dummy
48
+ module_function :trace
34
49
  end
35
50
 
36
51
  # Hook Integer operations for tracing in SantizerCoverage
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruzzy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Trail of Bits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-13 00:00:00.000000000 Z
11
+ date: 2024-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -101,5 +101,5 @@ requirements: []
101
101
  rubygems_version: 3.5.3
102
102
  signing_key:
103
103
  specification_version: 4
104
- summary: A Ruby C extension fuzzer
104
+ summary: A coverage-guided fuzzer for pure Ruby code and Ruby C extensions
105
105
  test_files: []