adding {setup_dir} to variable expansion (#417)

## Summary of the Pull Request

Adds a new placeholder {setup_dir} for the setup directory 

## PR Checklist
* [x] Applies to work item: #221
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/onefuzz) and sign the CLI.
* [x] Requires documentation to be updated
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Info on Pull Request

_What does this include?_

## Validation Steps Performed

_How does someone test & validate?_
This commit is contained in:
Cheick Keita
2021-01-12 16:39:59 -08:00
committed by GitHub
parent 2e2ba988ee
commit a89065f882
27 changed files with 145 additions and 30 deletions

View File

@ -15,6 +15,7 @@ The following values are replaced with the specific values at runtime.
(available wherever `input` is available) (available wherever `input` is available)
* `{runtime_dir}`: Path to the runtime directory for the task * `{runtime_dir}`: Path to the runtime directory for the task
* `{tools_dir}`: Path to the task specific `tools` directory * `{tools_dir}`: Path to the task specific `tools` directory
* `{setup_dir}` : Path to the setup directory
## Example ## Example

View File

@ -29,6 +29,7 @@ async fn run_impl(input: String, config: Config) -> Result<()> {
pub fn run(args: &clap::ArgMatches) -> Result<()> { pub fn run(args: &clap::ArgMatches) -> Result<()> {
let target_exe = value_t!(args, "target_exe", PathBuf)?; let target_exe = value_t!(args, "target_exe", PathBuf)?;
let setup_dir = value_t!(args, "setup_dir", PathBuf)?;
let input = value_t!(args, "input", String)?; let input = value_t!(args, "input", String)?;
let target_timeout = value_t!(args, "target_timeout", u64).ok(); let target_timeout = value_t!(args, "target_timeout", u64).ok();
let check_retry_count = value_t!(args, "check_retry_count", u64)?; let check_retry_count = value_t!(args, "check_retry_count", u64)?;
@ -65,6 +66,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(), task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(), instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
setup_dir,
}, },
}; };
@ -77,6 +79,11 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
pub fn args() -> App<'static, 'static> { pub fn args() -> App<'static, 'static> {
SubCommand::with_name("generic-crash-report") SubCommand::with_name("generic-crash-report")
.about("execute a local-only generic crash report") .about("execute a local-only generic crash report")
.arg(
Arg::with_name("setup_dir")
.takes_value(true)
.required(false),
)
.arg( .arg(
Arg::with_name("target_exe") Arg::with_name("target_exe")
.takes_value(true) .takes_value(true)

View File

@ -38,6 +38,7 @@ async fn run_impl(input: String, config: Config) -> Result<()> {
pub fn run(args: &clap::ArgMatches) -> Result<()> { pub fn run(args: &clap::ArgMatches) -> Result<()> {
let target_exe = value_t!(args, "target_exe", PathBuf)?; let target_exe = value_t!(args, "target_exe", PathBuf)?;
let setup_dir = value_t!(args, "setup_dir", PathBuf)?;
let input = value_t!(args, "input", String)?; let input = value_t!(args, "input", String)?;
let result_dir = value_t!(args, "result_dir", String)?; let result_dir = value_t!(args, "result_dir", String)?;
let target_options = args.values_of_lossy("target_options").unwrap_or_default(); let target_options = args.values_of_lossy("target_options").unwrap_or_default();
@ -69,6 +70,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(), task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(), instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
setup_dir,
}, },
}; };
@ -81,6 +83,11 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
pub fn args() -> App<'static, 'static> { pub fn args() -> App<'static, 'static> {
SubCommand::with_name("libfuzzer-coverage") SubCommand::with_name("libfuzzer-coverage")
.about("execute a local-only libfuzzer coverage task") .about("execute a local-only libfuzzer coverage task")
.arg(
Arg::with_name("setup_dir")
.takes_value(true)
.required(false),
)
.arg( .arg(
Arg::with_name("target_exe") Arg::with_name("target_exe")
.takes_value(true) .takes_value(true)

View File

@ -30,6 +30,7 @@ async fn run_impl(input: String, config: Config) -> Result<()> {
pub fn run(args: &clap::ArgMatches) -> Result<()> { pub fn run(args: &clap::ArgMatches) -> Result<()> {
let target_exe = value_t!(args, "target_exe", PathBuf)?; let target_exe = value_t!(args, "target_exe", PathBuf)?;
let setup_dir = value_t!(args, "setup_dir", PathBuf)?;
let input = value_t!(args, "input", String)?; let input = value_t!(args, "input", String)?;
let target_options = args.values_of_lossy("target_options").unwrap_or_default(); let target_options = args.values_of_lossy("target_options").unwrap_or_default();
let mut target_env = HashMap::new(); let mut target_env = HashMap::new();
@ -65,6 +66,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(), task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(), instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
setup_dir,
}, },
}; };
@ -77,6 +79,11 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
pub fn args() -> App<'static, 'static> { pub fn args() -> App<'static, 'static> {
SubCommand::with_name("libfuzzer-crash-report") SubCommand::with_name("libfuzzer-crash-report")
.about("execute a local-only libfuzzer crash report task") .about("execute a local-only libfuzzer crash report task")
.arg(
Arg::with_name("setup_dir")
.takes_value(true)
.required(false),
)
.arg( .arg(
Arg::with_name("target_exe") Arg::with_name("target_exe")
.takes_value(true) .takes_value(true)

View File

@ -25,6 +25,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
let crashes_dir = value_t!(args, "crashes_dir", String)?; let crashes_dir = value_t!(args, "crashes_dir", String)?;
let inputs_dir = value_t!(args, "inputs_dir", String)?; let inputs_dir = value_t!(args, "inputs_dir", String)?;
let target_exe = value_t!(args, "target_exe", PathBuf)?; let target_exe = value_t!(args, "target_exe", PathBuf)?;
let setup_dir = value_t!(args, "setup_dir", PathBuf)?;
let target_options = args.values_of_lossy("target_options").unwrap_or_default(); let target_options = args.values_of_lossy("target_options").unwrap_or_default();
// this happens during setup, not during runtime // this happens during setup, not during runtime
@ -71,6 +72,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(), task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(), instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
setup_dir,
}, },
}; };
@ -83,6 +85,11 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
pub fn args() -> App<'static, 'static> { pub fn args() -> App<'static, 'static> {
SubCommand::with_name("libfuzzer-fuzz") SubCommand::with_name("libfuzzer-fuzz")
.about("execute a local-only libfuzzer crash report task") .about("execute a local-only libfuzzer crash report task")
.arg(
Arg::with_name("setup_dir")
.takes_value(true)
.required(false),
)
.arg( .arg(
Arg::with_name("target_exe") Arg::with_name("target_exe")
.takes_value(true) .takes_value(true)

View File

@ -16,6 +16,7 @@ use uuid::Uuid;
pub fn run(args: &clap::ArgMatches) -> Result<()> { pub fn run(args: &clap::ArgMatches) -> Result<()> {
let target_exe = value_t!(args, "target_exe", PathBuf)?; let target_exe = value_t!(args, "target_exe", PathBuf)?;
let setup_dir = value_t!(args, "setup_dir", PathBuf)?;
let inputs = value_t!(args, "inputs", String)?; let inputs = value_t!(args, "inputs", String)?;
let unique_inputs = value_t!(args, "unique_inputs", String)?; let unique_inputs = value_t!(args, "unique_inputs", String)?;
let target_options = args.values_of_lossy("target_options").unwrap_or_default(); let target_options = args.values_of_lossy("target_options").unwrap_or_default();
@ -50,6 +51,7 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), job_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(), task_id: Uuid::parse_str("11111111-1111-1111-1111-111111111111").unwrap(),
instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(), instance_id: Uuid::parse_str("22222222-2222-2222-2222-222222222222").unwrap(),
setup_dir,
}, },
preserve_existing_outputs: true, preserve_existing_outputs: true,
}); });
@ -66,6 +68,11 @@ pub fn run(args: &clap::ArgMatches) -> Result<()> {
pub fn args() -> App<'static, 'static> { pub fn args() -> App<'static, 'static> {
SubCommand::with_name("libfuzzer-merge") SubCommand::with_name("libfuzzer-merge")
.about("execute a local-only libfuzzer merge task") .about("execute a local-only libfuzzer merge task")
.arg(
Arg::with_name("setup_dir")
.takes_value(true)
.required(false),
)
.arg( .arg(
Arg::with_name("target_exe") Arg::with_name("target_exe")
.takes_value(true) .takes_value(true)

View File

@ -39,6 +39,12 @@ fn main() -> Result<()> {
.short("c") .short("c")
.takes_value(true), .takes_value(true),
) )
.arg(
Arg::with_name("setup_dir")
.long("setup_dir")
.short("s")
.takes_value(true),
)
.subcommand(debug::cmd::args()) .subcommand(debug::cmd::args())
.subcommand(SubCommand::with_name("licenses").about("display third-party licenses")); .subcommand(SubCommand::with_name("licenses").about("display third-party licenses"));
@ -58,7 +64,8 @@ fn main() -> Result<()> {
} }
let config_path: PathBuf = matches.value_of("config").unwrap().parse()?; let config_path: PathBuf = matches.value_of("config").unwrap().parse()?;
let config = Config::from_file(config_path)?; let setup_dir = matches.value_of("setup_dir");
let config = Config::from_file(config_path, setup_dir)?;
init_telemetry(&config); init_telemetry(&config);

View File

@ -121,7 +121,8 @@ pub async fn run_tool(input: impl AsRef<Path>, config: &Config) -> Result<()> {
.target_options(&config.target_options) .target_options(&config.target_options)
.analyzer_exe(&config.analyzer_exe) .analyzer_exe(&config.analyzer_exe)
.analyzer_options(&config.analyzer_options) .analyzer_options(&config.analyzer_options)
.output_dir(&config.analysis.path); .output_dir(&config.analysis.path)
.setup_dir(&config.common.setup_dir);
let analyzer_path = Expand::new() let analyzer_path = Expand::new()
.tools_dir(&config.tools.path) .tools_dir(&config.tools.path)

View File

@ -10,7 +10,7 @@ use onefuzz::{
}; };
use reqwest::Url; use reqwest::Url;
use serde::{self, Deserialize}; use serde::{self, Deserialize};
use std::path::Path; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use uuid::Uuid; use uuid::Uuid;
@ -33,6 +33,8 @@ pub struct CommonConfig {
pub heartbeat_queue: Option<Url>, pub heartbeat_queue: Option<Url>,
pub telemetry_key: Option<Uuid>, pub telemetry_key: Option<Uuid>,
pub setup_dir: PathBuf,
} }
impl CommonConfig { impl CommonConfig {
@ -79,9 +81,16 @@ pub enum Config {
} }
impl Config { impl Config {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self> { pub fn from_file(path: impl AsRef<Path>, setup_dir: Option<impl AsRef<Path>>) -> Result<Self> {
let json = std::fs::read_to_string(path)?; let json = std::fs::read_to_string(path)?;
Ok(serde_json::from_str(&json)?) let mut json_config: serde_json::Value = serde_json::from_str(&json)?;
// override the setup_dir in the config file with the parameter value if specified
if let Some(setup_dir) = setup_dir {
json_config["setup_dir"] =
serde_json::Value::String(setup_dir.as_ref().to_string_lossy().into());
}
Ok(serde_json::from_value(json_config)?)
} }
pub fn common(&self) -> &CommonConfig { pub fn common(&self) -> &CommonConfig {

View File

@ -104,6 +104,7 @@ impl CoverageTask {
&self.config.target_exe, &self.config.target_exe,
&self.config.target_options, &self.config.target_options,
&self.config.target_env, &self.config.target_env,
&self.config.common.setup_dir,
); );
target.check_help().await?; target.check_help().await?;
} }

View File

@ -66,6 +66,7 @@ pub async fn spawn(config: Arc<GeneratorConfig>) -> Result<(), Error> {
let sync_task = continuous_sync(&config.readonly_inputs, Pull, config.ensemble_sync_delay); let sync_task = continuous_sync(&config.readonly_inputs, Pull, config.ensemble_sync_delay);
let crash_dir_monitor = config.crashes.monitor_results(new_result); let crash_dir_monitor = config.crashes.monitor_results(new_result);
let tester = Tester::new( let tester = Tester::new(
&config.common.setup_dir,
&config.target_exe, &config.target_exe,
&config.target_options, &config.target_options,
&config.target_env, &config.target_env,

View File

@ -72,6 +72,7 @@ impl LibFuzzerFuzzTask {
&self.config.target_exe, &self.config.target_exe,
&self.config.target_options, &self.config.target_options,
&self.config.target_env, &self.config.target_env,
&self.config.common.setup_dir,
); );
target.check_help().await?; target.check_help().await?;
} }
@ -156,6 +157,7 @@ impl LibFuzzerFuzzTask {
&self.config.target_exe, &self.config.target_exe,
&self.config.target_options, &self.config.target_options,
&self.config.target_env, &self.config.target_env,
&self.config.common.setup_dir,
); );
let mut running = fuzzer.fuzz(crash_dir.path(), local_inputs, &inputs)?; let mut running = fuzzer.fuzz(crash_dir.path(), local_inputs, &inputs)?;

View File

@ -102,6 +102,7 @@ pub async fn spawn(config: SupervisorConfig) -> Result<(), Error> {
&config.supervisor_options, &config.supervisor_options,
&config.supervisor_env, &config.supervisor_env,
&config.supervisor_input_marker, &config.supervisor_input_marker,
&config.common.setup_dir,
) )
.await?; .await?;
@ -156,6 +157,7 @@ async fn start_supervisor(
supervisor_options: &[String], supervisor_options: &[String],
supervisor_env: &HashMap<String, String>, supervisor_env: &HashMap<String, String>,
supervisor_input_marker: &Option<String>, supervisor_input_marker: &Option<String>,
setup_dir: impl AsRef<Path>,
) -> Result<Child> { ) -> Result<Child> {
let mut cmd = Command::new(supervisor_path.as_ref()); let mut cmd = Command::new(supervisor_path.as_ref());
@ -173,7 +175,8 @@ async fn start_supervisor(
.runtime_dir(runtime_dir) .runtime_dir(runtime_dir)
.target_exe(target_exe) .target_exe(target_exe)
.target_options(target_options) .target_options(target_options)
.input_corpus(inputs_dir); .input_corpus(inputs_dir)
.setup_dir(setup_dir);
if let Some(input_marker) = supervisor_input_marker { if let Some(input_marker) = supervisor_input_marker {
expand.input_marker(input_marker); expand.input_marker(input_marker);
@ -276,6 +279,7 @@ mod tests {
&supervisor_options, &supervisor_options,
&supervisor_env, &supervisor_env,
&supervisor_input_marker, &supervisor_input_marker,
None,
) )
.await .await
.unwrap(); .unwrap();

View File

@ -138,7 +138,8 @@ async fn merge(config: &Config, output_dir: impl AsRef<Path>) -> Result<()> {
.supervisor_exe(&config.supervisor_exe) .supervisor_exe(&config.supervisor_exe)
.supervisor_options(&config.supervisor_options) .supervisor_options(&config.supervisor_options)
.generated_inputs(output_dir) .generated_inputs(output_dir)
.target_exe(&config.target_exe); .target_exe(&config.target_exe)
.setup_dir(&config.common.setup_dir);
if config.target_options_merge { if config.target_options_merge {
supervisor_args.target_options(&config.target_options); supervisor_args.target_options(&config.target_options);

View File

@ -52,6 +52,7 @@ pub async fn spawn(config: Arc<Config>) -> Result<()> {
&config.target_exe, &config.target_exe,
&config.target_options, &config.target_options,
&config.target_env, &config.target_env,
&config.common.setup_dir,
); );
target.check_help().await?; target.check_help().await?;
} }
@ -162,6 +163,7 @@ pub async fn merge_inputs(
&config.target_exe, &config.target_exe,
&config.target_options, &config.target_options,
&config.target_env, &config.target_env,
&config.common.setup_dir,
); );
merger.merge(&config.unique_inputs.path, &candidates).await merger.merge(&config.unique_inputs.path, &candidates).await
} }

View File

@ -87,6 +87,7 @@ pub struct GenericReportProcessor<'a> {
impl<'a> GenericReportProcessor<'a> { impl<'a> GenericReportProcessor<'a> {
pub fn new(config: &'a Config, heartbeat_client: Option<TaskHeartbeatClient>) -> Self { pub fn new(config: &'a Config, heartbeat_client: Option<TaskHeartbeatClient>) -> Self {
let tester = Tester::new( let tester = Tester::new(
&config.common.setup_dir,
&config.target_exe, &config.target_exe,
&config.target_options, &config.target_options,
&config.target_env, &config.target_env,

View File

@ -61,6 +61,7 @@ impl ReportTask {
&self.config.target_exe, &self.config.target_exe,
&self.config.target_options, &self.config.target_options,
&self.config.target_env, &self.config.target_env,
&self.config.common.setup_dir,
); );
target.check_help().await?; target.check_help().await?;
} }
@ -101,6 +102,7 @@ impl AsanProcessor {
&self.config.target_exe, &self.config.target_exe,
&self.config.target_options, &self.config.target_options,
&self.config.target_env, &self.config.target_env,
&self.config.common.setup_dir,
); );
let task_id = self.config.common.task_id; let task_id = self.config.common.task_id;

View File

@ -180,8 +180,9 @@ async fn run_worker(mut work_set: WorkSet) -> Result<Vec<WorkerEvent>> {
let mut events = vec![]; let mut events = vec![];
let work_unit = work_set.work_units.pop().unwrap(); let work_unit = work_set.work_units.pop().unwrap();
let setup_dir = work_set.setup_dir()?;
let mut worker = Worker::new(work_unit); let mut worker = Worker::new(&setup_dir, work_unit);
while !worker.is_done() { while !worker.is_done() {
worker = worker.update(&mut events, &mut WorkerRunner).await?; worker = worker.update(&mut events, &mut WorkerRunner).await?;
} }

View File

@ -224,9 +224,9 @@ impl State<PendingReboot> {
impl State<Ready> { impl State<Ready> {
pub async fn run(self) -> Result<State<Busy>> { pub async fn run(self) -> Result<State<Busy>> {
let mut workers = vec![]; let mut workers = vec![];
let setup_dir = self.ctx.work_set.setup_dir()?;
for work in self.ctx.work_set.work_units { for work in self.ctx.work_set.work_units {
let worker = Some(Worker::new(work)); let worker = Some(Worker::new(&setup_dir, work));
workers.push(worker); workers.push(worker);
} }

View File

@ -42,10 +42,7 @@ impl SetupRunner {
// Download the setup container. // Download the setup container.
let setup_url = work_set.setup_url.url(); let setup_url = work_set.setup_url.url();
let setup_dir = work_set.setup_url.container(); let setup_dir = work_set.setup_dir()?;
let setup_dir = onefuzz::fs::onefuzz_root()?
.join("blob-containers")
.join(setup_dir);
// `azcopy sync` requires the local dir to exist. // `azcopy sync` requires the local dir to exist.
fs::create_dir_all(&setup_dir).await.with_context(|| { fs::create_dir_all(&setup_dir).await.with_context(|| {

View File

@ -69,6 +69,13 @@ impl WorkSet {
Ok(()) Ok(())
} }
pub fn setup_dir(&self) -> Result<PathBuf> {
let setup_dir = self.setup_url.container();
Ok(onefuzz::fs::onefuzz_root()?
.join("blob-containers")
.join(setup_dir))
}
} }
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]

View File

@ -1,7 +1,10 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use std::process::{Child, Command, Stdio}; use std::{
path::{Path, PathBuf},
process::{Child, Command, Stdio},
};
use anyhow::{Context as AnyhowContext, Result}; use anyhow::{Context as AnyhowContext, Result};
use downcast_rs::Downcast; use downcast_rs::Downcast;
@ -31,8 +34,10 @@ pub enum Worker {
} }
impl Worker { impl Worker {
pub fn new(work: WorkUnit) -> Self { pub fn new(setup_dir: impl AsRef<Path>, work: WorkUnit) -> Self {
let ctx = Ready; let ctx = Ready {
setup_dir: PathBuf::from(setup_dir.as_ref()),
};
let state = State { ctx, work }; let state = State { ctx, work };
state.into() state.into()
} }
@ -79,7 +84,9 @@ impl Worker {
} }
} }
pub struct Ready; pub struct Ready {
setup_dir: PathBuf,
}
pub struct Running { pub struct Running {
child: Box<dyn IWorkerChild>, child: Box<dyn IWorkerChild>,
@ -108,7 +115,7 @@ impl<C: Context> State<C> {
impl State<Ready> { impl State<Ready> {
pub async fn run(self, runner: &mut dyn IWorkerRunner) -> Result<State<Running>> { pub async fn run(self, runner: &mut dyn IWorkerRunner) -> Result<State<Running>> {
let child = runner.run(&self.work).await?; let child = runner.run(&self.ctx.setup_dir, &self.work).await?;
let state = State { let state = State {
ctx: Running { child }, ctx: Running { child },
@ -167,7 +174,7 @@ impl_from_state_for_worker!(Done);
#[async_trait] #[async_trait]
pub trait IWorkerRunner: Downcast { pub trait IWorkerRunner: Downcast {
async fn run(&mut self, work: &WorkUnit) -> Result<Box<dyn IWorkerChild>>; async fn run(&mut self, setup_dir: &Path, work: &WorkUnit) -> Result<Box<dyn IWorkerChild>>;
} }
impl_downcast!(IWorkerRunner); impl_downcast!(IWorkerRunner);
@ -184,7 +191,7 @@ pub struct WorkerRunner;
#[async_trait] #[async_trait]
impl IWorkerRunner for WorkerRunner { impl IWorkerRunner for WorkerRunner {
async fn run(&mut self, work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> { async fn run(&mut self, setup_dir: &Path, work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> {
let working_dir = work.working_dir()?; let working_dir = work.working_dir()?;
verbose!("worker working dir = {}", working_dir.display()); verbose!("worker working dir = {}", working_dir.display());
@ -220,6 +227,8 @@ impl IWorkerRunner for WorkerRunner {
cmd.current_dir(&working_dir); cmd.current_dir(&working_dir);
cmd.arg("-c"); cmd.arg("-c");
cmd.arg("config.json"); cmd.arg("config.json");
cmd.arg("-s");
cmd.arg(setup_dir);
cmd.stderr(Stdio::piped()); cmd.stderr(Stdio::piped());
cmd.stdout(Stdio::piped()); cmd.stdout(Stdio::piped());

View File

@ -10,7 +10,7 @@ pub struct WorkerRunnerDouble {
#[async_trait] #[async_trait]
impl IWorkerRunner for WorkerRunnerDouble { impl IWorkerRunner for WorkerRunnerDouble {
async fn run(&mut self, _work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> { async fn run(&mut self, _setup_dir: &Path, _work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> {
Ok(Box::new(self.child.clone())) Ok(Box::new(self.child.clone()))
} }
} }

View File

@ -55,7 +55,7 @@ struct RunnerDouble {
#[async_trait] #[async_trait]
impl IWorkerRunner for RunnerDouble { impl IWorkerRunner for RunnerDouble {
async fn run(&mut self, _work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> { async fn run(&mut self, _setup_dir: &Path, _work: &WorkUnit) -> Result<Box<dyn IWorkerChild>> {
Ok(Box::new(self.child.clone())) Ok(Box::new(self.child.clone()))
} }
} }
@ -64,7 +64,9 @@ impl IWorkerRunner for RunnerDouble {
async fn test_ready_run() { async fn test_ready_run() {
let mut runner = Fixture.runner(Fixture.child_running()); let mut runner = Fixture.runner(Fixture.child_running());
let state = State { let state = State {
ctx: Ready, ctx: Ready {
setup_dir: PathBuf::default(),
},
work: Fixture.work(), work: Fixture.work(),
}; };
@ -144,7 +146,9 @@ async fn test_worker_ready_update() {
let task_id = Fixture.work().task_id; let task_id = Fixture.work().task_id;
let state = State { let state = State {
ctx: Ready, ctx: Ready {
setup_dir: PathBuf::default(),
},
work: Fixture.work(), work: Fixture.work(),
}; };
let worker = Worker::Ready(state); let worker = Worker::Ready(state);

View File

@ -33,6 +33,7 @@ pub enum PlaceHolder {
GeneratorOptions, GeneratorOptions,
SupervisorExe, SupervisorExe,
SupervisorOptions, SupervisorOptions,
SetupDir,
} }
impl PlaceHolder { impl PlaceHolder {
@ -55,6 +56,7 @@ impl PlaceHolder {
Self::GeneratorOptions => "{generator_options}", Self::GeneratorOptions => "{generator_options}",
Self::SupervisorExe => "{supervisor_exe}", Self::SupervisorExe => "{supervisor_exe}",
Self::SupervisorOptions => "{supervisor_options}", Self::SupervisorOptions => "{supervisor_options}",
Self::SetupDir => "{setup_dir}",
} }
.to_string() .to_string()
} }
@ -215,6 +217,13 @@ impl<'a> Expand<'a> {
self self
} }
pub fn setup_dir(&mut self, arg: impl AsRef<Path>) -> &mut Self {
let arg = arg.as_ref();
let path = String::from(arg.to_string_lossy());
self.set_value(PlaceHolder::SetupDir, ExpandedValue::Path(path));
self
}
fn replace_value( fn replace_value(
&self, &self,
fmtstr: &str, fmtstr: &str,

View File

@ -16,6 +16,7 @@ const DEFAULT_TIMEOUT_SECS: u64 = 5;
const CRASH_SITE_UNAVAILABLE: &str = "<crash site unavailable>"; const CRASH_SITE_UNAVAILABLE: &str = "<crash site unavailable>";
pub struct Tester<'a> { pub struct Tester<'a> {
setup_dir: &'a Path,
exe_path: &'a Path, exe_path: &'a Path,
arguments: &'a [String], arguments: &'a [String],
environ: &'a HashMap<String, String>, environ: &'a HashMap<String, String>,
@ -42,6 +43,7 @@ pub struct TestResult {
impl<'a> Tester<'a> { impl<'a> Tester<'a> {
pub fn new( pub fn new(
setup_dir: &'a Path,
exe_path: &'a Path, exe_path: &'a Path,
arguments: &'a [String], arguments: &'a [String],
environ: &'a HashMap<String, String>, environ: &'a HashMap<String, String>,
@ -53,6 +55,7 @@ impl<'a> Tester<'a> {
) -> Self { ) -> Self {
let timeout = Duration::from_secs(timeout.unwrap_or(DEFAULT_TIMEOUT_SECS)); let timeout = Duration::from_secs(timeout.unwrap_or(DEFAULT_TIMEOUT_SECS));
Self { Self {
setup_dir,
exe_path, exe_path,
arguments, arguments,
environ, environ,
@ -193,6 +196,8 @@ impl<'a> Tester<'a> {
.target_exe(&self.exe_path) .target_exe(&self.exe_path)
.target_options(&self.arguments); .target_options(&self.arguments);
expand.setup_dir(&self.setup_dir);
let argv = expand.evaluate(&self.arguments)?; let argv = expand.evaluate(&self.arguments)?;
let mut env: HashMap<String, String> = HashMap::new(); let mut env: HashMap<String, String> = HashMap::new();
for (k, v) in self.environ { for (k, v) in self.environ {
@ -218,7 +223,7 @@ impl<'a> Tester<'a> {
Err(error) => (None, Some(error), None), Err(error) => (None, Some(error), None),
} }
} else { } else {
match run_cmd(self.exe_path, argv.clone(), &env, self.timeout).await { match run_cmd(&self.exe_path, argv.clone(), &env, self.timeout).await {
Ok(output) => (None, None, Some(output)), Ok(output) => (None, None, Some(output)),
Err(error) => (None, Some(error), None), Err(error) => (None, Some(error), None),
} }

View File

@ -22,6 +22,7 @@ pub struct LibFuzzerMergeOutput {
} }
pub struct LibFuzzer<'a> { pub struct LibFuzzer<'a> {
setup_dir: PathBuf,
exe: PathBuf, exe: PathBuf,
options: &'a [String], options: &'a [String],
env: &'a HashMap<String, String>, env: &'a HashMap<String, String>,
@ -32,11 +33,13 @@ impl<'a> LibFuzzer<'a> {
exe: impl Into<PathBuf>, exe: impl Into<PathBuf>,
options: &'a [String], options: &'a [String],
env: &'a HashMap<String, String>, env: &'a HashMap<String, String>,
setup_dir: impl Into<PathBuf>,
) -> Self { ) -> Self {
Self { Self {
exe: exe.into(), exe: exe.into(),
options, options,
env, env,
setup_dir: setup_dir.into(),
} }
} }
@ -53,7 +56,10 @@ impl<'a> LibFuzzer<'a> {
.arg("-help=1"); .arg("-help=1");
let mut expand = Expand::new(); let mut expand = Expand::new();
expand.target_exe(&self.exe).target_options(&self.options); expand
.target_exe(&self.exe)
.target_options(&self.options)
.setup_dir(&self.setup_dir);
for (k, v) in self.env { for (k, v) in self.env {
cmd.env(k, expand.evaluate_value(v)?); cmd.env(k, expand.evaluate_value(v)?);
@ -85,7 +91,8 @@ impl<'a> LibFuzzer<'a> {
.target_exe(&self.exe) .target_exe(&self.exe)
.target_options(&self.options) .target_options(&self.options)
.input_corpus(&corpus_dir) .input_corpus(&corpus_dir)
.crashes(&fault_dir); .crashes(&fault_dir)
.setup_dir(&self.setup_dir);
let mut cmd = Command::new(&self.exe); let mut cmd = Command::new(&self.exe);
cmd.kill_on_drop(true) cmd.kill_on_drop(true)
@ -148,7 +155,15 @@ impl<'a> LibFuzzer<'a> {
options.push("{input}".to_string()); options.push("{input}".to_string());
let tester = Tester::new( let tester = Tester::new(
&self.exe, &options, &self.env, &timeout, false, true, false, retry, &self.setup_dir,
&self.exe,
&options,
&self.env,
&timeout,
false,
true,
false,
retry,
); );
tester.test_input(test_input.as_ref()).await tester.test_input(test_input.as_ref()).await
} }
@ -162,7 +177,8 @@ impl<'a> LibFuzzer<'a> {
expand expand
.target_exe(&self.exe) .target_exe(&self.exe)
.target_options(&self.options) .target_options(&self.options)
.input_corpus(&corpus_dir); .input_corpus(&corpus_dir)
.setup_dir(&self.setup_dir);
let mut cmd = Command::new(&self.exe); let mut cmd = Command::new(&self.exe);