Skip to content

Commit

Permalink
refactored casr-afl
Browse files Browse the repository at this point in the history
  • Loading branch information
headshog committed Mar 19, 2024
1 parent 5f2bbcc commit a0cd41d
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 101 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,20 @@ Cluster reports:

Triage crashes after AFL++ fuzzing with casr-afl:

$ cp casr/tests/casr_tests/bin/load_afl /tmp/load_afl
$ cp casr/tests/casr_tests/bin/load_sydr /tmp/load_sydr
$ cp -r casr/tests/casr_tests/bin/load_afl /tmp/load_afl
$ cp -r casr/tests/casr_tests/bin/load_sydr /tmp/load_sydr
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-xlnt -o casr/tests/tmp_tests_casr/casr_afl_out
$ # You may also additionally generate crash reports for uninstrumented binary with casr-gdb
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-xlnt -o casr/tests/tmp_tests_casr/casr_afl_out --casr-gdb-args /tmp/load_sydr @@
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-xlnt -o casr/tests/tmp_tests_casr/casr_afl_out -- /tmp/load_sydr @@

Triage crashes after Sharpfuzz fuzzing with casr-afl:

$ cp casr/tests/casr_tests/csharp/test_casr_afl_csharp /tmp/test_casr_afl_csharp
$ cp casr/tests/casr_tests/csharp/test_casr_afl_csharp_module /tmp/test_casr_afl_csharp_module
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-sharpfuzz -o casr/tests/tmp_tests_casr/casr_afl_csharp_out -- dotnet run --project /tmp/test_casr_afl_csharp/test_casr_afl_csharp.csproj @@
$ cp -r casr/tests/casr_tests/csharp/test_casr_afl_csharp /tmp/test_casr_afl_csharp
$ cp -r casr/tests/casr_tests/csharp/test_casr_afl_csharp_module /tmp/test_casr_afl_csharp_module
$ dotnet publish -o /tmp/test_casr_afl_csharp/bin
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-sharpfuzz -o casr/tests/tmp_tests_casr/casr_afl_csharp_out
$ # You may force your own run arguments using --ignore-cmdline
$ casr-afl --ignore-cmdline -i casr/tests/casr_tests/casrep/afl-out-sharpfuzz -o casr/tests/tmp_tests_casr/casr_afl_csharp_out -- dotnet run --no-build --project /tmp/test_casr_afl_csharp/test_casr_afl_csharp.csproj @@

Triage libFuzzer crashes with casr-libfuzzer:

Expand Down
97 changes: 38 additions & 59 deletions casr/src/bin/casr-afl.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use casr::triage::{fuzzing_crash_triage_pipeline, CrashInfo};
use casr::util;

