Skip to content

Commit 0762390

Browse files
authored
Support CASR_PRELOAD option (#256)
1 parent 2acf1b2 commit 0762390

File tree

13 files changed

+222
-71
lines changed

13 files changed

+222
-71
lines changed

.github/workflows/aarch64.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
export CARGO_TERM_COLOR=always
2727
export CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
2828
apt-get update && apt-get install -y gdb pip curl python3.12-dev clang llvm build-essential binutils lld lua5.4
29+
update-alternatives --set cc /usr/bin/clang
2930
curl https://sh.rustup.rs -o rustup.sh && chmod +x rustup.sh && \
3031
./rustup.sh -y && rm rustup.sh
3132
run: |

casr/src/bin/casr-csharp.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ fn main() -> Result<()> {
7070
.value_name("PREFIX")
7171
.help("Path prefix to strip from stacktrace and crash line"),
7272
)
73+
.arg(
74+
Arg::new("ld-preload")
75+
.long("ld-preload")
76+
.env("CASR_PRELOAD")
77+
.action(ArgAction::Set)
78+
.num_args(1..)
79+
.value_name("LIBS")
80+
.value_parser(clap::value_parser!(String))
81+
.help("Set LD_PRELOAD for the target program without disrupting the CASR process itself (both ` ` and `:` are valid delimiter)")
82+
)
7383
.arg(
7484
Arg::new("ARGS")
7585
.action(ArgAction::Set)
@@ -107,6 +117,10 @@ fn main() -> Result<()> {
107117

108118
// Run program.
109119
let mut csharp_cmd = Command::new(argv[0]);
120+
// Set ld preload
121+
if let Some(ld_preload) = util::get_ld_preload(&matches) {
122+
csharp_cmd.env("LD_PRELOAD", ld_preload);
123+
}
110124
if let Some(ref file) = stdin_file {
111125
csharp_cmd.stdin(std::fs::File::open(file)?);
112126
}

casr/src/bin/casr-java.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ fn main() -> Result<()> {
8282
.value_name("PREFIX")
8383
.help("Path prefix to strip from stacktrace and crash line"),
8484
)
85+
.arg(
86+
Arg::new("ld-preload")
87+
.long("ld-preload")
88+
.env("CASR_PRELOAD")
89+
.action(ArgAction::Set)
90+
.num_args(1..)
91+
.value_name("LIBS")
92+
.value_parser(clap::value_parser!(String))
93+
.help("Set LD_PRELOAD for the target program without disrupting the CASR process itself (both ` ` and `:` are valid delimiter)")
94+
)
8595
.arg(
8696
Arg::new("ARGS")
8797
.action(ArgAction::Set)
@@ -111,6 +121,10 @@ fn main() -> Result<()> {
111121

112122
// Run program.
113123
let mut java_cmd = Command::new(argv[0]);
124+
// Set ld preload
125+
if let Some(ld_preload) = util::get_ld_preload(&matches) {
126+
java_cmd.env("LD_PRELOAD", ld_preload);
127+
}
114128
if let Some(ref file) = stdin_file {
115129
java_cmd.stdin(std::fs::File::open(file)?);
116130
}

casr/src/bin/casr-js.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ fn main() -> Result<()> {
7070
.value_name("PREFIX")
7171
.help("Path prefix to strip from stacktrace and crash line"),
7272
)
73+
.arg(
74+
Arg::new("ld-preload")
75+
.long("ld-preload")
76+
.env("CASR_PRELOAD")
77+
.action(ArgAction::Set)
78+
.num_args(1..)
79+
.value_name("LIBS")
80+
.value_parser(clap::value_parser!(String))
81+
.help("Set LD_PRELOAD for the target program without disrupting the CASR process itself (both ` ` and `:` are valid delimiter)")
82+
)
7383
.arg(
7484
Arg::new("ARGS")
7585
.action(ArgAction::Set)
@@ -99,6 +109,10 @@ fn main() -> Result<()> {
99109

100110
// Run program.
101111
let mut js_cmd = Command::new(argv[0]);
112+
// Set ld preload
113+
if let Some(ld_preload) = util::get_ld_preload(&matches) {
114+
js_cmd.env("LD_PRELOAD", ld_preload);
115+
}
102116
if let Some(ref file) = stdin_file {
103117
js_cmd.stdin(std::fs::File::open(file)?);
104118
}

casr/src/bin/casr-libfuzzer.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ use clap::{
88
};
99

1010
use std::collections::HashMap;
11+
use std::env;
1112
use std::fs;
1213
use std::path::{Path, PathBuf};
1314

1415
fn main() -> Result<()> {
1516
let matches = clap::Command::new("casr-libfuzzer")
1617
.version(clap::crate_version!())
17-
.about("Triage crashes found by libFuzzer based fuzzer (C/C++/go-fuzz/Atheris/Jazzer/Jazzer.js/jsfuzz) or LibAFL based fuzzer")
18+
.about("Triage crashes found by libFuzzer based fuzzer (C/C++/go-fuzz/Atheris/Jazzer/Jazzer.js/jsfuzz/luzer) or LibAFL based fuzzer")
1819
.term_width(90)
1920
.arg(
2021
Arg::new("log-level")
@@ -147,7 +148,10 @@ fn main() -> Result<()> {
147148
// Get tool.
148149
let mut envs = HashMap::new();
149150
let tool = if hint == "python" || hint == "auto" && argv[0].ends_with(".py") {
150-
envs.insert("LD_PRELOAD".to_string(), util::get_atheris_lib()?);
151+
// NOTE: https://doc.rust-lang.org/std/env/fn.var.html#errors
152+
if env::var("CASR_PRELOAD").is_err() {
153+
envs.insert("CASR_PRELOAD".to_string(), util::get_atheris_lib()?);
154+
}
151155
"casr-python"
152156
} else if hint == "java"
153157
|| hint == "auto" && (argv[0].ends_with("jazzer") || argv[0].ends_with("java"))

casr/src/bin/casr-lua.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ fn main() -> Result<()> {
7575
.value_name("PREFIX")
7676
.help("Path prefix to strip from stacktrace"),
7777
)
78+
.arg(
79+
Arg::new("ld-preload")
80+
.long("ld-preload")
81+
.env("CASR_PRELOAD")
82+
.action(ArgAction::Set)
83+
.num_args(1..)
84+
.value_name("LIBS")
85+
.value_parser(clap::value_parser!(String))
86+
.help("Set LD_PRELOAD for the target program without disrupting the CASR process itself (both ` ` and `:` are valid delimiter)")
87+
)
7888
.arg(
7989
Arg::new("ARGS")
8090
.action(ArgAction::Set)
@@ -104,6 +114,10 @@ fn main() -> Result<()> {
104114

105115
// Run program.
106116
let mut cmd = Command::new(argv[0]);
117+
// Set ld preload
118+
if let Some(ld_preload) = util::get_ld_preload(&matches) {
119+
cmd.env("LD_PRELOAD", ld_preload);
120+
}
107121
if let Some(ref file) = stdin_file {
108122
cmd.stdin(std::fs::File::open(file)?);
109123
}

casr/src/bin/casr-python.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@ fn main() -> Result<()> {
7474
.value_name("PREFIX")
7575
.help("Path prefix to strip from stacktrace"),
7676
)
77+
.arg(
78+
Arg::new("ld-preload")
79+
.long("ld-preload")
80+
.env("CASR_PRELOAD")
81+
.action(ArgAction::Set)
82+
.num_args(1..)
83+
.value_name("LIBS")
84+
.value_parser(clap::value_parser!(String))
85+
.help("Set LD_PRELOAD for the target program without disrupting the CASR process itself (both ` ` and `:` are valid delimiter)")
86+
)
7787
.arg(
7888
Arg::new("ARGS")
7989
.action(ArgAction::Set)
@@ -103,6 +113,10 @@ fn main() -> Result<()> {
103113

104114
// Run program.
105115
let mut python_cmd = Command::new(argv[0]);
116+
// Set ld preload
117+
if let Some(ld_preload) = util::get_ld_preload(&matches) {
118+
python_cmd.env("LD_PRELOAD", ld_preload);
119+
}
106120
if let Some(ref file) = stdin_file {
107121
python_cmd.stdin(std::fs::File::open(file)?);
108122
}

casr/src/bin/casr-san.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ fn main() -> Result<()> {
9090
.value_name("PREFIX")
9191
.help("Path prefix to strip from stacktrace and crash line"),
9292
)
93+
.arg(
94+
Arg::new("ld-preload")
95+
.long("ld-preload")
96+
.env("CASR_PRELOAD")
97+
.action(ArgAction::Set)
98+
.num_args(1..)
99+
.value_name("LIBS")
100+
.value_parser(clap::value_parser!(String))
101+
.help("Set LD_PRELOAD for the target program without disrupting the CASR process itself (both ` ` and `:` are valid delimiter)")
102+
)
93103
.arg(
94104
Arg::new("ARGS")
95105
.action(ArgAction::Set)
@@ -139,6 +149,10 @@ fn main() -> Result<()> {
139149

140150
// Run program with sanitizers.
141151
let mut sanitizers_cmd = Command::new(argv[0]);
152+
// Set ld preload
153+
if let Some(ld_preload) = util::get_ld_preload(&matches) {
154+
sanitizers_cmd.env("LD_PRELOAD", ld_preload);
155+
}
142156
if let Some(ref file) = stdin_file {
143157
sanitizers_cmd.stdin(std::fs::File::open(file).unwrap());
144158
}

casr/src/bin/casr-ubsan.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ use std::sync::RwLock;
3434
///
3535
/// * `timeout` - target program timeout
3636
///
37+
/// * `ld_preload` - LD_PRELOAD value
38+
///
3739
/// # Returns value
3840
///
3941
/// Vector of extracted ubsan warnings with crash lines
4042
fn extract_warnings(
4143
input: &PathBuf,
4244
argv: &[&str],
4345
timeout: u64,
46+
ld_preload: &Option<String>,
4447
) -> Result<Vec<(UbsanWarning, CrashLine)>> {
4548
// Get command line argv
4649
let mut argv = argv.to_owned();
@@ -54,6 +57,10 @@ fn extract_warnings(
5457
};
5558
// Run program.
5659
let mut cmd = Command::new(argv[0]);
60+
// Set ld preload
61+
if let Some(ld_preload) = ld_preload {
62+
cmd.env("LD_PRELOAD", ld_preload);
63+
}
5764
cmd.stdout(Stdio::null()).stderr(Stdio::piped());
5865
if stdin {
5966
let Ok(file) = fs::File::open(input) else {
@@ -169,7 +176,7 @@ fn save_report(report: CrashReport, output_dir: &Path, input: &Path) -> Result<(
169176
let dir_name = input.parent().unwrap().file_name().unwrap();
170177
let input_name = input.file_name().unwrap();
171178
let crashline = report.crashline;
172-
let crashline = crashline.split('/').last().unwrap();
179+
let crashline = crashline.split('/').next_back().unwrap();
173180
let crashline = crashline.replace(':', "_");
174181

175182
// Copy input
@@ -281,6 +288,16 @@ fn main() -> Result<()> {
281288
.action(ArgAction::SetTrue)
282289
.help("Remove output project directory if it exists")
283290
)
291+
.arg(
292+
Arg::new("ld-preload")
293+
.long("ld-preload")
294+
.env("CASR_PRELOAD")
295+
.action(ArgAction::Set)
296+
.num_args(1..)
297+
.value_name("LIBS")
298+
.value_parser(clap::value_parser!(String))
299+
.help("Set LD_PRELOAD for the target program without disrupting the CASR process itself (both ` ` and `:` are valid delimiter)")
300+
)
284301
.arg(
285302
Arg::new("ARGS")
286303
.action(ArgAction::Set)
@@ -352,6 +369,9 @@ fn main() -> Result<()> {
352369
.build()
353370
.unwrap();
354371

372+
// Get ld preload
373+
let ld_preload = util::get_ld_preload(&matches);
374+
355375
// Set ubsan env options
356376
if let Ok(mut ubsan_options) = env::var("UBSAN_OPTIONS") {
357377
if ubsan_options.starts_with(',') {
@@ -395,7 +415,8 @@ fn main() -> Result<()> {
395415
inputs
396416
.par_iter()
397417
.filter_map(|input| {
398-
let Ok(input_warnings) = extract_warnings(input, &argv, timeout) else {
418+
let Ok(input_warnings) = extract_warnings(input, &argv, timeout, &ld_preload)
419+
else {
399420
warn!("Failed to run program with input file {:?}", input);
400421
*counter.write().unwrap() += 1;
401422
return None;

casr/src/triage.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ impl<'a> CrashInfo {
144144
/// * `matches` - casr-afl/casr-libfuzzer arguments
145145
///
146146
/// * `crashes` - map of crashes, specified as a HashMap, where
147-
/// key is crash input file name and value is CrashInfo structure
147+
/// key is crash input file name and value is CrashInfo structure
148148
///
149149
/// * `gdb_args` - casr-gdb target arguments. If they are empty, casr-gdb won't be launched.
150150
pub fn fuzzing_crash_triage_pipeline(

casr/src/util.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ pub fn call_casr_san(matches: &ArgMatches, argv: &[&str], name: &str) -> Result<
4949
if let Some(path) = matches.get_one::<String>("ignore") {
5050
cmd.args(["--ignore", path]);
5151
}
52+
if let Some(ld_preload) = get_ld_preload(matches) {
53+
cmd.args(["--ld-preload", &ld_preload]);
54+
}
5255
cmd.arg("--").args(argv);
5356

5457
let output = cmd
@@ -614,3 +617,18 @@ pub fn strip_paths(report: &mut CrashReport, stacktrace: &Stacktrace, prefix: &s
614617
.join(" ");
615618
}
616619
}
620+
621+
/// Get LD_PRELOAD
622+
///
623+
/// # Arguments
624+
///
625+
/// * `matches` - casr options
626+
pub fn get_ld_preload(matches: &ArgMatches) -> Option<String> {
627+
let ld_preload = matches.get_many::<String>("ld-preload")?;
628+
Some(
629+
ld_preload
630+
.map(|s| s.to_string())
631+
.collect::<Vec<_>>()
632+
.join(":"),
633+
)
634+
}

0 commit comments

Comments
 (0)