Skip to content

smitebot: implement reproduce command - #207

Open
Ashish-Kumar-Dash wants to merge 1 commit into
lnfuzz:masterfrom
Ashish-Kumar-Dash:reproduce-cmd
Open

smitebot: implement reproduce command#207
Ashish-Kumar-Dash wants to merge 1 commit into
lnfuzz:masterfrom
Ashish-Kumar-Dash:reproduce-cmd

Conversation

@Ashish-Kumar-Dash

@Ashish-Kumar-Dash Ashish-Kumar-Dash commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Description

What

Adds smitebot reproduce <campaign-id> -i <input> [--attach]: replays a single input against a campaign's target by running its Docker image once, the same way scripts/coverage-report.sh feeds inputs to LocalRunner. The target's output streams to the terminal; the command interprets nothing as the logs are the deliverable.

smitebot reproduce <campaign-id> -i path/to/crash
smitebot reproduce <campaign-id> -i path/to/crash --attach   # interactive TTY

Mechanism

Resolves image + target from the campaign's state.json (no live campaign required), then runs:

  docker run --rm [-it] -v <input-parent>:/corpus:ro \
  -e SMITE_INPUT=/corpus/<basename> <image> /<target>-scenario
  • The input's parent directory is bind-mounted read-only and the basename is passed via SMITE_INPUT, so colons in AFL crash names (id:000000,sig:06,...) never land in the colon-delimited -v spec. This mirrors coverage-report.sh.
  • --attach adds -it to watch the run live.
  • execute returns true once the container runs to completion regardless of its exit code; false only on operational failure (unknown campaign, missing input, missing image, docker spawn error). Errors name the offending path/value and the fix, fore.g. a missing image points at smitebot build .

Scope for v1

Local-Docker reproduction only. Deliberately deferred for later PR:

  • Nyx-mode reproduction - a later phase.

Ref. #70

Comment thread smitebot/README.md

### smitebot reproduce

Replays a single input against a campaign's target by running its Docker image once, with the input fed to the target the same way the fuzzer's `LocalRunner` does. The target's output is streamed to the terminal; `reproduce` interprets nothing — read the logs to see what happened. Resolves the image and target from the campaign's `state.json`; no live campaign required.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: could remove the implementation details here, just like the semantics followed above

Comment on lines +43 to +60
let Some(runs_dir) = CampaignState::runs_dir() else {
log::error!("unable to determine home directory");
return false;
};

let state_path = runs_dir.join(&args.campaign_id).join("state.json");
let state = match CampaignState::load(&state_path) {
Ok(s) => s,
Err(e) => {
log::error!("{e}");
log::error!(
"campaign '{}' not found; list campaigns with: ls {}",
args.campaign_id,
runs_dir.display()
);
return false;
}
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This part of the code is repeated across many commands, I think we could refactor it into a helper in a follow-up PR

Comment on lines +84 to +92
if !docker_image_exists(&state.image) {
log::error!(
"Docker image '{}' not found; build it with: smitebot build --target {} --scenario {}",
state.image,
state.target,
state.scenario
);
return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure about others, but I often run a campaign with a specific docker image and then continue development alongside it, creating new docker images with the same name. So, if this command runs a docker image referenced by the same name, I might get false results without realizing it

I think we should compare the found docker image's digest with the one stored in image_digest in state.json and log a warning if they don't match, saying that the results might differ from what was observed during the campaign. We could also log the smite git hash used for the campaign, so the user can rebuild the image from that commit to reproduce the same results.

}

let run_args = docker_run_args(&state.image, state.target, parent, &basename, args.attach);
log::info!(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This log should come before let run_args...

Comment on lines +188 to +196
let parent = PathBuf::from("/tmp");
let args = docker_run_args("myimage", Target::Ldk, &parent, "in", false);
let image_pos = args.iter().position(|a| a == "myimage").unwrap();
let v_pos = args.iter().position(|a| a == "-v").unwrap();
let e_pos = args.iter().position(|a| a == "-e").unwrap();
assert!(v_pos < image_pos, "-v must appear before image");
assert!(e_pos < image_pos, "-e must appear before image");
assert_eq!(args.last().unwrap(), "/ldk-scenario");
assert!(args.contains(&"--rm".to_string()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: We could define flags upfront, like ["--rm", "-v", "-e"], and then iterate over them to get their positions in args and assert their positions relative to image_pos, this would also allow us to add the attach flag and test both cases

Comment on lines +30 to +32
/// Allocate an interactive TTY so the run can be watched live.
#[arg(long)]
attach: bool,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think we currently have any observable behavior with the -it option? It might be useful in the future, but I don't see any use for it currently. If we do need it later, I think that change should be paired with the change that introduces the relevant use case

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.

2 participants