Skip to content

scripts: Add automated fuzzing trial orchestrator - #153

Merged
morehouse merged 1 commit into
morehouse:masterfrom
Chand-ra:smite-orchestrator
Jul 24, 2026
Merged

scripts: Add automated fuzzing trial orchestrator#153
morehouse merged 1 commit into
morehouse:masterfrom
Chand-ra:smite-orchestrator

Conversation

@Chand-ra

Copy link
Copy Markdown

Introduce smite-orchestrator.py to handle the automated execution of parallel fuzzing trials across multiple targets for rigorous A/B coverage evaluation.

The script automatically queues jobs and maps CPU cores using taskset for strict isolation. It manages the full lifecycle of standalone Nyx mode (-X) fuzzers, including the generation and cleanup of isolated sharedirs per trial.

It features a live Rich TUI dashboard to monitor real-time coverage metrics and track failed trials, and ensures graceful teardown of active processes upon completion or interrupt.

@Chand-ra

Chand-ra commented Jul 16, 2026

Copy link
Copy Markdown
Author

Here's what the dashboard looks like:

python scripts/smite-orchestrator.py --out-dir ~/smite-results --configs baseline:encrypted_bytes,experimental:ir --targets lnd,ldk,cln,eclair --cores 0,1 --smite-dir ~/smite --afl-dir ~/AFLplusplus/ --trials 5 --timeout 120
Screenshot 2026-07-16 125255

CLN and Eclair ran pretty flaky: sometimes all of their trials would succeed and other times none would, but those two targets are flaky on my machine even when ran normally (without this orchestrator). This is probably because I use a VM, but would love if someone else could confirm it.

Edit: The top of the dashboard should read Smite Orchestrator (Parallel Fuzzing Trials) instead of Smite Orchestrator (Coverage Campaign). The screenshot was taken before this particular change was made, sorry.

@erickcestari

Copy link
Copy Markdown
Contributor

It's looking really nice!

Q: Couldn't this live in the smitebot cli?

@Chand-ra

Chand-ra commented Jul 17, 2026

Copy link
Copy Markdown
Author

It's looking really nice!

Thanks, Eric!

Q: Couldn't this live in the smitebot cli?

Right, the more I was working on the script the more I realized that this is a better fit as a feature in smitebot. We could reuse a lot of functionality from smitebot start (like automated seed creation, sharedir creation) that we need to re-implement here.

However, I decided to not go down that path because:

i) I already had a similar script in Python, and creating this script just meant making a couple of changes in that script (although it did end up being more than a couple 😞). This is probably the biggest reason.

ii) This script uses Rich to build the TUI and that's something that I was familiar with, I'm completely blank on TUI libraries in Rust though. Although now that I look around, ratatui would have probably worked.

iii) I had a discussion with Matt and Nishant on this some time ago and we agreed that it was fine to implement the script in Python.

It might be worthwhile to note this (porting this script to smitebot as a separate command) as something we may want to do in the future though.

@Ashish-Kumar-Dash

Ashish-Kumar-Dash commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Yes, I'm on board with this. Looking at it, the overlap with smitebot goes a bit further than start, the process-group teardown to reap orphaned QEMU is basically what stop does too, minus the graceful TERM→KILL escalation. Even the monitoring side wouldn't really need ratatui, #150 does its live view as a self-reloading tmux window over a single fuzzer_stats parser. Though the Rich dashboard aggregates many trials at once, which the single-campaign status view doesn't, so they might serve different purposes.

From my understanding, the one thing that'd make a port non-trivial is that smitebot is built entirely around -Y parallel campaigns, tmux, shared sharedir, runners cooperating on one coverage map, and this wants the opposite- isolated -X single-core trials. So start would need a single-trial -X mode before any of that reuse actually kicks in. Definitely worth writing down as future work, as start.rs is due for edits after status lands.

@Chand-ra

Copy link
Copy Markdown
Author

From my understanding, the one thing that'd make a port non-trivial is that smitebot is built entirely around -Y parallel campaigns, tmux, shared sharedir, runners cooperating on one coverage map, and this wants the opposite- isolated -X single-core trials. So start would need a single-trial -X mode before any of that reuse actually kicks in. Definitely worth writing down as future work, as start.rs is due for edits after status lands.

