Notes on how to run the fuzzer (not included in the PR, but for future reference): On Fedora39 (Fedora40 afl packages are a bit broken, I'll open a bug):
export AFL_USE_ASAN=1
export ASAN_OPTIONS="detect_leaks=0,use_sigaltstack=0"
./configure CC=afl-clang-fast 'CFLAGS=-Og -g -fno-omit-frame-pointer'
make -j32
cat >parse0.ml <<EOF
open Runtime_events
let runtime_begin _ _ _ = ()
let runtime_end _ _ _ = ()
let runtime_counter _ _ _ _ = ()
let alloc _ _ _ = ()
let lifecycle _ _ _ _ = ()
let lost_events _ _ = ()
let callbacks = Runtime_events.Callbacks.create
~runtime_begin ~runtime_end ~runtime_counter ~alloc ~lifecycle ~lost_events ()
let parse path_pid =
let cursor =
Runtime_events.create_cursor path_pid in
let finally () = Runtime_events.free_cursor cursor in
Fun.protect ~finally @@ fun () ->
Runtime_events.read_poll cursor callbacks None
let parse_corrupted path_pid =
try let (_:int) = parse path_pid in ()
with Failure _ | Invalid_argument _ ->
(* parsing corrupted rings, raises exceptions,
this is expected *)
()
let pid = Unix.getpid ()
let file = Printf.sprintf "%d.events" pid
let run () =
let () =
try Sys.remove file with Sys_error _ -> ()
in
Unix.symlink Sys.argv.(1) file;
Unix.truncate Sys.argv.(1) 68167744;
parse_corrupted (Some (".", pid));
Unix.unlink file
let () =
AflPersistent.run run
EOF
../ocamlopt.opt -I ../stdlib -I ../otherlibs/unix -I ../otherlibs/runtime_events unix.cmxa aflPersistent.cmx runtime_events.cmxa aflPersistent.mli -c
../ocamlopt.opt -I ../stdlib -I ../otherlibs/unix -I ../otherlibs/runtime_events unix.cmxa aflPersistent.cmx runtime_events.cmxa aflPersistent.ml -c
./ocamlopt.opt -I ../stdlib -I ../otherlibs/unix -I ../otherlibs/runtime_events unix.cmxa aflPersistent.cmx runtime_events.cmxa parse0.ml -o parse0p
In a separate dir build MSAN instrumented AFL runtime:
unset AFL_USE_ASAN
export AFL_USE_MSAN=1
./configure CC=afl-clang-fast CFLAGS="-Og -g -fno-omit-frame-pointer" --without-zstd --disable-native-compiler
make -j32
../runtime/ocamlrun ../ocamlc -nostdlib -I ../stdlib -I ../otherlibs/unix -I ../otherlibs/runtime_events unix.cma runtime_events.cma aflPersistent.cmo parse0.ml -custom -ccopt -I../runtime -o parse0p
Input data: get an .events file from (modify it to remove unlink at the end), and move it to input/
make one TEST=tests/lib-runtime-events/test_external_preserve.ml
To run:
export ASAN_OPTIONS="detect_leaks=0,use_sigaltstack=0,abort_on_error=1,symbolize=0"
# important to set this, otherwise AFL will set it, and enable leak reporting, which will result in what AFL calls "unstable" results (where test binary output is different)
export LSAN_OPTIONS="detect_leaks=0,symbolize=0"
afl-fuzz -M fuzzer001 -i input -o output -- afl-persistent.1.4/parse0p @@
for i in $(seq 1 15); do AFL_NO_UI=1 afl-fuzz -P explore -S fuzzer01$i -i input/ -o output/ afl-persistent.1.4/parse0p @@& done
afl-fuzz -S fuzzer04M -i input/ -o output/ ../ocaml-fuzz-msan/afl-persistent.1.4/parse0p @@
Caveats:
When AFL aborts a run (e.g. due to a timeout) the symlink is not cleaned up and a lot of symlinks pile up in the current dir.
In fact so many files can be created that cleaning up with 'rm *.events' is not possible anymore, and this has to be used instead:
find . -name '*.events' -print0 | xargs -0 rm
Fedora 40 bug reported here https://bugzilla.redhat.com/show_bug.cgi?id=2297764 , should be fixable with a package rebuild (and perhaps could be future proofed by making
afl-clang-fast
callclang-<MAJORVER>
instead.