mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-17 20:38:06 +00:00
add libfuzzer regression tasks to local fuzzing (#744)
This commit is contained in:
@ -10,7 +10,7 @@ use tokio::time::timeout;
|
||||
use crate::local::{
|
||||
common::add_common_config, generic_analysis, generic_crash_report, generic_generator,
|
||||
libfuzzer, libfuzzer_coverage, libfuzzer_crash_report, libfuzzer_fuzz, libfuzzer_merge,
|
||||
libfuzzer_test_input, radamsa, test_input,
|
||||
libfuzzer_regression, libfuzzer_test_input, radamsa, test_input,
|
||||
};
|
||||
|
||||
const RADAMSA: &str = "radamsa";
|
||||
@ -20,6 +20,7 @@ const LIBFUZZER_CRASH_REPORT: &str = "libfuzzer-crash-report";
|
||||
const LIBFUZZER_COVERAGE: &str = "libfuzzer-coverage";
|
||||
const LIBFUZZER_MERGE: &str = "libfuzzer-merge";
|
||||
const LIBFUZZER_TEST_INPUT: &str = "libfuzzer-test-input";
|
||||
const LIBFUZZER_REGRESSION: &str = "libfuzzer-regression";
|
||||
const GENERIC_CRASH_REPORT: &str = "crash-report";
|
||||
const GENERIC_GENERATOR: &str = "generator";
|
||||
const GENERIC_ANALYSIS: &str = "analysis";
|
||||
@ -43,6 +44,7 @@ pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
(GENERIC_GENERATOR, Some(sub)) => generic_generator::run(sub).await,
|
||||
(GENERIC_TEST_INPUT, Some(sub)) => test_input::run(sub).await,
|
||||
(LIBFUZZER_TEST_INPUT, Some(sub)) => libfuzzer_test_input::run(sub).await,
|
||||
(LIBFUZZER_REGRESSION, Some(sub)) => libfuzzer_regression::run(sub).await,
|
||||
_ => {
|
||||
anyhow::bail!("missing subcommand\nUSAGE: {}", args.usage());
|
||||
}
|
||||
@ -78,6 +80,9 @@ pub fn args(name: &str) -> App<'static, 'static> {
|
||||
LIBFUZZER_COVERAGE,
|
||||
)))
|
||||
.subcommand(add_common_config(libfuzzer_merge::args(LIBFUZZER_MERGE)))
|
||||
.subcommand(add_common_config(libfuzzer_regression::args(
|
||||
LIBFUZZER_REGRESSION,
|
||||
)))
|
||||
.subcommand(add_common_config(libfuzzer_crash_report::args(
|
||||
LIBFUZZER_CRASH_REPORT,
|
||||
)))
|
||||
|
@ -33,6 +33,7 @@ pub const TOOLS_DIR: &str = "tools_dir";
|
||||
pub const RENAME_OUTPUT: &str = "rename_output";
|
||||
pub const CHECK_FUZZER_HELP: &str = "check_fuzzer_help";
|
||||
pub const DISABLE_CHECK_DEBUGGER: &str = "disable_check_debugger";
|
||||
pub const REGRESSION_REPORTS_DIR: &str = "regression_reports_dir";
|
||||
|
||||
pub const TARGET_EXE: &str = "target_exe";
|
||||
pub const TARGET_ENV: &str = "target_env";
|
||||
|
@ -5,17 +5,20 @@ use crate::{
|
||||
local::{
|
||||
common::{
|
||||
build_common_config, wait_for_dir, DirectoryMonitorQueue, ANALYZER_EXE, COVERAGE_DIR,
|
||||
UNIQUE_REPORTS_DIR,
|
||||
REGRESSION_REPORTS_DIR, UNIQUE_REPORTS_DIR,
|
||||
},
|
||||
generic_analysis::{build_analysis_config, build_shared_args as build_analysis_args},
|
||||
libfuzzer_coverage::{build_coverage_config, build_shared_args as build_coverage_args},
|
||||
libfuzzer_crash_report::{build_report_config, build_shared_args as build_crash_args},
|
||||
libfuzzer_fuzz::{build_fuzz_config, build_shared_args as build_fuzz_args},
|
||||
libfuzzer_regression::{
|
||||
build_regression_config, build_shared_args as build_regression_args,
|
||||
},
|
||||
},
|
||||
tasks::{
|
||||
analysis::generic::run as run_analysis, config::CommonConfig,
|
||||
coverage::libfuzzer_coverage::CoverageTask, fuzz::libfuzzer_fuzz::LibFuzzerFuzzTask,
|
||||
report::libfuzzer_report::ReportTask,
|
||||
regression::libfuzzer::LibFuzzerRegressionTask, report::libfuzzer_report::ReportTask,
|
||||
},
|
||||
};
|
||||
use anyhow::Result;
|
||||
@ -87,7 +90,7 @@ pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
Some(analysis_input_monitor.queue_client),
|
||||
CommonConfig {
|
||||
task_id: Uuid::new_v4(),
|
||||
..common
|
||||
..common.clone()
|
||||
},
|
||||
)?;
|
||||
let analysis_task = spawn(async move { run_analysis(analysis_config).await });
|
||||
@ -96,6 +99,19 @@ pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
task_handles.push(analysis_input_monitor.handle);
|
||||
}
|
||||
|
||||
if args.is_present(REGRESSION_REPORTS_DIR) {
|
||||
let regression_config = build_regression_config(
|
||||
args,
|
||||
CommonConfig {
|
||||
task_id: Uuid::new_v4(),
|
||||
..common
|
||||
},
|
||||
)?;
|
||||
let regression = LibFuzzerRegressionTask::new(regression_config);
|
||||
let regression_task = spawn(async move { regression.run().await });
|
||||
task_handles.push(regression_task);
|
||||
}
|
||||
|
||||
try_wait_all_join_handles(task_handles).await?;
|
||||
|
||||
Ok(())
|
||||
@ -110,6 +126,7 @@ pub fn args(name: &'static str) -> App<'static, 'static> {
|
||||
build_crash_args(),
|
||||
build_analysis_args(false),
|
||||
build_coverage_args(true),
|
||||
build_regression_args(false),
|
||||
] {
|
||||
for arg in args {
|
||||
if used.contains(arg.b.name) {
|
||||
|
138
src/agent/onefuzz-agent/src/local/libfuzzer_regression.rs
Normal file
138
src/agent/onefuzz-agent/src/local/libfuzzer_regression.rs
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
use crate::{
|
||||
local::common::{
|
||||
build_common_config, get_cmd_arg, get_cmd_env, get_cmd_exe, get_synced_dir, CmdType,
|
||||
CHECK_FUZZER_HELP, CHECK_RETRY_COUNT, COVERAGE_DIR, CRASHES_DIR, NO_REPRO_DIR,
|
||||
REGRESSION_REPORTS_DIR, REPORTS_DIR, TARGET_ENV, TARGET_EXE, TARGET_OPTIONS,
|
||||
TARGET_TIMEOUT, UNIQUE_REPORTS_DIR,
|
||||
},
|
||||
tasks::{
|
||||
config::CommonConfig,
|
||||
regression::libfuzzer::{Config, LibFuzzerRegressionTask},
|
||||
},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use clap::{App, Arg, SubCommand};
|
||||
|
||||
const REPORT_NAMES: &str = "report_names";
|
||||
|
||||
pub fn build_regression_config(
|
||||
args: &clap::ArgMatches<'_>,
|
||||
common: CommonConfig,
|
||||
) -> Result<Config> {
|
||||
let target_exe = get_cmd_exe(CmdType::Target, args)?.into();
|
||||
let target_env = get_cmd_env(CmdType::Target, args)?;
|
||||
let target_options = get_cmd_arg(CmdType::Target, args);
|
||||
let target_timeout = value_t!(args, TARGET_TIMEOUT, u64).ok();
|
||||
let crashes = get_synced_dir(CRASHES_DIR, common.job_id, common.task_id, args)?;
|
||||
let regression_reports =
|
||||
get_synced_dir(REGRESSION_REPORTS_DIR, common.job_id, common.task_id, args)?;
|
||||
let check_retry_count = value_t!(args, CHECK_RETRY_COUNT, u64)?;
|
||||
|
||||
let reports = get_synced_dir(REPORTS_DIR, common.job_id, common.task_id, args).ok();
|
||||
let no_repro = get_synced_dir(NO_REPRO_DIR, common.job_id, common.task_id, args).ok();
|
||||
let unique_reports =
|
||||
get_synced_dir(UNIQUE_REPORTS_DIR, common.job_id, common.task_id, args).ok();
|
||||
|
||||
let report_list = if args.is_present(REPORT_NAMES) {
|
||||
Some(values_t!(args, REPORT_NAMES, String)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let check_fuzzer_help = args.is_present(CHECK_FUZZER_HELP);
|
||||
|
||||
let config = Config {
|
||||
target_exe,
|
||||
target_env,
|
||||
target_options,
|
||||
target_timeout,
|
||||
check_fuzzer_help,
|
||||
check_retry_count,
|
||||
crashes,
|
||||
regression_reports,
|
||||
reports,
|
||||
no_repro,
|
||||
unique_reports,
|
||||
readonly_inputs: None,
|
||||
report_list,
|
||||
minimized_stack_depth: None,
|
||||
common,
|
||||
};
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub async fn run(args: &clap::ArgMatches<'_>) -> Result<()> {
|
||||
let common = build_common_config(args, true)?;
|
||||
let config = build_regression_config(args, common)?;
|
||||
LibFuzzerRegressionTask::new(config).run().await
|
||||
}
|
||||
|
||||
pub fn build_shared_args(local_job: bool) -> Vec<Arg<'static, 'static>> {
|
||||
let mut args = vec![
|
||||
Arg::with_name(TARGET_EXE)
|
||||
.long(TARGET_EXE)
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
Arg::with_name(TARGET_ENV)
|
||||
.long(TARGET_ENV)
|
||||
.takes_value(true)
|
||||
.multiple(true),
|
||||
Arg::with_name(TARGET_OPTIONS)
|
||||
.long(TARGET_OPTIONS)
|
||||
.takes_value(true)
|
||||
.value_delimiter(" ")
|
||||
.help("Use a quoted string with space separation to denote multiple arguments"),
|
||||
Arg::with_name(COVERAGE_DIR)
|
||||
.takes_value(true)
|
||||
.required(!local_job)
|
||||
.long(COVERAGE_DIR),
|
||||
Arg::with_name(CHECK_FUZZER_HELP)
|
||||
.takes_value(false)
|
||||
.long(CHECK_FUZZER_HELP),
|
||||
Arg::with_name(TARGET_TIMEOUT)
|
||||
.takes_value(true)
|
||||
.long(TARGET_TIMEOUT),
|
||||
Arg::with_name(CRASHES_DIR)
|
||||
.long(CRASHES_DIR)
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
Arg::with_name(REGRESSION_REPORTS_DIR)
|
||||
.long(REGRESSION_REPORTS_DIR)
|
||||
.takes_value(true)
|
||||
.required(local_job),
|
||||
Arg::with_name(REPORTS_DIR)
|
||||
.long(REPORTS_DIR)
|
||||
.takes_value(true)
|
||||
.required(false),
|
||||
Arg::with_name(NO_REPRO_DIR)
|
||||
.long(NO_REPRO_DIR)
|
||||
.takes_value(true)
|
||||
.required(false),
|
||||
Arg::with_name(UNIQUE_REPORTS_DIR)
|
||||
.long(UNIQUE_REPORTS_DIR)
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
Arg::with_name(CHECK_RETRY_COUNT)
|
||||
.takes_value(true)
|
||||
.long(CHECK_RETRY_COUNT)
|
||||
.default_value("0"),
|
||||
];
|
||||
if local_job {
|
||||
args.push(
|
||||
Arg::with_name(REPORT_NAMES)
|
||||
.long(REPORT_NAMES)
|
||||
.takes_value(true)
|
||||
.multiple(true),
|
||||
)
|
||||
}
|
||||
args
|
||||
}
|
||||
|
||||
pub fn args(name: &'static str) -> App<'static, 'static> {
|
||||
SubCommand::with_name(name)
|
||||
.about("execute a local-only libfuzzer regression task")
|
||||
.args(&build_shared_args(false))
|
||||
}
|
@ -11,6 +11,7 @@ pub mod libfuzzer_coverage;
|
||||
pub mod libfuzzer_crash_report;
|
||||
pub mod libfuzzer_fuzz;
|
||||
pub mod libfuzzer_merge;
|
||||
pub mod libfuzzer_regression;
|
||||
pub mod libfuzzer_test_input;
|
||||
pub mod radamsa;
|
||||
pub mod test_input;
|
||||
|
@ -32,7 +32,9 @@ pub async fn run(
|
||||
readonly_inputs: &Option<SyncedDir>,
|
||||
handler: &impl RegressionHandler,
|
||||
) -> Result<()> {
|
||||
info!("Starting generic regression task");
|
||||
info!("starting regression task");
|
||||
regression_reports.init().await?;
|
||||
|
||||
handle_crash_reports(
|
||||
handler,
|
||||
crashes,
|
||||
@ -41,7 +43,8 @@ pub async fn run(
|
||||
®ression_reports,
|
||||
&heartbeat_client,
|
||||
)
|
||||
.await?;
|
||||
.await
|
||||
.context("handling crash reports")?;
|
||||
|
||||
if let Some(readonly_inputs) = &readonly_inputs {
|
||||
handle_inputs(
|
||||
@ -50,9 +53,11 @@ pub async fn run(
|
||||
®ression_reports,
|
||||
&heartbeat_client,
|
||||
)
|
||||
.await?;
|
||||
.await
|
||||
.context("handling inputs")?;
|
||||
}
|
||||
|
||||
info!("regression task stopped");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ use crate::tasks::{
|
||||
utils::default_bool_true,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
use reqwest::Url;
|
||||
|
||||
use super::common::{self, RegressionHandler};
|
||||
@ -78,8 +78,6 @@ impl LibFuzzerRegressionTask {
|
||||
}
|
||||
|
||||
pub async fn run(&self) -> Result<()> {
|
||||
info!("Starting libfuzzer regression task");
|
||||
|
||||
let mut report_dirs = vec![];
|
||||
for dir in &[
|
||||
&self.config.reports,
|
||||
@ -101,7 +99,8 @@ impl LibFuzzerRegressionTask {
|
||||
&self.config.readonly_inputs,
|
||||
self,
|
||||
)
|
||||
.await?;
|
||||
.await
|
||||
.context("libfuzzer regression")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user