From c8a8a3e99a803e0fcabcef6b6bd07a36ddf0c318 Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Tue, 4 Jun 2024 16:09:38 +0300 Subject: [PATCH 01/10] Add report accumulation support for `casr-libfuzzer` and `casr-afl` --- casr/Cargo.toml | 2 +- casr/src/bin/casr-afl.rs | 9 +++ casr/src/bin/casr-cluster.rs | 6 +- casr/src/bin/casr-libfuzzer.rs | 9 +++ casr/src/triage.rs | 101 ++++++++++++++++++++---------- casr/src/util.rs | 29 ++++++--- casr/tests/tests.rs | 110 +++++++++++++++++++++++++++++++-- 7 files changed, 214 insertions(+), 52 deletions(-) diff --git a/casr/Cargo.toml b/casr/Cargo.toml index 13494d1e..e85e41cc 100644 --- a/casr/Cargo.toml +++ b/casr/Cargo.toml @@ -37,6 +37,7 @@ tokio = { version = "1", features = ["rt", "macros"], optional = true } toml = { version = "0.8", optional = true } wait-timeout = "0.2" which = "6.0" +copy_dir = "0.1.3" libcasr = { path = "../libcasr", version = "2.12.0", features = ["serde", "exploitable"] } @@ -52,4 +53,3 @@ required-features = ["dojo"] [dev-dependencies] lazy_static = "1.4" -copy_dir = "0.1.3" diff --git a/casr/src/bin/casr-afl.rs b/casr/src/bin/casr-afl.rs index 4ff9e9cd..e71cac2b 100644 --- a/casr/src/bin/casr-afl.rs +++ b/casr/src/bin/casr-afl.rs @@ -75,6 +75,15 @@ fn main() -> Result<()> { .value_parser(clap::value_parser!(PathBuf)) .help("Output directory with triaged reports") ) + .arg( + Arg::new("seed") + .short('s') + .long("seed") + .action(ArgAction::Set) + .value_parser(clap::value_parser!(PathBuf)) + .value_name("SEED_DIR") + .help("Seed directory with previously triaged reports") + ) .arg( Arg::new("force-remove") .short('f') diff --git a/casr/src/bin/casr-cluster.rs b/casr/src/bin/casr-cluster.rs index ae465a23..ce51d048 100644 --- a/casr/src/bin/casr-cluster.rs +++ b/casr/src/bin/casr-cluster.rs @@ -762,11 +762,11 @@ fn main() -> Result<()> { println!("Number of new clusters: {result}"); } // Print crashline dedup summary - if before != 0 { + if dedup_crashlines { println!("Number of reports before crashline deduplication in new clusters: {before}"); - } - if before != after { println!("Number of reports after crashline deduplication in new clusters: {after}"); + } else { + println!("Number of reports in new clusters: {after}"); } let sil = calc_avg_sil(paths[1], jobs)?; println!("Cluster silhouette score: {sil}"); diff --git a/casr/src/bin/casr-libfuzzer.rs b/casr/src/bin/casr-libfuzzer.rs index bb58cfd4..1d79e750 100644 --- a/casr/src/bin/casr-libfuzzer.rs +++ b/casr/src/bin/casr-libfuzzer.rs @@ -74,6 +74,15 @@ fn main() -> Result<()> { .value_name("OUTPUT_DIR") .help("Output directory with triaged reports") ) + .arg( + Arg::new("seed") + .short('s') + .long("seed") + .action(ArgAction::Set) + .value_parser(clap::value_parser!(PathBuf)) + .value_name("SEED_DIR") + .help("Seed directory with previously triaged reports") + ) .arg( Arg::new("force-remove") .short('f') diff --git a/casr/src/triage.rs b/casr/src/triage.rs index 99d59df2..16c4a5cb 100644 --- a/casr/src/triage.rs +++ b/casr/src/triage.rs @@ -159,8 +159,16 @@ pub fn fuzzing_crash_triage_pipeline( bail!("No crashes found"); } + let seed_mode = matches.contains_id("seed"); + let output_dir = initialize_dirs(matches)?; + let casrep_dir = if seed_mode { + output_dir.join("casrep") + } else { + output_dir.to_path_buf() + }; + // Get timeout let timeout = *matches.get_one::("timeout").unwrap(); @@ -189,7 +197,7 @@ pub fn fuzzing_crash_triage_pipeline( .join( || { crashes.par_iter().try_for_each(|(_, crash)| { - if let Err(e) = crash.run_casr(output_dir.as_path(), timeout) { + if let Err(e) = crash.run_casr(casrep_dir.as_path(), timeout) { // Disable util::log_progress *counter.write().unwrap() = total; bail!(e); @@ -210,7 +218,7 @@ pub fn fuzzing_crash_triage_pipeline( info!("Deduplicating CASR reports..."); let casr_cluster_d = Command::new(&casr_cluster) .arg("-d") - .arg(output_dir.clone().into_os_string()) + .arg(casrep_dir.clone().into_os_string()) .output() .with_context(|| format!("Couldn't launch {casr_cluster:?}"))?; @@ -230,41 +238,66 @@ pub fn fuzzing_crash_triage_pipeline( } if !matches.get_flag("no-cluster") { - if output_dir - .read_dir()? - .flatten() - .map(|e| e.path()) - .filter(|e| e.extension().is_some() && e.extension().unwrap() == "casrep") - .count() - < 2 - { - info!("There are less than 2 CASR reports, nothing to cluster."); - return summarize_results(matches, crashes, gdb_args); - } - info!("Clustering CASR reports..."); - let casr_cluster_c = Command::new(&casr_cluster) - .arg("-c") - .arg(output_dir.clone().into_os_string()) - .output() - .with_context(|| format!("Couldn't launch {casr_cluster:?}"))?; + if seed_mode { + info!("Accumulating CASR reports..."); + let casr_cluster_u = Command::new(&casr_cluster) + .arg("-u") + .arg(casrep_dir.clone().into_os_string()) + .arg(output_dir.clone().into_os_string()) + .output() + .with_context(|| format!("Couldn't launch {casr_cluster:?}"))?; + + if casr_cluster_u.status.success() { + info!( + "{}", + String::from_utf8_lossy(&casr_cluster_u.stdout).trim_end() + ); + } else { + error!( + "{}", + String::from_utf8_lossy(&casr_cluster_u.stderr).trim_end() + ); + } - if casr_cluster_c.status.success() { - info!( - "{}", - String::from_utf8_lossy(&casr_cluster_c.stdout).trim_end() - ); + // Remove reports from deduplication phase. They are in clusters now. + fs::remove_dir_all(casrep_dir)?; } else { - error!( - "{}", - String::from_utf8_lossy(&casr_cluster_c.stderr).trim_end() - ); - } + if casrep_dir + .read_dir()? + .flatten() + .map(|e| e.path()) + .filter(|e| e.extension().is_some() && e.extension().unwrap() == "casrep") + .count() + < 2 + { + info!("There are less than 2 CASR reports, nothing to cluster."); + return summarize_results(matches, crashes, gdb_args); + } + info!("Clustering CASR reports..."); + let casr_cluster_c = Command::new(&casr_cluster) + .arg("-c") + .arg(output_dir.clone().into_os_string()) + .output() + .with_context(|| format!("Couldn't launch {casr_cluster:?}"))?; + + if casr_cluster_c.status.success() { + info!( + "{}", + String::from_utf8_lossy(&casr_cluster_c.stdout).trim_end() + ); + } else { + error!( + "{}", + String::from_utf8_lossy(&casr_cluster_c.stderr).trim_end() + ); + } - // Remove reports from deduplication phase. They are in clusters now. - for casrep in fs::read_dir(output_dir)?.flatten().map(|e| e.path()) { - if let Some(ext) = casrep.extension() { - if ext == "casrep" { - let _ = fs::remove_file(casrep); + // Remove reports from deduplication phase. They are in clusters now. + for casrep in fs::read_dir(casrep_dir)?.flatten().map(|e| e.path()) { + if let Some(ext) = casrep.extension() { + if ext == "casrep" { + let _ = fs::remove_file(casrep); + } } } } diff --git a/casr/src/util.rs b/casr/src/util.rs index 67064cf2..cd8f8a5a 100644 --- a/casr/src/util.rs +++ b/casr/src/util.rs @@ -9,6 +9,7 @@ use libcasr::stacktrace::{ use anyhow::{bail, Context, Result}; use clap::ArgMatches; +use copy_dir::copy_dir; use gdb_command::stacktrace::StacktraceExt; use is_executable::IsExecutable; use log::{info, warn}; @@ -316,28 +317,36 @@ pub fn get_atheris_lib() -> Result { pub fn initialize_dirs(matches: &clap::ArgMatches) -> Result<&PathBuf> { // Get output dir let output_dir = matches.get_one::("output").unwrap(); - if !output_dir.exists() { - fs::create_dir_all(output_dir).with_context(|| { - format!("Couldn't create output directory {}", output_dir.display()) - })?; - } else if output_dir.read_dir()?.next().is_some() { + if output_dir.exists() && output_dir.read_dir()?.next().is_some() { if matches.get_flag("force-remove") { fs::remove_dir_all(output_dir)?; - fs::create_dir_all(output_dir).with_context(|| { - format!("Couldn't create output directory {}", output_dir.display()) - })?; } else { bail!("Output directory is not empty."); } } + + if let Some(seed_dir) = matches.get_one::("seed") { + copy_dir(seed_dir, output_dir) + .with_context(|| format!("Couldn't copy seed directory {}", seed_dir.display()))?; + // Get casrep dir + let casrep_dir = output_dir.join("casrep"); + if !casrep_dir.exists() && fs::create_dir_all(&casrep_dir).is_err() { + bail!("Failed to create dir {}", &casrep_dir.to_str().unwrap()); + } + } else { + fs::create_dir_all(output_dir).with_context(|| { + format!("Couldn't create output directory {}", output_dir.display()) + })?; + } + // Get oom dir let oom_dir = output_dir.join("oom"); - if fs::create_dir_all(&oom_dir).is_err() { + if !oom_dir.exists() && fs::create_dir_all(&oom_dir).is_err() { bail!("Failed to create dir {}", &oom_dir.to_str().unwrap()); } // Get timeout dir let timeout_dir = output_dir.join("timeout"); - if fs::create_dir_all(&timeout_dir).is_err() { + if !timeout_dir.exists() && fs::create_dir_all(&timeout_dir).is_err() { bail!("Failed to create dir {}", &timeout_dir.to_str().unwrap()); } diff --git a/casr/tests/tests.rs b/casr/tests/tests.rs index 61b4f68d..64bf794d 100644 --- a/casr/tests/tests.rs +++ b/casr/tests/tests.rs @@ -3951,32 +3951,32 @@ fn test_casr_libfuzzer() { let paths = [ abs_path("tests/casr_tests/casrep/libfuzzer_crashes_xlnt"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed"), abs_path("tests/tmp_tests_casr/casr_libfuzzer_out"), abs_path("tests/casr_tests/bin/load_fuzzer"), ]; - let _ = fs::remove_dir_all(&paths[1]); let _ = fs::create_dir(abs_path("tests/tmp_tests_casr")); let bins = Path::new(*EXE_CASR_LIBFUZZER.read().unwrap()) .parent() .unwrap(); let mut cmd = Command::new(*EXE_CASR_LIBFUZZER.read().unwrap()); - cmd.args(["-i", &paths[0], "-o", &paths[1], "--", &paths[2]]) + cmd.args(["-i", &paths[0], "-o", &paths[1], "-f", "--", &paths[3]]) .env( "PATH", format!("{}:{}", bins.display(), std::env::var("PATH").unwrap()), ); - let output = cmd.output().expect("failed to start casr-libfuzzer"); + let output = cmd.output().expect("failed to start casr-libfuzzer"); assert!( output.status.success(), "Stdout {}.\n Stderr: {}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); - let err = String::from_utf8_lossy(&output.stderr); + let err = String::from_utf8_lossy(&output.stderr); assert!(!err.is_empty()); assert!(err.contains("casr-san: No crash on input")); @@ -4036,6 +4036,108 @@ fn test_casr_libfuzzer() { } assert!(storage.values().all(|x| *x > 1)); + + // Remove several clusters + let cluster_paths = [ + abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl2"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl20"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl21"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl22"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl23"), + ]; + for path in cluster_paths { + let _ = fs::remove_dir_all(path); + } + + let mut cmd = Command::new(*EXE_CASR_LIBFUZZER.read().unwrap()); + cmd.args([ + "-i", &paths[0], "-s", &paths[1], "-o", &paths[2], "-f", "--", &paths[3], + ]) + .env( + "PATH", + format!("{}:{}", bins.display(), std::env::var("PATH").unwrap()), + ); + + let output = cmd.output().expect("failed to start casr-libfuzzer"); + assert!( + output.status.success(), + "Stdout {}.\n Stderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + + let err = String::from_utf8_lossy(&output.stderr); + assert!(!err.is_empty()); + + assert!(err.contains("casr-san: No crash on input")); + assert!(err.contains("1 out of memory seeds are saved to")); + assert!(err.contains("EXPLOITABLE")); + assert!(err.contains("NOT_EXPLOITABLE")); + assert!(err.contains("PROBABLY_EXPLOITABLE")); + assert!(err.contains("heap-buffer-overflow(read)")); + assert!(err.contains("heap-buffer-overflow(write)")); + assert!(err.contains("DestAvNearNull")); + assert!(err.contains("xml::serialization")); + assert!(err.contains("AbortSignal")); + assert!(err.contains("compound_document.hpp:83")); + + let re = Regex::new(r"Number of duplicates: (?P\d+)").unwrap(); + let duplicates_cnt = re + .captures(&err) + .unwrap() + .name("unique") + .map(|x| x.as_str()) + .unwrap() + .parse::() + .unwrap(); + + assert_eq!(duplicates_cnt, 28, "Invalid number of duplicates"); + + let re = Regex::new(r"Number of new clusters: (?P\d+)").unwrap(); + let clusters_cnt = re + .captures(&err) + .unwrap() + .name("clusters") + .map(|x| x.as_str()) + .unwrap() + .parse::() + .unwrap(); + + assert_eq!(clusters_cnt, 5, "Invalid number of new clusters"); + + let re = Regex::new(r"Number of reports in new clusters: (?P\d+)").unwrap(); + let reports_cnt = re + .captures(&err) + .unwrap() + .name("clusters") + .map(|x| x.as_str()) + .unwrap() + .parse::() + .unwrap(); + + assert_eq!(reports_cnt, 17, "Invalid number of reports in new clusters"); + + let mut storage: HashMap = HashMap::new(); + for entry in fs::read_dir(&paths[1]).unwrap() { + let e = entry.unwrap().path(); + let fname = e.file_name().unwrap().to_str().unwrap(); + if fname.starts_with("cl") && e.is_dir() { + for file in fs::read_dir(e).unwrap() { + let mut e = file.unwrap().path(); + if e.is_file() && e.extension().is_some() && e.extension().unwrap() == "casrep" { + e = e.with_extension(""); + } + let fname = e.file_name().unwrap().to_str().unwrap(); + if let Some(v) = storage.get_mut(fname) { + *v += 1; + } else { + storage.insert(fname.to_string(), 1); + } + } + } + } + + assert!(storage.values().all(|x| *x > 1)); } #[test] From 01034ea6fd4c925e9ef24620cdaf6ca9e4d320f2 Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Tue, 4 Jun 2024 17:32:38 +0300 Subject: [PATCH 02/10] Fix --- casr/src/util.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/casr/src/util.rs b/casr/src/util.rs index cd8f8a5a..d87a997f 100644 --- a/casr/src/util.rs +++ b/casr/src/util.rs @@ -333,10 +333,8 @@ pub fn initialize_dirs(matches: &clap::ArgMatches) -> Result<&PathBuf> { if !casrep_dir.exists() && fs::create_dir_all(&casrep_dir).is_err() { bail!("Failed to create dir {}", &casrep_dir.to_str().unwrap()); } - } else { - fs::create_dir_all(output_dir).with_context(|| { - format!("Couldn't create output directory {}", output_dir.display()) - })?; + } else if !output_dir.exists() && fs::create_dir_all(output_dir).is_err() { + format!("Couldn't create output directory {}", output_dir.display()); } // Get oom dir From d91a732db003c0f43c90013daf409921f1a61de9 Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Thu, 6 Jun 2024 14:04:11 +0300 Subject: [PATCH 03/10] Add env variant --- casr/src/bin/casr-afl.rs | 1 + casr/src/bin/casr-libfuzzer.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/casr/src/bin/casr-afl.rs b/casr/src/bin/casr-afl.rs index e71cac2b..0a368c6d 100644 --- a/casr/src/bin/casr-afl.rs +++ b/casr/src/bin/casr-afl.rs @@ -79,6 +79,7 @@ fn main() -> Result<()> { Arg::new("seed") .short('s') .long("seed") + .env("CASR_SEED_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) .value_name("SEED_DIR") diff --git a/casr/src/bin/casr-libfuzzer.rs b/casr/src/bin/casr-libfuzzer.rs index 1d79e750..298ba395 100644 --- a/casr/src/bin/casr-libfuzzer.rs +++ b/casr/src/bin/casr-libfuzzer.rs @@ -68,6 +68,7 @@ fn main() -> Result<()> { Arg::new("output") .short('o') .long("output") + .env("CASR_SEED_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) .required(true) From a788f4d618db706fe1f6cf2961615eff3d3c72c2 Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Sun, 9 Jun 2024 22:18:06 +0300 Subject: [PATCH 04/10] Update docs --- docs/usage.md | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 8a3a23b7..1cd4a265 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -215,16 +215,18 @@ Create CASR reports (.casrep) from C# reports ... Add "-- " to run Options: - -o, --output Path to save report. Path can be a directory, then report name - is generated - --stdout Print CASR report to stdout - --stdin Stdin file for program - -t, --timeout Timeout (in seconds) for target execution, 0 value means that - timeout is disabled [default: 0] - --ignore File with regular expressions for functions and file paths that - should be ignored - -h, --help Print help - -V, --version Print version + -o, --output Path to save report. Path can be a directory, then report + name is generated + --stdout Print CASR report to stdout + --stdin Stdin file for program + -t, --timeout Timeout (in seconds) for target execution, 0 value means that + timeout is disabled [default: 0] + --ignore File with regular expressions for functions and file paths + that should be ignored + --strip-path Path prefix to strip from stacktrace and crash line [env: + CASR_STRIP_PATH=] + -h, --help Print help + -V, --version Print version Run casr-csharp: @@ -447,16 +449,19 @@ Triage crashes found by AFL++/Sharpfuzz triage C# crashes with additional options Options: - -l, --log-level Logging level [default: info] [possible values: info, debug] + -l, --log-level Logging level [default: info] [possible values: info, + debug] -j, --jobs Number of parallel jobs for generating CASR reports [default: half of cpu cores] -t, --timeout Timeout (in seconds) for target execution, 0 value means that timeout is disabled [default: 0] -i, --input AFL++ work directory -o, --output Output directory with triaged reports + -s, --seed Seed directory with previously triaged reports [env: + CASR_SEED_DIR=] -f, --force-remove Remove output project directory if it exists - --ignore-cmdline Force usage to run target instead of searching for cmdline files - in AFL fuzzing directory + --ignore-cmdline Force usage to run target instead of searching for + cmdline files in AFL fuzzing directory --no-cluster Do not cluster CASR reports -h, --help Print help -V, --version Print version @@ -586,7 +591,9 @@ Triage crashes found by libFuzzer based fuzzer -i, --input Directory containing crashes found by libFuzzer [default: .] -o, --output - Output directory with triaged reports + Output directory with triaged reports [env: CASR_SEED_DIR=] + -s, --seed + Seed directory with previously triaged reports -f, --force-remove Remove output project directory if it exists --no-cluster From ef99f8a597ca37e181dd858b91b3a2d4974ef0e5 Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Mon, 10 Jun 2024 19:44:24 +0300 Subject: [PATCH 05/10] Fix usage --- casr/src/bin/casr-libfuzzer.rs | 2 +- docs/usage.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/casr/src/bin/casr-libfuzzer.rs b/casr/src/bin/casr-libfuzzer.rs index 298ba395..baf0a38b 100644 --- a/casr/src/bin/casr-libfuzzer.rs +++ b/casr/src/bin/casr-libfuzzer.rs @@ -68,7 +68,6 @@ fn main() -> Result<()> { Arg::new("output") .short('o') .long("output") - .env("CASR_SEED_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) .required(true) @@ -79,6 +78,7 @@ fn main() -> Result<()> { Arg::new("seed") .short('s') .long("seed") + .env("CASR_SEED_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) .value_name("SEED_DIR") diff --git a/docs/usage.md b/docs/usage.md index 1cd4a265..460a26d8 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -591,9 +591,9 @@ Triage crashes found by libFuzzer based fuzzer -i, --input Directory containing crashes found by libFuzzer [default: .] -o, --output - Output directory with triaged reports [env: CASR_SEED_DIR=] + Output directory with triaged reports -s, --seed - Seed directory with previously triaged reports + Seed directory with previously triaged reports [env: CASR_SEED_DIR=] -f, --force-remove Remove output project directory if it exists --no-cluster From d028a9d14838844030fbd3292b8389eaeb57e8db Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Mon, 10 Jun 2024 22:56:48 +0300 Subject: [PATCH 06/10] Add sil score checking --- casr/tests/tests.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/casr/tests/tests.rs b/casr/tests/tests.rs index 64bf794d..2ecec6f0 100644 --- a/casr/tests/tests.rs +++ b/casr/tests/tests.rs @@ -4117,6 +4117,21 @@ fn test_casr_libfuzzer() { assert_eq!(reports_cnt, 17, "Invalid number of reports in new clusters"); + let re = Regex::new(r"Cluster silhouette score: (?P(0|1)\.\d+)").unwrap(); + let sil_score = re + .captures(&err) + .unwrap() + .name("score") + .map(|x| x.as_str()) + .unwrap() + .parse::() + .unwrap(); + + assert_eq!( + sil_score, 0.3831644389715882, + "Invalid cluster silhouette score" + ); + let mut storage: HashMap = HashMap::new(); for entry in fs::read_dir(&paths[1]).unwrap() { let e = entry.unwrap().path(); From 7f52ce19e744c6d4aa2d3376ce0a62b01839a3d3 Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Wed, 12 Jun 2024 13:53:55 +0300 Subject: [PATCH 07/10] changed copydir version --- casr/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/casr/Cargo.toml b/casr/Cargo.toml index e85e41cc..b93b9702 100644 --- a/casr/Cargo.toml +++ b/casr/Cargo.toml @@ -37,7 +37,7 @@ tokio = { version = "1", features = ["rt", "macros"], optional = true } toml = { version = "0.8", optional = true } wait-timeout = "0.2" which = "6.0" -copy_dir = "0.1.3" +copy_dir = "0.1" libcasr = { path = "../libcasr", version = "2.12.0", features = ["serde", "exploitable"] } From ea477c010a20b27ef2ee61e4c1418856e3f9ddfd Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Wed, 12 Jun 2024 14:31:24 +0300 Subject: [PATCH 08/10] Renamed option --- casr/src/bin/casr-afl.rs | 12 ++++++------ casr/src/bin/casr-libfuzzer.rs | 12 ++++++------ casr/src/triage.rs | 6 +++--- casr/src/util.rs | 6 +++--- casr/tests/tests.rs | 14 +++++++------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/casr/src/bin/casr-afl.rs b/casr/src/bin/casr-afl.rs index 0a368c6d..cc09953f 100644 --- a/casr/src/bin/casr-afl.rs +++ b/casr/src/bin/casr-afl.rs @@ -76,14 +76,14 @@ fn main() -> Result<()> { .help("Output directory with triaged reports") ) .arg( - Arg::new("seed") - .short('s') - .long("seed") - .env("CASR_SEED_DIR") + Arg::new("base") + .short('b') + .long("base") + .env("CASR_BASE_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) - .value_name("SEED_DIR") - .help("Seed directory with previously triaged reports") + .value_name("BASE_DIR") + .help("Base directory with previously triaged reports") ) .arg( Arg::new("force-remove") diff --git a/casr/src/bin/casr-libfuzzer.rs b/casr/src/bin/casr-libfuzzer.rs index baf0a38b..b5d3356f 100644 --- a/casr/src/bin/casr-libfuzzer.rs +++ b/casr/src/bin/casr-libfuzzer.rs @@ -75,14 +75,14 @@ fn main() -> Result<()> { .help("Output directory with triaged reports") ) .arg( - Arg::new("seed") - .short('s') - .long("seed") - .env("CASR_SEED_DIR") + Arg::new("base") + .short('b') + .long("base") + .env("CASR_BASE_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) - .value_name("SEED_DIR") - .help("Seed directory with previously triaged reports") + .value_name("BASE_DIR") + .help("Base directory with previously triaged reports") ) .arg( Arg::new("force-remove") diff --git a/casr/src/triage.rs b/casr/src/triage.rs index 16c4a5cb..fcd7fa64 100644 --- a/casr/src/triage.rs +++ b/casr/src/triage.rs @@ -159,11 +159,11 @@ pub fn fuzzing_crash_triage_pipeline( bail!("No crashes found"); } - let seed_mode = matches.contains_id("seed"); + let base_mode = matches.contains_id("base"); let output_dir = initialize_dirs(matches)?; - let casrep_dir = if seed_mode { + let casrep_dir = if base_mode { output_dir.join("casrep") } else { output_dir.to_path_buf() @@ -238,7 +238,7 @@ pub fn fuzzing_crash_triage_pipeline( } if !matches.get_flag("no-cluster") { - if seed_mode { + if base_mode { info!("Accumulating CASR reports..."); let casr_cluster_u = Command::new(&casr_cluster) .arg("-u") diff --git a/casr/src/util.rs b/casr/src/util.rs index d87a997f..2494707c 100644 --- a/casr/src/util.rs +++ b/casr/src/util.rs @@ -325,9 +325,9 @@ pub fn initialize_dirs(matches: &clap::ArgMatches) -> Result<&PathBuf> { } } - if let Some(seed_dir) = matches.get_one::("seed") { - copy_dir(seed_dir, output_dir) - .with_context(|| format!("Couldn't copy seed directory {}", seed_dir.display()))?; + if let Some(base_dir) = matches.get_one::("base") { + copy_dir(base_dir, output_dir) + .with_context(|| format!("Couldn't copy base directory {}", base_dir.display()))?; // Get casrep dir let casrep_dir = output_dir.join("casrep"); if !casrep_dir.exists() && fs::create_dir_all(&casrep_dir).is_err() { diff --git a/casr/tests/tests.rs b/casr/tests/tests.rs index 2ecec6f0..c7d47812 100644 --- a/casr/tests/tests.rs +++ b/casr/tests/tests.rs @@ -3951,7 +3951,7 @@ fn test_casr_libfuzzer() { let paths = [ abs_path("tests/casr_tests/casrep/libfuzzer_crashes_xlnt"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_base"), abs_path("tests/tmp_tests_casr/casr_libfuzzer_out"), abs_path("tests/casr_tests/bin/load_fuzzer"), ]; @@ -4039,11 +4039,11 @@ fn test_casr_libfuzzer() { // Remove several clusters let cluster_paths = [ - abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl2"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl20"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl21"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl22"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_seed/cl23"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl2"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl20"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl21"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl22"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl23"), ]; for path in cluster_paths { let _ = fs::remove_dir_all(path); @@ -4051,7 +4051,7 @@ fn test_casr_libfuzzer() { let mut cmd = Command::new(*EXE_CASR_LIBFUZZER.read().unwrap()); cmd.args([ - "-i", &paths[0], "-s", &paths[1], "-o", &paths[2], "-f", "--", &paths[3], + "-i", &paths[0], "-b", &paths[1], "-o", &paths[2], "-f", "--", &paths[3], ]) .env( "PATH", From 08336ac1eb79fe20e2fd519298ebb8065a7038de Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Wed, 12 Jun 2024 15:53:13 +0300 Subject: [PATCH 09/10] Renamed option x2 --- casr/src/bin/casr-afl.rs | 11 +++++----- casr/src/bin/casr-libfuzzer.rs | 11 +++++----- casr/src/triage.rs | 6 +++--- casr/src/util.rs | 6 +++--- casr/tests/tests.rs | 14 ++++++------- docs/usage.md | 37 +++++++++++++++++----------------- 6 files changed, 42 insertions(+), 43 deletions(-) diff --git a/casr/src/bin/casr-afl.rs b/casr/src/bin/casr-afl.rs index cc09953f..eff16db3 100644 --- a/casr/src/bin/casr-afl.rs +++ b/casr/src/bin/casr-afl.rs @@ -76,14 +76,13 @@ fn main() -> Result<()> { .help("Output directory with triaged reports") ) .arg( - Arg::new("base") - .short('b') - .long("base") - .env("CASR_BASE_DIR") + Arg::new("join") + .long("join") + .env("CASR_PREV_CLSUTERS_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) - .value_name("BASE_DIR") - .help("Base directory with previously triaged reports") + .value_name("PREV_CLSUTERS_DIR") + .help("Use directory with previously triaged reports for new reports accumulation") ) .arg( Arg::new("force-remove") diff --git a/casr/src/bin/casr-libfuzzer.rs b/casr/src/bin/casr-libfuzzer.rs index b5d3356f..dc182360 100644 --- a/casr/src/bin/casr-libfuzzer.rs +++ b/casr/src/bin/casr-libfuzzer.rs @@ -75,14 +75,13 @@ fn main() -> Result<()> { .help("Output directory with triaged reports") ) .arg( - Arg::new("base") - .short('b') - .long("base") - .env("CASR_BASE_DIR") + Arg::new("join") + .long("join") + .env("CASR_PREV_CLSUTERS_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) - .value_name("BASE_DIR") - .help("Base directory with previously triaged reports") + .value_name("PREV_CLSUTERS_DIR") + .help("Use directory with previously triaged reports for new reports accumulation") ) .arg( Arg::new("force-remove") diff --git a/casr/src/triage.rs b/casr/src/triage.rs index fcd7fa64..0071f486 100644 --- a/casr/src/triage.rs +++ b/casr/src/triage.rs @@ -159,11 +159,11 @@ pub fn fuzzing_crash_triage_pipeline( bail!("No crashes found"); } - let base_mode = matches.contains_id("base"); + let accum_mode = matches.contains_id("join"); let output_dir = initialize_dirs(matches)?; - let casrep_dir = if base_mode { + let casrep_dir = if accum_mode { output_dir.join("casrep") } else { output_dir.to_path_buf() @@ -238,7 +238,7 @@ pub fn fuzzing_crash_triage_pipeline( } if !matches.get_flag("no-cluster") { - if base_mode { + if accum_mode { info!("Accumulating CASR reports..."); let casr_cluster_u = Command::new(&casr_cluster) .arg("-u") diff --git a/casr/src/util.rs b/casr/src/util.rs index 2494707c..7d5f6c5f 100644 --- a/casr/src/util.rs +++ b/casr/src/util.rs @@ -325,9 +325,9 @@ pub fn initialize_dirs(matches: &clap::ArgMatches) -> Result<&PathBuf> { } } - if let Some(base_dir) = matches.get_one::("base") { - copy_dir(base_dir, output_dir) - .with_context(|| format!("Couldn't copy base directory {}", base_dir.display()))?; + if let Some(join_dir) = matches.get_one::("join") { + copy_dir(join_dir, output_dir) + .with_context(|| format!("Couldn't copy join directory {}", join_dir.display()))?; // Get casrep dir let casrep_dir = output_dir.join("casrep"); if !casrep_dir.exists() && fs::create_dir_all(&casrep_dir).is_err() { diff --git a/casr/tests/tests.rs b/casr/tests/tests.rs index c7d47812..ca638d21 100644 --- a/casr/tests/tests.rs +++ b/casr/tests/tests.rs @@ -3951,7 +3951,7 @@ fn test_casr_libfuzzer() { let paths = [ abs_path("tests/casr_tests/casrep/libfuzzer_crashes_xlnt"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_base"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_join"), abs_path("tests/tmp_tests_casr/casr_libfuzzer_out"), abs_path("tests/casr_tests/bin/load_fuzzer"), ]; @@ -4039,11 +4039,11 @@ fn test_casr_libfuzzer() { // Remove several clusters let cluster_paths = [ - abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl2"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl20"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl21"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl22"), - abs_path("tests/tmp_tests_casr/casr_libfuzzer_base/cl23"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_join/cl2"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_join/cl20"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_join/cl21"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_join/cl22"), + abs_path("tests/tmp_tests_casr/casr_libfuzzer_join/cl23"), ]; for path in cluster_paths { let _ = fs::remove_dir_all(path); @@ -4051,7 +4051,7 @@ fn test_casr_libfuzzer() { let mut cmd = Command::new(*EXE_CASR_LIBFUZZER.read().unwrap()); cmd.args([ - "-i", &paths[0], "-b", &paths[1], "-o", &paths[2], "-f", "--", &paths[3], + "-i", &paths[0], "--join", &paths[1], "-o", &paths[2], "-f", "--", &paths[3], ]) .env( "PATH", diff --git a/docs/usage.md b/docs/usage.md index 460a26d8..b0f1e78e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -449,22 +449,22 @@ Triage crashes found by AFL++/Sharpfuzz triage C# crashes with additional options Options: - -l, --log-level Logging level [default: info] [possible values: info, - debug] - -j, --jobs Number of parallel jobs for generating CASR reports - [default: half of cpu cores] - -t, --timeout Timeout (in seconds) for target execution, 0 value means - that timeout is disabled [default: 0] - -i, --input AFL++ work directory - -o, --output Output directory with triaged reports - -s, --seed Seed directory with previously triaged reports [env: - CASR_SEED_DIR=] - -f, --force-remove Remove output project directory if it exists - --ignore-cmdline Force usage to run target instead of searching for - cmdline files in AFL fuzzing directory - --no-cluster Do not cluster CASR reports - -h, --help Print help - -V, --version Print version + -l, --log-level Logging level [default: info] [possible values: info, + debug] + -j, --jobs Number of parallel jobs for generating CASR reports + [default: half of cpu cores] + -t, --timeout Timeout (in seconds) for target execution, 0 value means + that timeout is disabled [default: 0] + -i, --input AFL++ work directory + -o, --output Output directory with triaged reports + --join Use directory with previously triaged reports for new + reports accumulation [env: CASR_PREV_CLSUTERS_DIR=] + -f, --force-remove Remove output project directory if it exists + --ignore-cmdline Force usage to run target instead of searching + for cmdline files in AFL fuzzing directory + --no-cluster Do not cluster CASR reports + -h, --help Print help + -V, --version Print version `casr-afl` provides a straightforward CASR integration with AFL++. While walking through afl instances, `casr-afl` generates crash reports depending on target binary. For @@ -592,8 +592,9 @@ Triage crashes found by libFuzzer based fuzzer Directory containing crashes found by libFuzzer [default: .] -o, --output Output directory with triaged reports - -s, --seed - Seed directory with previously triaged reports [env: CASR_SEED_DIR=] + --join + Use directory with previously triaged reports for new reports accumulation [env: + CASR_PREV_CLSUTERS_DIR=] -f, --force-remove Remove output project directory if it exists --no-cluster From 76c12a255f605aee038d4d51fc43d963b951548d Mon Sep 17 00:00:00 2001 From: hkctkuy Date: Wed, 12 Jun 2024 16:59:14 +0300 Subject: [PATCH 10/10] Fix typo --- casr/src/bin/casr-afl.rs | 4 ++-- casr/src/bin/casr-libfuzzer.rs | 4 ++-- docs/usage.md | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/casr/src/bin/casr-afl.rs b/casr/src/bin/casr-afl.rs index eff16db3..b201e046 100644 --- a/casr/src/bin/casr-afl.rs +++ b/casr/src/bin/casr-afl.rs @@ -78,10 +78,10 @@ fn main() -> Result<()> { .arg( Arg::new("join") .long("join") - .env("CASR_PREV_CLSUTERS_DIR") + .env("CASR_PREV_CLUSTERS_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) - .value_name("PREV_CLSUTERS_DIR") + .value_name("PREV_CLUSTERS_DIR") .help("Use directory with previously triaged reports for new reports accumulation") ) .arg( diff --git a/casr/src/bin/casr-libfuzzer.rs b/casr/src/bin/casr-libfuzzer.rs index dc182360..4e6d0581 100644 --- a/casr/src/bin/casr-libfuzzer.rs +++ b/casr/src/bin/casr-libfuzzer.rs @@ -77,10 +77,10 @@ fn main() -> Result<()> { .arg( Arg::new("join") .long("join") - .env("CASR_PREV_CLSUTERS_DIR") + .env("CASR_PREV_CLUSTERS_DIR") .action(ArgAction::Set) .value_parser(clap::value_parser!(PathBuf)) - .value_name("PREV_CLSUTERS_DIR") + .value_name("PREV_CLUSTERS_DIR") .help("Use directory with previously triaged reports for new reports accumulation") ) .arg( diff --git a/docs/usage.md b/docs/usage.md index b0f1e78e..6599858f 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -457,8 +457,8 @@ Triage crashes found by AFL++/Sharpfuzz that timeout is disabled [default: 0] -i, --input AFL++ work directory -o, --output Output directory with triaged reports - --join Use directory with previously triaged reports for new - reports accumulation [env: CASR_PREV_CLSUTERS_DIR=] + --join Use directory with previously triaged reports for new + reports accumulation [env: CASR_PREV_CLUSTERS_DIR=] -f, --force-remove Remove output project directory if it exists --ignore-cmdline Force usage to run target instead of searching for cmdline files in AFL fuzzing directory @@ -592,9 +592,9 @@ Triage crashes found by libFuzzer based fuzzer Directory containing crashes found by libFuzzer [default: .] -o, --output Output directory with triaged reports - --join + --join Use directory with previously triaged reports for new reports accumulation [env: - CASR_PREV_CLSUTERS_DIR=] + CASR_PREV_CLUSTERS_DIR=] -f, --force-remove Remove output project directory if it exists --no-cluster