Skip to content

Commit af9e9e4

Browse files
authored
[casr-afl][casr-libfuzzer] Add hints (#230)
1 parent 4be568a commit af9e9e4

File tree

10 files changed

+62
-23
lines changed

10 files changed

+62
-23
lines changed

.github/workflows/coverage.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
- name: Build and Run Tests
3939
env:
4040
CARGO_INCREMENTAL: 0
41-
RUSTFLAGS: '-Cinstrument-coverage -Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
41+
RUSTFLAGS: '-Cinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort'
4242
RUSTDOCFLAGS: '-Cpanic=abort'
4343
LLVM_PROFILE_FILE: 'casr-%p-%m.profraw'
4444
run: |
@@ -61,6 +61,6 @@ jobs:
6161
--excl-stop '^}$' \
6262
-t lcov
6363
- name: Upload Coverage Reports to Codecov
64-
uses: codecov/codecov-action@v3
64+
uses: codecov/codecov-action@v5
6565
env:
6666
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

.github/workflows/riscv64.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ jobs:
2525
install: |
2626
export CARGO_TERM_COLOR=always
2727
export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
28-
apt-get update && apt-get install -y gdb pip curl python3.10-dev clang llvm build-essential
28+
apt-get update \
29+
&& apt-get install -y gdb pip curl python3-dev clang llvm build-essential
2930
curl https://sh.rustup.rs -o rustup.sh && chmod +x rustup.sh && \
3031
./rustup.sh -y && rm rustup.sh
3132
run: |

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[![Crates.io](https://img.shields.io/crates/v/casr)](https://crates.io/crates/casr)
22
[![Documentation](https://docs.rs/libcasr/badge.svg)](https://docs.rs/libcasr)
3-
[![codecov](https://codecov.io/github/ispras/casr/graph/badge.svg?token=D9VY1WRWA7)](https://codecov.io/github/ispras/casr)
3+
[![codecov](https://codecov.io/github/ispras/casr/graph/badge.svg?token=D9VY1WRWA7)](https://app.codecov.io/github/ispras/casr)
44
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/ispras/casr/blob/master/LICENSE)
55

66
[![amd64](https://github.com/ispras/casr/actions/workflows/amd64.yml/badge.svg?branch=master)](https://github.com/ispras/casr/actions/workflows/amd64.yml)

casr/src/bin/casr-afl.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ fn main() -> Result<()> {
103103
.long("no-cluster")
104104
.help("Do not cluster CASR reports")
105105
)
106+
.arg(
107+
Arg::new("hint")
108+
.long("hint")
109+
.value_name("HINT")
110+
.action(ArgAction::Set)
111+
.default_value("auto")
112+
.value_parser(["auto", "gdb", "san", "csharp"])
113+
.help("Hint to force run casr-HINT tool to analyze crashes")
114+
)
106115
.arg(
107116
Arg::new("ARGS")
108117
.action(ArgAction::Set)
@@ -129,6 +138,8 @@ fn main() -> Result<()> {
129138
bail!("ARGS is empty, but \"ignore-cmdline\" option is provided.");
130139
}
131140

141+
let hint = matches.get_one::<String>("hint").unwrap();
142+
132143
// Get all crashes.
133144
let mut crashes: HashMap<String, CrashInfo> = HashMap::new();
134145
for node_dir in fs::read_dir(matches.get_one::<PathBuf>("input").unwrap())? {
@@ -152,9 +163,11 @@ fn main() -> Result<()> {
152163
continue;
153164
}
154165
};
155-
crash_info.casr_tool = if !crash_info.target_args.is_empty()
156-
&& (crash_info.target_args[0].ends_with("dotnet")
157-
|| crash_info.target_args[0].ends_with("mono"))
166+
crash_info.casr_tool = if hint == "csharp"
167+
|| hint == "auto"
168+
&& !crash_info.target_args.is_empty()
169+
&& (crash_info.target_args[0].ends_with("dotnet")
170+
|| crash_info.target_args[0].ends_with("mono"))
158171
{
159172
is_casr_gdb = false;
160173
util::get_path("casr-csharp")?
@@ -169,7 +182,7 @@ fn main() -> Result<()> {
169182
.map(|x| x + 1);
170183

171184
// When we triage crashes for binaries, use casr-san.
172-
if is_casr_gdb {
185+
if hint == "san" || hint == "auto" && is_casr_gdb {
173186
if let Some(target) = crash_info.target_args.first() {
174187
match util::symbols_list(Path::new(target)) {
175188
Ok(list) => {

casr/src/bin/casr-cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ fn main() -> Result<()> {
153153
));
154154

155155
if !report.package.is_empty() && !report.package_version.is_empty() {
156-
header_string.append(&format!(
156+
header_string.append(format!(
157157
" from {} {}",
158158
report.package, report.package_version
159159
));

casr/src/bin/casr-libfuzzer.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ fn main() -> Result<()> {
102102
.action(ArgAction::Set)
103103
.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)"),
104104
)
105+
.arg(
106+
Arg::new("hint")
107+
.long("hint")
108+
.value_name("HINT")
109+
.action(ArgAction::Set)
110+
.default_value("auto")
111+
.value_parser(["auto", "gdb", "java", "js", "python", "san"])
112+
.help("Hint to force run casr-HINT tool to analyze crashes")
113+
)
105114
.arg(
106115
Arg::new("ARGS")
107116
.action(ArgAction::Set)
@@ -132,22 +141,31 @@ fn main() -> Result<()> {
132141
Vec::new()
133142
};
134143

144+
// Get hint
145+
let hint = matches.get_one::<String>("hint").unwrap();
146+
135147
// Get tool.
136148
let mut envs = HashMap::new();
137-
let tool = if argv[0].ends_with(".py") {
149+
let tool = if hint == "python" || hint == "auto" && argv[0].ends_with(".py") {
138150
envs.insert("LD_PRELOAD".to_string(), util::get_atheris_lib()?);
139151
"casr-python"
140-
} else if argv[0].ends_with("jazzer") || argv[0].ends_with("java") {
152+
} else if hint == "java"
153+
|| hint == "auto" && (argv[0].ends_with("jazzer") || argv[0].ends_with("java"))
154+
{
141155
"casr-java"
142-
} else if argv[0].ends_with(".js")
143-
|| argv[0].ends_with("node")
144-
|| argv.len() > 1 && argv[0].ends_with("npx") && argv[1] == "jazzer"
145-
|| argv[0].ends_with("jsfuzz")
156+
} else if hint == "js"
157+
|| hint == "auto"
158+
&& (argv[0].ends_with(".js")
159+
|| argv[0].ends_with("node")
160+
|| argv.len() > 1 && argv[0].ends_with("npx") && argv[1] == "jazzer"
161+
|| argv[0].ends_with("jsfuzz"))
146162
{
147163
"casr-js"
148164
} else {
149165
let sym_list = util::symbols_list(Path::new(argv[0]))?;
150-
if sym_list.contains("__asan") || sym_list.contains("runtime.go") {
166+
if hint == "san"
167+
|| hint == "auto" && (sym_list.contains("__asan") || sym_list.contains("runtime.go"))
168+
{
151169
"casr-san"
152170
} else {
153171
"casr-gdb"

casr/src/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ pub fn initialize_dirs(matches: &clap::ArgMatches) -> Result<&PathBuf> {
334334
bail!("Failed to create dir {}", &casrep_dir.to_str().unwrap());
335335
}
336336
} else if !output_dir.exists() && fs::create_dir_all(output_dir).is_err() {
337-
format!("Couldn't create output directory {}", output_dir.display());
337+
bail!("Couldn't create output directory {}", output_dir.display());
338338
}
339339

340340
// Get oom dir

casr/tests/tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4683,6 +4683,7 @@ fn test_casr_python_call_san_df() {
46834683
let work_dir = abs_path("tests/casr_tests/python");
46844684
let test_dir = abs_path("tests/tmp_tests_casr/test_casr_python_call_san_df");
46854685

4686+
let _ = std::fs::remove_dir_all(&test_dir);
46864687
let _ = copy_dir(work_dir, &test_dir).unwrap();
46874688

46884689
let paths = [
@@ -5924,6 +5925,8 @@ fn test_casr_afl_csharp() {
59245925
];
59255926

59265927
let _ = fs::remove_dir_all(&paths[1]);
5928+
let _ = fs::remove_dir_all(&paths[4]);
5929+
let _ = fs::remove_dir_all(&paths[5]);
59275930
let _ = fs::create_dir(abs_path("tests/tmp_tests_casr"));
59285931
let _ = copy_dir(&paths[2], &paths[4]).unwrap();
59295932
let _ = copy_dir(&paths[3], &paths[5]).unwrap();
@@ -6024,6 +6027,8 @@ fn test_casr_afl_csharp_ignore_cmd() {
60246027
];
60256028

60266029
let _ = fs::remove_dir_all(&paths[1]);
6030+
let _ = fs::remove_dir_all(&paths[4]);
6031+
let _ = fs::remove_dir_all(&paths[5]);
60276032
let _ = fs::create_dir(abs_path("tests/tmp_tests_casr"));
60286033
let _ = copy_dir(&paths[2], &paths[4]).unwrap();
60296034
let _ = copy_dir(&paths[3], &paths[5]).unwrap();

docs/usage.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,9 @@ Triage crashes found by AFL++/Sharpfuzz
463463
--ignore-cmdline Force <ARGS> usage to run target instead of searching
464464
for cmdline files in AFL fuzzing directory
465465
--no-cluster Do not cluster CASR reports
466+
--hint <HINT> Hint to force run casr-HINT tool to analyze crashes
467+
[default: auto] [possible values: auto, gdb, san,
468+
csharp]
466469
-h, --help Print help
467470
-V, --version Print version
468471

@@ -603,6 +606,9 @@ Triage crashes found by libFuzzer based fuzzer
603606
Add "--casr-gdb-args './gdb_fuzz_target <arguments>'" to generate additional
604607
crash reports with casr-gdb (e.g., test whether program crashes without
605608
sanitizers)
609+
--hint <HINT>
610+
Hint to force run casr-HINT tool to analyze crashes [default: auto] [possible
611+
values: auto, gdb, java, js, python, san]
606612
-h, --help
607613
Print help
608614
-V, --version

libcasr/src/cluster.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,12 @@ impl Cluster {
197197
/// NOTE: Result also can be interpreted as diameter of cluster merge result
198198
pub fn dist_rep(cluster: &Cluster, report: &ReportInfo) -> f64 {
199199
let (_, (trace, _)) = report;
200-
if let Some(max) = cluster
200+
cluster
201201
.stacktraces()
202202
.iter()
203203
.map(|s| 1.0 - similarity(s, trace))
204204
.max_by(|a, b| a.total_cmp(b))
205-
{
206-
max
207-
} else {
208-
0f64
209-
}
205+
.unwrap_or(0f64)
210206
}
211207
}
212208

0 commit comments

Comments
 (0)