use anyhow::bail;
use anyhow::Result;
use anyhow::{bail, Result};
use clap::{
error::{ContextKind, ContextValue, ErrorKind},
Arg, ArgAction,
Expand Down Expand Up @@ -87,61 +86,49 @@ fn main() -> Result<()> {
Arg::new("ignore-cmdline")
.action(ArgAction::SetTrue)
.long("ignore-cmdline")
.help("Force <casr-gdb-args> usage to run target instead of searching for cmdline files in AFL fuzzing directory")
.help("Force <ARGS> usage to run target instead of searching for cmdline files in AFL fuzzing directory")
)
.arg(
Arg::new("no-cluster")
.action(ArgAction::SetTrue)
.long("no-cluster")
.help("Do not cluster CASR reports")
)
.arg(
Arg::new("casr-gdb-args")
.long("casr-gdb-args")
.action(ArgAction::Set)
.help("Add \"--casr-gdb-args \'./gdb_fuzz_target <arguments>\'\" to generate additional crash reports with casr-gdb (e.g., test whether program crashes without sanitizers)"),
)
.arg(
Arg::new("ARGS")
.action(ArgAction::Set)
.required(false)
.num_args(1..)
.last(true)
.help("Add \"-- fuzz_target <arguments>\""),
.help("Add \"-- ./gdb_fuzz_target <arguments>\" to generate additional crash reports with casr-gdb \
(for compiled binaries, e.g., test whether program crashes without sanitizers), \"-- dotnet <arguments>\" \
or \"-- mono <arguments>\" to triage C# crashes with additional options")
)
.get_matches();

// Init log.
util::initialize_logging(&matches);

// Get fuzz target args.
let argv: Vec<&str> = if let Some(argvs) = matches.get_many::<String>("ARGS") {
argvs.map(|v| v.as_str()).collect()
let mut args = if let Some(argv) = matches.get_many::<String>("ARGS") {
argv.cloned().collect()
} else {
Vec::new()
};

// Get gdb args.
let mut gdb_args = if let Some(argv) = matches.get_one::<String>("casr-gdb-args") {
shell_words::split(argv)?
} else {
Vec::new()
};
if gdb_args.is_empty() && matches.get_flag("ignore-cmdline") {
bail!("casr-gdb-args is empty, but \"ignore-cmdline\" option is provided.");
if args.is_empty() && matches.get_flag("ignore-cmdline") {
bail!("ARGS is empty, but \"ignore-cmdline\" option is provided.");
}

// Get tool.
let tool = if !argv.is_empty() && (argv[0].ends_with("dotnet") || argv[0].ends_with("mono")) {
let mut tool = if matches.get_flag("ignore-cmdline")
&& (args[0].ends_with("dotnet") || args[0].ends_with("mono"))
{
"casr-csharp"

Check warning on line 126 in casr/src/bin/casr-afl.rs

View check run for this annotation

Codecov / codecov/patch

casr/src/bin/casr-afl.rs#L125-L126

Added lines #L125 - L126 were not covered by tests
} else {
"casr-gdb"
};
let tool_path = util::get_path(tool)?;

if !gdb_args.is_empty() && tool != "casr-gdb" {
bail!("casr-gdb-args is provided with other tool (casr-csharp).");
}

// Get all crashes.
let mut crashes: HashMap<String, CrashInfo> = HashMap::new();
for node_dir in fs::read_dir(matches.get_one::<PathBuf>("input").unwrap())? {
Expand All @@ -151,38 +138,30 @@ fn main() -> Result<()> {
}

// Get crashes from one node.
let mut crash_info = if tool == "casr-gdb" {
CrashInfo {
target_args: if matches.get_flag("ignore-cmdline") {
gdb_args.clone()
} else {
let cmdline_path = path.join("cmdline");
if let Ok(cmdline) = fs::read_to_string(&cmdline_path) {
cmdline.split_whitespace().map(|s| s.to_string()).collect()
} else {
error!("Couldn't read {}.", cmdline_path.display());
continue;
}
},
envs: HashMap::new(),
..Default::default()
}
let mut crash_info = casr::triage::CrashInfo {
..Default::default()
};
if matches.get_flag("ignore-cmdline") {
crash_info.casr_tool = tool_path.clone();
crash_info.target_args = args.clone()
} else {
CrashInfo {
target_args: argv.iter().map(|x| x.to_string()).collect(),
envs: vec![
("AFL_SKIP_BIN_CHECK".to_string(), "1".to_string()),
(
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES".to_string(),
"1".to_string(),
),
]
.into_iter()
.collect(),
..Default::default()
let cmdline_path = path.join("cmdline");
if let Ok(cmdline) = fs::read_to_string(&cmdline_path) {
let cmd_args: Vec<String> =
cmdline.split_whitespace().map(|s| s.to_string()).collect();
if cmd_args[0].ends_with("dotnet") || cmd_args[0].ends_with("mono") {
tool = "casr-csharp";
crash_info.casr_tool = util::get_path("casr-csharp")?.clone()
} else {
tool = "casr-gdb";
crash_info.casr_tool = util::get_path("casr-gdb")?.clone()
}
crash_info.target_args = cmd_args;
} else {
error!("Couldn't read {}.", cmdline_path.display());
continue;
}
};
crash_info.casr_tool = tool_path.clone();
crash_info.at_index = crash_info
.target_args
.iter()
Expand All @@ -196,7 +175,7 @@ fn main() -> Result<()> {
match util::symbols_list(Path::new(target)) {
Ok(list) => {
if list.contains("__asan") {
crash_info.casr_tool = util::get_path("casr-san")?.clone();
crash_info.casr_tool = util::get_path("casr-san")?.clone()
}
}
Err(e) => {
Expand Down Expand Up @@ -226,10 +205,10 @@ fn main() -> Result<()> {
}
}

if matches.get_flag("ignore-cmdline") {
gdb_args = Vec::new();
if matches.get_flag("ignore-cmdline") || tool != "casr-gdb" {
args = Vec::new();
}

// Generate reports
fuzzing_crash_triage_pipeline(&matches, &crashes, &gdb_args)
fuzzing_crash_triage_pipeline(&matches, &crashes, &args)
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/usr/bin/dotnet
/build_test/test_casr_afl_csharp/bin/test_casr_afl_csharp.dll
/tmp/test_casr_afl_csharp/bin/test_casr_afl_csharp.dll
@@
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/usr/bin/dotnet
/build_test/test_casr_afl_csharp/bin/test_casr_afl_csharp.dll
/tmp/test_casr_afl_csharp/bin/test_casr_afl_csharp.dll
@@
35 changes: 12 additions & 23 deletions casr/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3699,8 +3699,9 @@ fn test_casr_afl() {
&paths[0],
"-o",
&paths[1],
"--casr-gdb-args",
"/tmp/load_sydr @@",
"--",
"/tmp/load_sydr",
"@@",
])
.env(
"PATH",
Expand Down Expand Up @@ -3793,7 +3794,7 @@ fn test_casr_afl_ignore_cmd() {
&paths[0],
"-o",
&paths[1],
"--casr-gdb-args",
"--",
&load_afl,
])
.output()
Expand Down Expand Up @@ -5854,32 +5855,20 @@ fn test_casr_afl_csharp() {

let _ = Command::new(dotnet_path.to_str().unwrap())
.args([
"build",
"publish",
"-o",
&format!("{}/bin", &paths[4]),
&format!("{}/test_casr_afl_csharp.csproj", &paths[4]),
])
.output()
.expect("dotnet build crashed");
.expect("dotnet publish crashed");

let bins = Path::new(*EXE_CASR_AFL.read().unwrap()).parent().unwrap();
let mut output = Command::new(*EXE_CASR_AFL.read().unwrap());
output
.args([
"-i",
&paths[0],
"-o",
&paths[1],
"--",
&dotnet_path.to_str().unwrap(),
"run",
"--project",
&format!("{}/test_casr_afl_csharp.csproj", &paths[4]),
"--no-build",
"@@",
])
.env(
"PATH",
format!("{}:{}", bins.display(), std::env::var("PATH").unwrap()),
);
output.args(["-i", &paths[0], "-o", &paths[1]]).env(
"PATH",
format!("{}:{}", bins.display(), std::env::var("PATH").unwrap()),
);

print!("{:?}", output);
let output = output.output().expect("casr-afl crashed");
Expand Down
29 changes: 18 additions & 11 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,10 @@ Triage crashes found by AFL++ (Sharpfuzz)
Usage: casr-afl [OPTIONS] --input <INPUT_DIR> --output <OUTPUT_DIR> [-- <ARGS>...]

Arguments:
[ARGS]... Add "-- fuzz_target <arguments>"
[ARGS]... Add "-- ./gdb_fuzz_target <arguments>" to generate additional crash reports
with casr-gdb (for compiled binaries, e.g., test whether program crashes
without sanitizers), "-- dotnet <arguments>" or "-- mono <arguments>" to
triage C# crashes with additional options

Options:
-l, --log-level <log-level>
Expand All @@ -460,10 +463,6 @@ Triage crashes found by AFL++ (Sharpfuzz)
in AFL fuzzing directory
--no-cluster
Do not cluster CASR reports
--casr-gdb-args <casr-gdb-args>
Add "--casr-gdb-args './gdb_fuzz_target <arguments>'" to generate additional
crash reports with casr-gdb (e.g., test whether program crashes without
sanitizers)
-h, --help
Print help
-V, --version
Expand All @@ -483,8 +482,8 @@ fuzzer [Sharpfuzz](https://github.com/Metalnem/sharpfuzz).

AFL++ Example (Ubuntu 20.04+):

$ cp casr/tests/casr_tests/bin/load_afl /tmp/load_afl
$ cp casr/tests/casr_tests/bin/load_sydr /tmp/load_sydr
$ cp -r casr/tests/casr_tests/bin/load_afl /tmp/load_afl
$ cp -r casr/tests/casr_tests/bin/load_sydr /tmp/load_sydr
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-xlnt -o casr/tests/tmp_tests_casr/casr_afl_out

$ tree tests/tmp_tests_casr/casr_afl_out
Expand Down Expand Up @@ -558,12 +557,20 @@ variable may be used by [casr-san](#casr-san).

Sharpfuzz example:

$ $ cp casr/tests/casr_tests/csharp/test_casr_afl_csharp /tmp/test_casr_afl_csharp
$ cp casr/tests/casr_tests/csharp/test_casr_afl_csharp_module /tmp/test_casr_afl_csharp_module
$ cp -r casr/tests/casr_tests/csharp/test_casr_afl_csharp /tmp/test_casr_afl_csharp
$ cp -r casr/tests/casr_tests/csharp/test_casr_afl_csharp_module /tmp/test_casr_afl_csharp_module
$ dotnet publish -o /tmp/test_casr_afl_csharp/bin
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-sharpfuzz -o casr/tests/tmp_tests_casr/casr_afl_csharp_out

Sharpfuzz example (with --ignore-cmdline):

$ cp -r casr/tests/casr_tests/csharp/test_casr_afl_csharp /tmp/test_casr_afl_csharp
$ cp -r casr/tests/casr_tests/csharp/test_casr_afl_csharp_module /tmp/test_casr_afl_csharp_module
$ dotnet build /tmp/test_casr_afl_csharp/test_casr_afl_csharp.csproj
$ casr-afl -i casr/tests/casr_tests/casrep/afl-out-sharpfuzz -o casr/tests/tmp_tests_casr/casr_afl_csharp_out -- dotnet run --no-build --project /tmp/test_casr_afl_csharp/test_casr_afl_csharp.csproj @@
$ casr-afl --ignore-cmdline -i casr/tests/casr_tests/casrep/afl-out-sharpfuzz -o casr/tests/tmp_tests_casr/casr_afl_csharp_out -- dotnet run --no-build --project /tmp/test_casr_afl_csharp/test_casr_afl_csharp.csproj @@

**NOTE:** if you run `casr-afl` for Sharpfuzz pipeline using `dotnet`, build your project before run (via `dotnet build` or `dotnet publish`) and specify `--no-build` option for `dotnet run`.
**NOTE:** if you run `casr-afl` for Sharpfuzz pipeline using `--ignore-cmdline` with `dotnet run`, build
your project before (via `dotnet build` or `dotnet publish`) and specify `--no-build` option for `dotnet run`.

## casr-libfuzzer

Expand Down

0 comments on commit a0cd41d

Please sign in to comment.