Check for missing shared libs on failed LibFuzzer -help check (#1812)

This commit is contained in:
Joe Ranweiler
2022-04-21 12:49:44 -07:00
committed by GitHub
parent 3e5c6d7658
commit 2075d55edf
3 changed files with 66 additions and 4 deletions

1
src/agent/Cargo.lock generated
View File

@ -1974,6 +1974,7 @@ dependencies = [
"cpp_demangle", "cpp_demangle",
"debugger", "debugger",
"dunce", "dunce",
"dynamic-library",
"futures", "futures",
"futures-util", "futures-util",
"hex", "hex",

View File

@ -12,6 +12,7 @@ async-trait = "0.1"
base64 = "0.13" base64 = "0.13"
bytes = "1.1" bytes = "1.1"
dunce = "1.0" dunce = "1.0"
dynamic-library = { path = "../dynamic-library" }
futures = "0.3" futures = "0.3"
futures-util = "0.3" futures-util = "0.3"
hex = "0.4" hex = "0.4"

View File

@ -56,15 +56,35 @@ impl<'a> LibFuzzer<'a> {
} }
} }
// Build an async `Command`.
async fn build_command( async fn build_command(
&self, &self,
fault_dir: Option<&Path>, fault_dir: Option<&Path>,
corpus_dir: Option<&Path>, corpus_dir: Option<&Path>,
extra_corpus_dirs: Option<&[&Path]>, extra_corpus_dirs: Option<&[&Path]>,
) -> Result<Command> { ) -> Result<Command> {
let mut cmd = Command::new(&self.exe); let std_cmd = self
cmd.kill_on_drop(true) .build_std_command(fault_dir, corpus_dir, extra_corpus_dirs)
.env(PATH, get_path_with_directory(PATH, &self.setup_dir)?) .await?;
// Make async.
let mut cmd = Command::from(std_cmd);
// Terminate the process if the `Child` handle is dropped.
cmd.kill_on_drop(true);
Ok(cmd)
}
// Build a non-async `Command`.
async fn build_std_command(
&self,
fault_dir: Option<&Path>,
corpus_dir: Option<&Path>,
extra_corpus_dirs: Option<&[&Path]>,
) -> Result<std::process::Command> {
let mut cmd = std::process::Command::new(&self.exe);
cmd.env(PATH, get_path_with_directory(PATH, &self.setup_dir)?)
.env_remove("RUST_LOG") .env_remove("RUST_LOG")
.stdin(Stdio::null()) .stdin(Stdio::null())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
@ -199,6 +219,9 @@ impl<'a> LibFuzzer<'a> {
Ok(()) Ok(())
} }
/// Invoke `{target_exe} -help=1`. If this succeeds, then the dynamic linker is at
/// 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<()> { async fn check_help(&self) -> Result<()> {
let mut cmd = self.build_command(None, None, None).await?; let mut cmd = self.build_command(None, None, None).await?;
cmd.arg("-help=1"); cmd.arg("-help=1");
@ -209,12 +232,49 @@ impl<'a> LibFuzzer<'a> {
.wait_with_output() .wait_with_output()
.await .await
.with_context(|| format_err!("libfuzzer failed to run: {}", self.exe.display()))?; .with_context(|| format_err!("libfuzzer failed to run: {}", self.exe.display()))?;
if !result.status.success() { if !result.status.success() {
bail!("fuzzer does not respond to '-help=1'. output:{:?}", result); // To provide user-actionable errors, try to identify any missing shared libraries.
match self.find_missing_libraries().await {
Ok(missing) => {
if missing.is_empty() {
bail!("fuzzer does not respond to '-help=1'. no missing shared libraries detected. output: {:?}", result);
} else {
let missing = missing.join(", ");
bail!("fuzzer does not respond to '-help=1'. missing shared libraries: {}. output: {:?}", missing, result);
}
}
Err(err) => {
bail!("fuzzer does not respond to '-help=1'. additional error while checking for missing shared libraries: {}. output: {:?}", err, result);
}
}
} }
Ok(()) Ok(())
} }
#[cfg(not(target_os = "macos"))]
async fn find_missing_libraries(&self) -> Result<Vec<String>> {
let cmd = self.build_std_command(None, None, None).await?;
#[cfg(target_os = "linux")]
let blocking = move || dynamic_library::linux::find_missing(cmd);
#[cfg(target_os = "windows")]
let blocking = move || dynamic_library::windows::find_missing(cmd);
let missing = tokio::task::spawn_blocking(blocking).await??;
let missing = missing.into_iter().map(|m| m.name).collect();
Ok(missing)
}
#[cfg(target_os = "macos")]
async fn find_missing_libraries(&self) -> Result<Vec<String>> {
todo!()
}
pub async fn fuzz( pub async fn fuzz(
&self, &self,
fault_dir: impl AsRef<Path>, fault_dir: impl AsRef<Path>,