mirror of
https://github.com/microsoft/onefuzz.git
synced 2025-06-17 20:38:06 +00:00
provide parsed call stack details asan logs (#591)
For a given entry in a call stack, this parses out the following: line, function name, function offset, source file name, source file line, module path, and module offset. Additionally, this provides a code-generated libclusterfuzz port of the regular expressions used for stack minimization. For an example of the minimization, instead of: ```json [ "#0 0x56512a9c1418 in __sanitizer_print_stack_trace /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_stack.cpp:86:3", "#1 0x56512aaaa42d in fuzzer::PrintStackTrace() third_party/libFuzzer/src/FuzzerUtil.cpp:205:5", "#2 0x56512aa6a85e in fuzzer::Fuzzer::CrashCallback() third_party/libFuzzer/src/FuzzerLoop.cpp:232:3", "#3 0x56512aa6a7df in fuzzer::Fuzzer::StaticCrashSignalCallback() third_party/libFuzzer/src/FuzzerLoop.cpp:203:6", "#4 0x56512aaab948 in fuzzer::CrashHandler(int, siginfo_t*, void*) third_party/libFuzzer/src/FuzzerUtilPosix.cpp:46:3", "#5 0x7f1ee3f0188f (/lib/x86_64-linux-gnu/libpthread.so.0+0x1288f)", "#6 0x56512a9e5aa1 in Json::OurReader::parse(char const*, char const*, Json::Value&, bool) third_party/jsoncpp/source/src/lib_json/json_reader.cpp:1062:10", "#7 0x56512a9eedb4 in Json::OurCharReader::parse(char const*, char const*, Json::Value*, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char> >*) third_party/jsoncpp/source/src/lib_json/json_reader.cpp:1899:23", "#8 0x56512a9e03a3 in LLVMFuzzerTestOneInput third_party/jsoncpp/fuzzers/json_fuzzer.cc:39:24", "#9 0x56512aa6d0cf in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) third_party/libFuzzer/src/FuzzerLoop.cpp:556:15", "#10 0x56512aa3b7da in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) third_party/libFuzzer/src/FuzzerDriver.cpp:292:6", "#11 0x56512aa4108a in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) third_party/libFuzzer/src/FuzzerDriver.cpp:774:9","#12 0x56512aa821ac in main third_party/libFuzzer/src/FuzzerMain.cpp:19:10", "#13 0x7f1ee3361b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310", ] ``` The minimized call stack is: ```json [ "Json::OurReader::parse(char const*, char const*, Json::Value&, bool)", "Json::OurCharReader::parse(char const*, char const*, Json::Value*, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char> >*)", "json_fuzzer.cc" ] ``` This also provides a naïve function name list, which comes close to Clusterfuzz's function identification. This would result in: ```json [ "Json::OurReader::parse", "Json::OurCharReader::parse", "json_fuzzer.cc" ] ``` Lastly, for our `stack hash` functionality used by the crash reporting task, those now provide the ability to specify the number of frames to include when building the hash.
This commit is contained in:
@ -33,6 +33,7 @@ onefuzz = { path = "../onefuzz" }
|
||||
storage-queue = { path = "../storage-queue" }
|
||||
reqwest-retry = { path = "../reqwest-retry" }
|
||||
onefuzz-telemetry = { path = "../onefuzz-telemetry" }
|
||||
stacktrace-parser = { path = "../stacktrace-parser" }
|
||||
path-absolutize = "3.0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -58,6 +58,7 @@ pub fn build_report_config(
|
||||
check_retry_count,
|
||||
check_queue,
|
||||
crashes,
|
||||
minimized_stack_depth: None,
|
||||
input_queue,
|
||||
no_repro,
|
||||
reports,
|
||||
|
@ -50,6 +50,7 @@ pub fn build_report_config(
|
||||
target_timeout,
|
||||
check_retry_count,
|
||||
check_fuzzer_help,
|
||||
minimized_stack_depth: None,
|
||||
input_queue,
|
||||
check_queue,
|
||||
crashes,
|
||||
|
@ -3,17 +3,17 @@
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use futures::StreamExt;
|
||||
use onefuzz::{asan::AsanLog, blob::BlobUrl, monitor::DirectoryMonitor, syncdir::SyncedDir};
|
||||
use onefuzz::{blob::BlobUrl, monitor::DirectoryMonitor, syncdir::SyncedDir};
|
||||
use onefuzz_telemetry::{
|
||||
Event::{new_report, new_unable_to_reproduce, new_unique_report},
|
||||
EventData,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stacktrace_parser::CrashLog;
|
||||
use std::path::{Path, PathBuf};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||
pub struct CrashReport {
|
||||
pub input_sha256: String,
|
||||
|
||||
@ -27,9 +27,18 @@ pub struct CrashReport {
|
||||
pub crash_site: String,
|
||||
|
||||
pub call_stack: Vec<String>,
|
||||
|
||||
pub call_stack_sha256: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub minimized_stack: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub minimized_stack_sha256: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub minimized_stack_function_names: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub minimized_stack_function_names_sha256: Option<String>,
|
||||
|
||||
pub asan_log: Option<String>,
|
||||
|
||||
pub task_id: Uuid,
|
||||
@ -123,24 +132,42 @@ impl From<BlobUrl> for InputBlob {
|
||||
|
||||
impl CrashReport {
|
||||
pub fn new(
|
||||
asan_log: AsanLog,
|
||||
crash_log: CrashLog,
|
||||
task_id: Uuid,
|
||||
job_id: Uuid,
|
||||
executable: impl Into<PathBuf>,
|
||||
input_blob: Option<InputBlob>,
|
||||
input_sha256: String,
|
||||
minimized_stack_depth: Option<usize>,
|
||||
) -> Self {
|
||||
let call_stack_sha256 = crash_log.call_stack_sha256();
|
||||
let minimized_stack_sha256 = if crash_log.minimized_stack.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(crash_log.minimized_stack_sha256(minimized_stack_depth))
|
||||
};
|
||||
|
||||
let minimized_stack_function_names_sha256 =
|
||||
if crash_log.minimized_stack_function_names.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(crash_log.minimized_stack_function_names_sha256(minimized_stack_depth))
|
||||
};
|
||||
Self {
|
||||
input_sha256,
|
||||
input_blob,
|
||||
executable: executable.into(),
|
||||
crash_type: asan_log.fault_type().into(),
|
||||
crash_site: asan_log.summary().into(),
|
||||
call_stack: asan_log.call_stack().to_vec(),
|
||||
call_stack_sha256: asan_log.call_stack_sha256(),
|
||||
asan_log: Some(asan_log.text().to_string()),
|
||||
scariness_score: asan_log.scariness_score(),
|
||||
scariness_description: asan_log.scariness_description().to_owned(),
|
||||
crash_type: crash_log.fault_type,
|
||||
crash_site: crash_log.summary,
|
||||
call_stack_sha256,
|
||||
minimized_stack: crash_log.minimized_stack,
|
||||
minimized_stack_sha256,
|
||||
minimized_stack_function_names: crash_log.minimized_stack_function_names,
|
||||
minimized_stack_function_names_sha256,
|
||||
call_stack: crash_log.call_stack,
|
||||
asan_log: Some(crash_log.text),
|
||||
scariness_score: crash_log.scariness_score,
|
||||
scariness_description: crash_log.scariness_description,
|
||||
task_id,
|
||||
job_id,
|
||||
}
|
||||
|
@ -47,6 +47,9 @@ pub struct Config {
|
||||
#[serde(default = "default_bool_true")]
|
||||
pub check_queue: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub minimized_stack_depth: Option<usize>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub common: CommonConfig,
|
||||
}
|
||||
@ -132,6 +135,7 @@ impl<'a> GenericReportProcessor<'a> {
|
||||
&self.config.target_exe,
|
||||
input_blob,
|
||||
input_sha256,
|
||||
self.config.minimized_stack_depth,
|
||||
);
|
||||
Ok(CrashTestResult::CrashReport(crash_report))
|
||||
} else if let Some(crash) = test_report.crash {
|
||||
@ -144,11 +148,9 @@ impl<'a> GenericReportProcessor<'a> {
|
||||
crash_type: crash.crash_type,
|
||||
crash_site: crash.crash_site,
|
||||
call_stack_sha256,
|
||||
asan_log: None,
|
||||
scariness_score: None,
|
||||
scariness_description: None,
|
||||
task_id,
|
||||
job_id,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(CrashTestResult::CrashReport(crash_report))
|
||||
|
@ -36,6 +36,9 @@ pub struct Config {
|
||||
#[serde(default)]
|
||||
pub check_retry_count: u64,
|
||||
|
||||
#[serde(default)]
|
||||
pub minimized_stack_depth: Option<usize>,
|
||||
|
||||
#[serde(default = "default_bool_true")]
|
||||
pub check_queue: bool,
|
||||
|
||||
@ -140,6 +143,7 @@ impl AsanProcessor {
|
||||
&self.config.target_exe,
|
||||
input_blob,
|
||||
input_sha256,
|
||||
self.config.minimized_stack_depth,
|
||||
);
|
||||
Ok(CrashTestResult::CrashReport(crash_report))
|
||||
}
|
||||
|
Reference in New Issue
Block a user