Conversation
Introduce the SnapshotSetup trait for specifying the setup for different IR scenarios. Then implement the trait for PostInitSetup, which starts fuzzing after the init handshake is complete.
Having timing info for each Act operation is very helpful for understanding what's happening when running inputs locally.
ekzyis
left a comment
There was a problem hiding this comment.
I tried to follow the steps in the README, but it seems like the LDK target is broken:
[hcat] INFO [smite_scenarios::targets::bitcoind] Starting bitcoind...
INFO [smite_scenarios::targets::bitcoind] Waiting for bitcoind to be ready...
INFO [smite_scenarios::targets::bitcoind] bitcoind is ready
INFO [smite_scenarios::targets::ldk] Starting ldk-node-wrapper...
DEBUG [smite::process] ldk-node-wrapper: dropping running process, attempting shutdown
DEBUG [smite::process] ldk-node-wrapper: sending SIGTERM to process group 179
DEBUG [smite::process] ldk-node-wrapper: exited with signal: 4 (SIGILL)
DEBUG [smite::process] bitcoind: dropping running process, attempting shutdown
DEBUG [smite::process] bitcoind: sending SIGTERM to process group 146
DEBUG [smite::process] bitcoind: exited with exit status: 0
ERROR [smite::scenarios] Failed to initialize scenario: target error: failed to start: no PUBKEY line received
[!] libnyx failed to initialize QEMU-Nyx: agent abort() ->
USER_ABORT called: INFO [smite_scenarios::targets::bitcoind] Waiting for bitcoind to be ready...
INFO [smite_scenarios::targets::bitcoind] bitcoind is ready
INFO [smite_scenarios::targets::ldk] Starting ldk-node-wrapper...
DEBUG [smite::process] ldk-node-wrapper: dropping running process, attempting shutdown
DEBUG [smite::process] ldk-node-wrapper: sending SIGTERM to process group 179
DEBUG [smite::process] ldk-node-wrapper: exited with signal: 4 (SIGILL)
DEBUG [smite::process] bitcoind: dropping running process, attempting shutdown
DEBUG [smite::process] bitcoind: sending SIGTERM to process group 146
DEBUG [smite::process] bitcoind: exited with exit status: 0
ERROR [smite::scenarios] Failed to initialize scenario: target error: failed to start: no PUBKEY line received
[-] PROGRAM ABORT : Something went wrong ...
Location : afl_fsrv_start(), src/afl-forkserver.c:835
This also happens on master (c4a400c) with ldk_init scenario, so it's unrelated to the changes here.
Does this happen for you?
| // Drain any remaining post-init noise so the snapshot starts with a | ||
| // clean connection. | ||
| ping_pong(&mut conn)?; |
There was a problem hiding this comment.
nit: related to my other comment: I think this wouldn't drain noise after pong was received. Is this a concern?
There was a problem hiding this comment.
Right, other messages could also come after the pong, which we will miss here. If it becomes an issue, we'll have to resort to other tricks to filter that out, like we do with disabling gossip.
| // -- Act operations -- | ||
| Operation::SendMessage => { | ||
| let bytes = resolve_message(&variables, instr.inputs[0])?; | ||
| let msg_type = bytes.get(..2).map(|b| u16::from_be_bytes([b[0], b[1]])); |
There was a problem hiding this comment.
Can we not assume that bytes.len() >= 2 because it resolved as a message and use u16::from_be_bytes([bytes[0], bytes[1]]) directly?
There was a problem hiding this comment.
I think that would work right now.
Currently all Variable::Messages have the two-byte prefix, but if we ever allow sending sending of arbitrary data, that would no longer be the case.
| // Ping-pong sync to ensure the target has at least done the initial | ||
| // processing of all previous messages. Timeouts here signal a hang. |
There was a problem hiding this comment.
nit: Isn't this probabilistic that the target has done the initial processing of all previous messages instead of ensured?
There was a problem hiding this comment.
It's ensured that the initial processing is done (i.e. message was read and forwarded to the appropriate subsystem), since messages are read in order. Obviously the full processing may not be done, but we don't have a great way to ensure that.
| let Ok(program) = postcard::from_bytes::<Program>(input) else { | ||
| return ScenarioResult::Skip; | ||
| }; |
The scenario configures the snapshot state using a SnapshotSetup. Then on each iteration the scenario deserializes an input into a Program, uses the executor to run the program, and checks for crashes and hangs.
Fuzzes each target using IrScenario and PostInitSetup.
| let Ok(program) = postcard::from_bytes::<Program>(input) else { | ||
| return ScenarioResult::Skip; | ||
| }; |
| // Ping-pong sync to ensure the target has at least done the initial | ||
| // processing of all previous messages. Timeouts here signal a hang. |
There was a problem hiding this comment.
It's ensured that the initial processing is done (i.e. message was read and forwarded to the appropriate subsystem), since messages are read in order. Obviously the full processing may not be done, but we don't have a great way to ensure that.
| // Drain any remaining post-init noise so the snapshot starts with a | ||
| // clean connection. | ||
| ping_pong(&mut conn)?; |
There was a problem hiding this comment.
Right, other messages could also come after the pong, which we will miss here. If it becomes an issue, we'll have to resort to other tricks to filter that out, like we do with disabling gossip.
| // -- Act operations -- | ||
| Operation::SendMessage => { | ||
| let bytes = resolve_message(&variables, instr.inputs[0])?; | ||
| let msg_type = bytes.get(..2).map(|b| u16::from_be_bytes([b[0], b[1]])); |
There was a problem hiding this comment.
I think that would work right now.
Currently all Variable::Messages have the two-byte prefix, but if we ever allow sending sending of arbitrary data, that would no longer be the case.
No, I can't reproduce this ,and I'm not sure why LDK isn't starting up for you. @NishantBansal2003, @erickcestari: Have either of you run into this? |
Nope, I ran it and haven’t found any issues like that Logs (FYI)[+] Enabled environment variable AFL_CUSTOM_MUTATOR_LIBRARY with value target/release/libsmite_ir_mutator.so
[+] Enabled environment variable AFL_CUSTOM_MUTATOR_ONLY with value 1
afl-fuzz++4.36a based on afl by Michal Zalewski and a large online community
[+] AFL++ is maintained by Marc "van Hauser" Heuse, Dominik Maier, Andrea Fioraldi and Heiko "hexcoder" Eißfeldt
[+] AFL++ is open source, get it at https://github.com/AFLplusplus/AFLplusplus
[+] NOTE: AFL++ >= v3 has changed defaults and behaviours - see README.md
[+] AFL++ Nyx mode is enabled (developed and maintained by Sergej Schumilo)
[+] Nyx is open source, get it at https://github.com/Nyx-Fuzz
[+] No -M/-S set, autoconfiguring for "-S default"
[+] Enabled environment variable AFL_DISABLE_TRIM with value 1
[*] Getting to work...
[+] Using exploration-based constant power schedule (EXPLORE)
[+] Enabled testcache with 50 MB
[+] Generating fuzz data with a length of min=1 max=1048576
[+] FrameShift status: enabled (10% overhead configured)
[*] Trying to load libnyx.so plugin...
[+] libnyx plugin is ready!
[+] You have 20 CPU cores and 1 runnable tasks (utilization: 5%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/fuzzing_in_depth.md#c-using-multiple-cores
[*] Setting up output directories...
[*] Checking CPU core loadout...
[+] Found a free CPU core, try binding to #0.
[*] Loading custom mutator library from 'target/release/libsmite_ir_mutator.so'...
[+] Found 'afl_custom_mutator'.
[*] optional symbol 'afl_custom_fuzz_count' not found.
[*] optional symbol 'afl_custom_post_process' not found.
[*] optional symbol 'afl_custom_init_trim' not found.
[*] optional symbol 'afl_custom_trim' not found.
[*] optional symbol 'afl_custom_post_trim' not found.
[*] optional symbol 'afl_custom_havoc_mutation' not found.
[*] optional symbol 'afl_custom_havoc_mutation_probability' not found.
[*] optional symbol 'afl_custom_queue_get' not found.
[+] Found 'afl_custom_splice_optout'.
[*] optional symbol 'afl_custom_fuzz_send' not found.
[*] optional symbol 'afl_custom_post_run' not found.
[*] optional symbol 'afl_custom_queue_new_entry' not found
[+] Found 'afl_custom_describe'.
[+] Custom mutator 'target/release/libsmite_ir_mutator.so' installed successfully.
[*] Validating target binary...
[*] Scanning '/tmp/smite-seeds'...
[*] Creating hard links for all input files...
[+] Loaded a total of 1 seeds.
[*] Spinning up the NYX backend...
[!] libnyx: spawning qemu with:
/home/nishant/Desktop/AFLplusplus/nyx_mode/QEMU-Nyx/x86_64-softmmu/qemu-system-x86_64 -kernel /home/nishant/Desktop/AFLplusplus/nyx_mode/packer/linux_initramfs/bzImage-linux-4.15-rc7 -initrd /home/nishant/Desktop/AFLplusplus/nyx_mode/packer/linux_initramfs/init.cpio.gz -append nokaslr oops=panic nopti ignore_rlimit_data -display none -serial none -enable-kvm -net none -k de -m 4096 -chardev socket,server,path=/tmp/smite-out/workdir/interface_0,id=nyx_interface -device nyx,chardev=nyx_interface,bitmap_size=65536,input_buffer_size=1048576,worker_id=0,workdir=/tmp/smite-out/workdir,sharedir=/tmp/smite-nyx,aux_buffer_size=4096 -machine kAFL64-v1 -cpu kAFL64-Hypervisor-v1 -fast_vm_reload path=/tmp/smite-out/workdir/snapshot/,load=off,skip_serialization=on
american fuzzy lop ++4.36a {default} (/tmp/smite-nyx) [explore] - Nyx
┌─ process timing ────────────────────────────────────┬─ overall results ────┐
│ run time : 0 days, 0 hrs, 3 min, 6 sec │ cycles done : 0 │
│ last new find : 0 days, 0 hrs, 0 min, 3 sec │ corpus count : 521 │
│last saved crash : none seen yet │saved crashes : 0 │
│ last saved hang : none seen yet │ saved hangs : 0 │
├─ cycle progress ─────────────────────┬─ map coverage┴──────────────────────┤
│ now processing : 386*0 (74.1%) │ map density : 0.45% / 0.49% │
│ runs timed out : 0 (0.00%) │ count coverage : 4.44 bits/tuple │
├─ stage progress ─────────────────────┼─ findings in depth ─────────────────┤
│ now trying : libsmite_ir_mutator.so │ favored items : 39 (7.49%) │
│ stage execs : 68/400 (17.00%) │ new edges on : 48 (9.21%) │
│ total execs : 354k │ total crashes : 0 (0 saved) │
│ exec speed : 1740/sec │ total tmouts : 0 (0 saved) │
├─ fuzzing strategy yields ────────────┴─────────────┬─ item geometry ───────┤
│ bit flips : disabled (custom-mutator-only mode) │ levels : 8 │
│ byte flips : disabled (custom-mutator-only mode) │ pending : 428 │
│ arithmetics : disabled (custom-mutator-only mode) │ pend fav : 0 │
│ known ints : disabled (custom-mutator-only mode) │ own finds : 520 │
│ dictionary : n/a │ imported : 0 │
│havoc/splice : 0/0, 0/0 │ stability : 58.92% │
│py/custom/rq : unused, 513/306k, unused, unused ├───────────────────────┘
│ trim/eff : disabled, disabled │ [cpu000: 10%]
└─ strategy: explore ────────── state: started :-) ──┘
|
I've tested it in the same commit (c4a400c) and encountered the same error as @ekzyis. Full logCPU |
|
Could it be an issue with rust nightly? I've made a fresh build with the new rust nightly version. |
|
|
|
I rebuilt the Docker image with |
|
Created #65 for it so we can focus on the PR here |
Enables end-to-end IR fuzzing of all 4 targets.
IrScenariois parameterized by aSnapshotSetupthat determines the snapshot restore point. Currently we only implement aPostInitSetuptailored towards theopen_channelfunding flow, but we can add more snapshot setups as needed.Ref: #5 (Milestone 1)