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

Commit 256f261

Browse files
authored
Parse .NET exception stacks in crash output (#2988)
1 parent 5bbf95e commit 256f261

File tree

14 files changed

+662
-87
lines changed

14 files changed

+662
-87
lines changed

src/agent/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/agent/onefuzz/examples/test-input.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ async fn main() -> Result<()> {
8989
println!();
9090
println!("[+] verbose test result:");
9191
println!();
92-
println!("{test_result:?}");
92+
println!("{test_result:#?}");
9393

9494
Ok(())
9595
}

src/agent/onefuzz/src/input_tester.rs

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl<'a> Tester<'a> {
204204
cmd.args(args).stdin(Stdio::null());
205205
cmd.envs(env);
206206

207-
let (sender, receiver) = std::sync::mpsc::channel();
207+
let (sender, receiver) = tokio::sync::oneshot::channel();
208208

209209
// Create two async tasks: one off-thread task for the blocking triage run,
210210
// and one task that will kill the triage target if we time out.
@@ -215,60 +215,67 @@ impl<'a> Tester<'a> {
215215
let triage = crate::triage::TriageCommand::new(cmd)?;
216216

217217
// Share the new child ID with main thread.
218-
sender.send(triage.pid())?;
218+
let Ok(()) = sender.send(triage.pid()) else { bail!("unable to send PID") };
219219

220220
// The target run is blocking, and may hang.
221221
triage.run()
222222
});
223223

224224
// Save the new process ID of the spawned triage target, so we can try to kill
225225
// the (possibly hung) target out-of-band, if we time out.
226-
let target_pid = receiver.recv()?;
226+
let target_pid = match receiver.await {
227+
Ok(pid) => pid,
228+
Err(e) => {
229+
if triage.is_finished() {
230+
bail!("triage run failed: {:?}", triage.await.unwrap().err());
231+
} else {
232+
bail!("unable to receive PID: {}", e);
233+
}
234+
}
235+
};
227236

228237
let timeout = tokio::time::timeout(self.timeout, triage).await;
229-
let crash = if timeout.is_err() {
238+
if timeout.is_err() {
230239
// Yes. Try to kill the target process, if hung.
231240
kill(target_pid, Signal::SIGKILL)?;
232241
bail!("process timed out");
233-
} else {
234-
let report = timeout???;
235-
236-
if let Some(crash) = report.crashes.last() {
237-
let crash_thread = crash
238-
.threads
239-
.get(&crash.tid.as_raw())
240-
.ok_or_else(|| anyhow!("no thread info for crash thread ID = {}", crash.tid))?;
241-
242-
let call_stack: Vec<_> = crash_thread
243-
.callstack
244-
.iter()
245-
.enumerate()
246-
.map(|(idx, frame)| StackEntry {
247-
line: format!("#{idx} {frame}"),
248-
address: Some(frame.addr.0),
249-
function_name: frame.function.as_ref().map(|x| x.name.clone()),
250-
function_offset: frame.function.as_ref().map(|x| x.offset),
251-
module_path: frame.module.as_ref().map(|x| x.name.clone()),
252-
module_offset: frame.module.as_ref().map(|x| x.offset),
253-
source_file_name: None,
254-
source_file_line: None,
255-
source_file_path: None,
256-
})
257-
.collect();
258-
259-
let crash_type = crash.signal.to_string();
260-
let sanitizer = crash_type.clone();
261-
let fault_type = crash_type;
262-
263-
Some(CrashLog::new(
264-
None, None, sanitizer, fault_type, None, None, call_stack,
265-
)?)
266-
} else {
267-
None
268-
}
242+
}
243+
244+
let report = timeout???;
245+
246+
let Some(crash) = report.crashes.last() else {
247+
return Ok(None);
269248
};
270249

271-
Ok(crash)
250+
let crash_thread = crash
251+
.threads
252+
.get(&crash.tid.as_raw())
253+
.ok_or_else(|| anyhow!("no thread info for crash thread ID = {}", crash.tid))?;
254+
255+
let call_stack: Vec<_> = crash_thread
256+
.callstack
257+
.iter()
258+
.enumerate()
259+
.map(|(idx, frame)| StackEntry {
260+
line: format!("#{idx} {frame}"),
261+
address: Some(frame.addr.0),
262+
function_name: frame.function.as_ref().map(|x| x.name.clone()),
263+
function_offset: frame.function.as_ref().map(|x| x.offset),
264+
module_path: frame.module.as_ref().map(|x| x.name.clone()),
265+
module_offset: frame.module.as_ref().map(|x| x.offset),
266+
source_file_name: None,
267+
source_file_line: None,
268+
source_file_path: None,
269+
})
270+
.collect();
271+
272+
let crash_type = crash.signal.to_string();
273+
let sanitizer = crash_type.clone();
274+
let fault_type = crash_type;
275+
276+
Ok(Some(CrashLog::new(
277+
None, None, sanitizer, fault_type, None, None, call_stack,
278+
)?))
272279
}
273280

274281
pub async fn test_input(&self, input_file: impl AsRef<Path>) -> Result<TestResult> {

src/agent/onefuzz/src/libfuzzer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,13 @@ impl LibFuzzer {
353353
.check_asan_stderr(true)
354354
.check_retry_count(retry)
355355
.add_setup_to_path(true)
356-
.set_optional(timeout, |tester, timeout| tester.timeout(timeout));
356+
.set_optional(timeout, Tester::timeout);
357357

358358
if cfg!(target_family = "unix") {
359359
tester = tester.add_setup_to_ld_library_path(true);
360360
}
361361

362-
tester.test_input(test_input.as_ref()).await
362+
tester.test_input(test_input).await
363363
}
364364

365365
pub async fn merge(

src/agent/stacktrace-parser/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ license = "MIT"
99
anyhow = "1.0"
1010
hex = "0.4"
1111
regex = "1.7.1"
12+
lazy_static = "1.4.0"
1213
sha2 = "0.10.2"
1314
serde = { version = "1.0", features = ["derive"] }
1415
serde_json = "1.0"
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
{
2+
"text": "Unhandled exception. System.Exception: No fuzzing target specified\n ---> System.Exception: Missing `LIBFUZZER_DOTNET_TARGET` environment variables: LIBFUZZER_DOTNET_TARGET_ASSEMBLY, LIBFUZZER_DOTNET_TARGET_CLASS, LIBFUZZER_DOTNET_TARGET_METHOD\n at LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironmentVars() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 190\n at LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 166\n --- End of inner exception stack trace ---\n at LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 171\n at LibFuzzerDotnetLoader.Program.TryMain() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 70\n at LibFuzzerDotnetLoader.Program.Main(String[] args) in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 57\n",
3+
"sanitizer": ".NET",
4+
"summary": "Unhandled exception. System.Exception: No fuzzing target specified ---> System.Exception: Missing `LIBFUZZER_DOTNET_TARGET` environment variables: LIBFUZZER_DOTNET_TARGET_ASSEMBLY, LIBFUZZER_DOTNET_TARGET_CLASS, LIBFUZZER_DOTNET_TARGET_METHOD",
5+
"fault_type": "Unhandled exception",
6+
"call_stack": [
7+
" at LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 171",
8+
" at LibFuzzerDotnetLoader.Program.TryMain() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 70",
9+
" at LibFuzzerDotnetLoader.Program.Main(String[] args) in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 57"
10+
],
11+
"full_stack_details": [
12+
{
13+
"line": " at LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 171",
14+
"function_name": "LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment()",
15+
"source_file_name": "Program.cs",
16+
"source_file_path": "/workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs",
17+
"source_file_line": 171
18+
},
19+
{
20+
"line": " at LibFuzzerDotnetLoader.Program.TryMain() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 70",
21+
"function_name": "LibFuzzerDotnetLoader.Program.TryMain()",
22+
"source_file_name": "Program.cs",
23+
"source_file_path": "/workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs",
24+
"source_file_line": 70
25+
},
26+
{
27+
"line": " at LibFuzzerDotnetLoader.Program.Main(String[] args) in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 57",
28+
"function_name": "LibFuzzerDotnetLoader.Program.Main(String[] args)",
29+
"source_file_name": "Program.cs",
30+
"source_file_path": "/workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs",
31+
"source_file_line": 57
32+
}
33+
],
34+
"full_stack_names": [
35+
"LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment",
36+
"LibFuzzerDotnetLoader.Program.TryMain",
37+
"LibFuzzerDotnetLoader.Program.Main"
38+
],
39+
"minimized_stack_details": [
40+
{
41+
"line": " at LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 171",
42+
"function_name": "LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment()",
43+
"source_file_name": "Program.cs",
44+
"source_file_path": "/workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs",
45+
"source_file_line": 171
46+
},
47+
{
48+
"line": " at LibFuzzerDotnetLoader.Program.TryMain() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 70",
49+
"function_name": "LibFuzzerDotnetLoader.Program.TryMain()",
50+
"source_file_name": "Program.cs",
51+
"source_file_path": "/workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs",
52+
"source_file_line": 70
53+
},
54+
{
55+
"line": " at LibFuzzerDotnetLoader.Program.Main(String[] args) in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 57",
56+
"function_name": "LibFuzzerDotnetLoader.Program.Main(String[] args)",
57+
"source_file_name": "Program.cs",
58+
"source_file_path": "/workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs",
59+
"source_file_line": 57
60+
}
61+
],
62+
"minimized_stack": [
63+
" at LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 171",
64+
" at LibFuzzerDotnetLoader.Program.TryMain() in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 70",
65+
" at LibFuzzerDotnetLoader.Program.Main(String[] args) in /workspaces/onefuzz/src/agent/LibFuzzerDotnetLoader/Program.cs:line 57"
66+
],
67+
"minimized_stack_function_names": [
68+
"LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment",
69+
"LibFuzzerDotnetLoader.Program.TryMain",
70+
"LibFuzzerDotnetLoader.Program.Main"
71+
],
72+
"minimized_stack_function_lines": [
73+
"LibFuzzerDotnetLoader.LibFuzzerDotnetTarget.FromEnvironment() Program.cs:171",
74+
"LibFuzzerDotnetLoader.Program.TryMain() Program.cs:70",
75+
"LibFuzzerDotnetLoader.Program.Main(String[] args) Program.cs:57"
76+
]
77+
}

0 commit comments

Comments
 (0)