Right, I first implemented this using smitebot start to run a single trial, and that worked for a while, but a couple of things proved to be confounding:

  1. smitebot start uses UNIX timestamps to write state.json files to a globally shared tracking folder. Parallel trials that get executed at the same instance cause race conditions.

    I tried side-stepping this using time-based locks, but that turned out to be a flaky workaround. The best solution is probably to never write these files in the first place since we're directly polling fuzzer_stats to display the relevant data and afl-fuzz.log provides a window to each fuzzer's live state.

  2. I wanted more granular control over when we create the sharedirs and how we use them. Right now we create them at the start of each trial (similar to smitebot start), but I can envision a future where we might want to create those before we run any trial (similar to what we're doing with the Docker images) and possibly re-use them across trials.

  3. tmux proved to be the biggest obstacle. Running parallel tmux instances completely fudges the TUI dashboard. Need to entirely disable it for the parallel fuzzing trials.

@morehouse

Copy link
Copy Markdown
Owner

CLN and Eclair ran pretty flaky: sometimes all of their trials would succeed and other times none would, but those two targets are flaky on my machine even when ran normally (without this orchestrator). This is probably because I use a VM, but would love if someone else could confirm it.

Doesn't happen for me on bare metal. Could you file a bug with the startup errors you get?

Q: Couldn't this live in the smitebot cli?

I do eventually want this ported over to smitebot. But a Python script works for now.

Comment thread scripts/smite-orchestrator.py Outdated
Comment thread scripts/smite-orchestrator.py Outdated
Comment thread scripts/smite-orchestrator.py Outdated
"AFL_NO_AFFINITY": "1",
"AFL_NO_UI": "1",
"AFL_NO_COLOR": "1",
"AFL_FORKSRV_INIT_TMOUT": "1800000",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't had to touch the forkserver timeout; I assume it's needed for your nested virtualization setup?

@Chand-ra Chand-ra Jul 18, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Spawning parallel Nyx-mode AFL++ instances on my potato laptop takes some time, the default timeout frequently produced false positive crashes😅. This is supposed to be a generous upper bound to prevent that.

Comment thread scripts/smite-orchestrator.py
@Chand-ra

Copy link
Copy Markdown
Author

CLN and Eclair ran pretty flaky: sometimes all of their trials would succeed and other times none would, but those two targets are flaky on my machine even when ran normally (without this orchestrator). This is probably because I use a VM, but would love if someone else could confirm it.

Doesn't happen for me on bare metal. Could you file a bug with the startup errors you get?

Sure, I'll do that if I encounter those again.

Introduce `smite-orchestrator.py` to handle the automated execution
of parallel fuzzing trials across multiple targets for rigorous A/B
coverage evaluation.

The script automatically queues jobs and maps CPU cores using `taskset`
for strict isolation. It manages the full lifecycle of standalone Nyx
mode (`-X`) fuzzers, including the generation and cleanup of isolated
sharedirs per trial.

It features a live Rich TUI dashboard to monitor real-time coverage
metrics and track failed trials, and ensures graceful teardown of
active processes upon completion or interrupt.
@Chand-ra
Chand-ra force-pushed the smite-orchestrator branch from 66ddbd3 to d9f0bfb Compare July 20, 2026 05:22
@Chand-ra

Copy link
Copy Markdown
Author

CLN and Eclair ran pretty flaky: sometimes all of their trials would succeed and other times none would, but those two targets are flaky on my machine even when ran normally (without this orchestrator). This is probably because I use a VM, but would love if someone else could confirm it.

Doesn't happen for me on bare metal. Could you file a bug with the startup errors you get?

Sure, I'll do that if I encounter those again.

I think now I have a good idea of why this happens.

To make the required changes to this script, I had to revert a change I had made to setup-nyx.sh which decreased the memory allocation for a new VM instance from 4 GB to 2 GB. I forgot to re-apply the said change after modifying the script. So now when I invoked the orchestrator, all the targets (including previously non-failing targets LND and LDK) failed with the same errors that CLN and Eclair did earlier.

I believe this is because a single target consumed (4 GB + some overhead) of memory, and because my VM has only 10 GB of memory, spawning two such instances forced the OOM killer to terminate one of these instances. Changing the allocated memory to 2 GB fixed the issue for LND, LDK, and Eclair.

As for why the issue only surfaced in CLN and Eclair earlier, I believe it is because these two targets are the most memory-hungry out of the set (CLN spawns a bunch of sub-daemons and Eclair needs JVM).

@morehouse morehouse left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used this to evaluate #154 (comment), and everything was seamless.

The ability to choose the CPU cores was especially helpful so that I could make sure P cores were used for all trials.

@morehouse
morehouse merged commit abee205 into morehouse:master Jul 24, 2026
5 checks passed
@Chand-ra
Chand-ra deleted the smite-orchestrator branch July 27, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants