mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-17 12:28:07 +00:00
Check for missing shared libs on failed LibFuzzer -help
check (#1812)
This commit is contained in:
1
src/agent/Cargo.lock
generated
1
src/agent/Cargo.lock
generated
@ -1974,6 +1974,7 @@ dependencies = [
|
|||||||
"cpp_demangle",
|
"cpp_demangle",
|
||||||
"debugger",
|
"debugger",
|
||||||
"dunce",
|
"dunce",
|
||||||
|
"dynamic-library",
|
||||||
"futures",
|
"futures",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex",
|
"hex",
|
||||||
|
@ -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"
|
||||||
|
@ -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>,
|
||||||
|
Reference in New Issue
Block a user