mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-18 12:48:07 +00:00
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:
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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?;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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)?;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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?;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(|| {
|
||||||
|
@ -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)]
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user