Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Commit

Permalink
Create temp working directory for each libfuzzer invocation
Browse files Browse the repository at this point in the history
  • Loading branch information
Porges authored Oct 26, 2023
1 parent 957f1fb commit 5c34c24
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/agent/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions src/agent/coverage/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.4"
tempfile = "3.7"
tempfile = "3.8"
debuggable-module = { path = "../../debuggable-module" }


Expand All @@ -34,4 +34,3 @@ name = "fuzz_target_allowlist_parse"
path = "fuzz_targets/fuzz_target_allowlist_parse.rs"
test = false
doc = false

1 change: 1 addition & 0 deletions src/agent/onefuzz-agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ azure_storage = { version = "0.15", default-features = false, features = [
azure_storage_blobs = { version = "0.15", default-features = false, features = [
"enable_reqwest",
] }
tempfile = "3.8"


[target.'cfg(target_family = "unix")'.dependencies]
Expand Down
3 changes: 2 additions & 1 deletion src/agent/onefuzz-agent/src/validations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ async fn run_setup(setup_folder: impl AsRef<Path>) -> Result<()> {
}

async fn get_logs(config: ValidationConfig) -> Result<()> {
let tmp_working_dir = tempfile::tempdir()?;
let setup_folder = config
.setup_folder
.clone()
Expand All @@ -121,7 +122,7 @@ async fn get_logs(config: ValidationConfig) -> Result<()> {
},
);

let cmd = libfuzzer.build_std_command(None, None, None, None, None)?;
let cmd = libfuzzer.build_std_command(tmp_working_dir.path(), None, None, None, None, None)?;
print_logs(cmd)?;
Ok(())
}
Expand Down
18 changes: 12 additions & 6 deletions src/agent/onefuzz-task/src/tasks/fuzz/libfuzzer/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ where
worker_id: usize,
stats_sender: Option<&StatsSender>,
) -> Result<()> {
let tmp_working_dir = self.create_local_temp_dir().await?;
let crash_dir = self.create_local_temp_dir().await?;
let run_id = Uuid::new_v4();

Expand All @@ -272,7 +273,12 @@ where
info!("config is: {:?}", self.config);

let fuzzer = L::from_config(&self.config).await?;
let mut running = fuzzer.fuzz(crash_dir.path(), local_inputs, &inputs)?;
let mut running = fuzzer.fuzz(
tmp_working_dir.path(),
crash_dir.path(),
local_inputs,
&inputs,
)?;

info!("child is: {:?}", running);

Expand Down Expand Up @@ -376,22 +382,22 @@ where
// note that collecting the dumps must be enabled by the template
#[cfg(target_os = "linux")]
if let Some(pid) = pid {
// expect crash dump to exist in CWD
let filename = format!("core.{pid}");
// expect crash dump to exist in fuzzer (temp) working dir
let filename = tmp_working_dir.path().join(format!("core.{pid}"));
let dest_filename = dump_file_name.as_deref().unwrap_or(OsStr::new(&filename));
let dest_path = crashdumps.local_path.join(dest_filename);
match tokio::fs::rename(&filename, &dest_path).await {
Ok(()) => {
info!(
"moved crash dump {} to output directory: {}",
filename,
filename.display(),
dest_path.display()
);
}
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
// okay, no crash dump found
info!("no crash dump found with name: {}", filename);
info!("no crash dump found with name: {}", filename.display());
} else {
return Err(e).context("moving crash dump to output directory");
}
Expand All @@ -406,7 +412,7 @@ where
{
let dumpfile_extension = Some(std::ffi::OsStr::new("dmp"));

let mut working_dir = tokio::fs::read_dir(".").await?;
let mut working_dir = tokio::fs::read_dir(tmp_working_dir.path()).await?;
let mut found_dump = false;
while let Some(next) = working_dir.next_entry().await? {
if next.path().extension() == dumpfile_extension {
Expand Down
28 changes: 26 additions & 2 deletions src/agent/onefuzz/src/libfuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,15 @@ impl LibFuzzer {
// Build an async `Command`.
fn build_command(
&self,
working_dir: &Path,
fault_dir: Option<&Path>,
corpus_dir: Option<&Path>,
extra_corpus_dirs: Option<&[&Path]>,
extra_args: Option<&[&OsStr]>,
custom_arg_filter: Option<&dyn Fn(String) -> Option<String>>,
) -> Result<Command> {
let std_cmd = self.build_std_command(
working_dir,
fault_dir,
corpus_dir,
extra_corpus_dirs,
Expand All @@ -96,13 +98,20 @@ impl LibFuzzer {
// Build a non-async `Command`.
pub fn build_std_command(
&self,
working_dir: &Path,
fault_dir: Option<&Path>,
corpus_dir: Option<&Path>,
extra_corpus_dirs: Option<&[&Path]>,
extra_args: Option<&[&OsStr]>,
custom_arg_filter: Option<&dyn Fn(String) -> Option<String>>,
) -> Result<std::process::Command> {
let mut cmd = std::process::Command::new(&self.exe);

// subprocess is isolated in its own working directory
// this is to prevent collisions between multiple libfuzzers
// (for example, crash dumps are generated into working directory on Windows)
cmd.current_dir(working_dir);

cmd.env(PATH, get_path_with_directory(PATH, &self.setup_dir)?)
.env_remove("RUST_LOG")
.stdin(Stdio::null())
Expand Down Expand Up @@ -250,7 +259,9 @@ impl LibFuzzer {
// Verify that the libfuzzer exits with a zero return code with a known
// good input, which libfuzzer works as we expect.
async fn check_input(&self, input: &Path) -> Result<()> {
let tmp_working_dir = tempdir()?;
let mut cmd = self.build_command(
tmp_working_dir.path(),
None,
None,
None,
Expand Down Expand Up @@ -294,7 +305,15 @@ impl LibFuzzer {
/// least able to satisfy the fuzzer's shared library dependencies. User-authored
/// dynamic loading may still fail later on, e.g. in `LLVMFuzzerInitialize()`.
async fn check_help(&self) -> Result<()> {
let mut cmd = self.build_command(None, None, None, Some(&["-help=1".as_ref()]), None)?;
let tmp_working_dir = tempdir()?;
let mut cmd = self.build_command(
tmp_working_dir.path(),
None,
None,
None,
Some(&["-help=1".as_ref()]),
None,
)?;

let result = cmd
.spawn()
Expand Down Expand Up @@ -326,7 +345,8 @@ impl LibFuzzer {
}

async fn find_missing_libraries(&self) -> Result<(Vec<String>, Vec<String>)> {
let cmd = self.build_std_command(None, None, None, None, None)?;
let tmp_working_dir = tempdir()?;
let cmd = self.build_std_command(tmp_working_dir.path(), None, None, None, None, None)?;

#[cfg(target_os = "linux")]
let blocking = move || dynamic_library::linux::find_missing(cmd);
Expand All @@ -343,6 +363,7 @@ impl LibFuzzer {

pub fn fuzz(
&self,
working_dir: &Path,
fault_dir: impl AsRef<Path>,
corpus_dir: impl AsRef<Path>,
extra_corpus_dirs: &[impl AsRef<Path>],
Expand All @@ -357,6 +378,7 @@ impl LibFuzzer {
let artifact_prefix = artifact_prefix(fault_dir.as_ref());

let mut cmd = self.build_command(
working_dir,
Some(fault_dir.as_ref()),
Some(corpus_dir.as_ref()),
Some(&extra_corpus_dirs),
Expand Down Expand Up @@ -406,8 +428,10 @@ impl LibFuzzer {
corpus_dir: impl AsRef<Path>,
extra_corpus_dirs: &[impl AsRef<Path>],
) -> Result<LibFuzzerMergeOutput> {
let tmp_working_dir = tempdir()?;
let extra_corpus_dirs: Vec<&Path> = extra_corpus_dirs.iter().map(|x| x.as_ref()).collect();
let mut cmd = self.build_command(
tmp_working_dir.path(),
None,
Some(corpus_dir.as_ref()),
Some(&extra_corpus_dirs),
Expand Down

0 comments on commit 5c34c24

Please sign in to comment.