Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support MemorySanitizer for casr-san #249

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions casr/src/bin/casr-cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,16 @@
tree.expand_item(row);
}

if !report.msan_report.is_empty() {
row = tree
.insert_container_item("MsanReport".to_string(), Placement::After, row)
.unwrap();
report.msan_report.iter().for_each(|e| {
tree.insert_item(e.clone(), Placement::LastChild, row);
});
tree.expand_item(row);
}

Check warning on line 422 in casr/src/bin/casr-cli.rs

View check run for this annotation

Codecov / codecov/patch

casr/src/bin/casr-cli.rs#L414-L422

Added lines #L414 - L422 were not covered by tests

if !report.ubsan_report.is_empty() {
row = tree
.insert_container_item("UbsanReport".to_string(), Placement::After, row)
Expand Down Expand Up @@ -656,6 +666,10 @@
select.add_item("AsanReport", report.asan_report.join("\n"));
}

if !report.msan_report.is_empty() {
select.add_item("MsanReport", report.msan_report.join("\n"));
}

Check warning on line 671 in casr/src/bin/casr-cli.rs

View check run for this annotation

Codecov / codecov/patch

casr/src/bin/casr-cli.rs#L669-L671

Added lines #L669 - L671 were not covered by tests

if !report.ubsan_report.is_empty() {
select.add_item("UbsanReport", report.ubsan_report.join("\n"));
}
Expand Down
18 changes: 17 additions & 1 deletion casr/src/bin/casr-san.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
.collect();
let rasan_start =
Regex::new(r"==\d+==\s*ERROR: (LeakSanitizer|AddressSanitizer|libFuzzer):").unwrap();
let rmsan_start = Regex::new(r"==\d+==\s*WARNING: MemorySanitizer:").unwrap();
if let Some(report_start) = san_stderr_list
.iter()
.position(|line| rasan_start.is_match(line))
Expand All @@ -233,6 +234,21 @@
eprintln!("Couldn't estimate severity. {}", severity.err().unwrap());
}
report.stacktrace = AsanStacktrace::extract_stacktrace(&report.asan_report.join("\n"))?;
} else if let Some(report_start) = san_stderr_list
.iter()
.position(|line| rmsan_start.is_match(line))
{
// Set MSAN report in casr report.
let report_end = san_stderr_list.iter().rposition(|s| !s.is_empty()).unwrap() + 1;
report.msan_report = Vec::from(&san_stderr_list[report_start..report_end]);
let context = AsanContext(report.msan_report.clone());
let severity = context.severity();
if let Ok(severity) = severity {
report.execution_class = severity;
} else {
eprintln!("Couldn't estimate severity. {}", severity.err().unwrap());
}

Check warning on line 250 in casr/src/bin/casr-san.rs

View check run for this annotation

Codecov / codecov/patch

casr/src/bin/casr-san.rs#L249-L250

Added lines #L249 - L250 were not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we may move the duplicate code here inside a function

report.stacktrace = AsanStacktrace::extract_stacktrace(&report.msan_report.join("\n"))?;
} else {
// Get termination signal.
if let Some(signal) = sanitizers_result.status.signal() {
Expand Down Expand Up @@ -287,7 +303,7 @@
}

// Get stacktrace to find crash line.
stacktrace = if !report.asan_report.is_empty() {
stacktrace = if !report.asan_report.is_empty() || !report.msan_report.is_empty() {
AsanStacktrace::parse_stacktrace(&report.stacktrace)?
} else {
let mut parsed_stacktrace = GdbStacktrace::parse_stacktrace(&report.stacktrace)?;
Expand Down
15 changes: 15 additions & 0 deletions casr/tests/casr_tests/test_msan.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <stdio.h>

void set_val(bool &b, const int val) {
if (val > 1) {
b = false;
}
}

int main(const int argc, const char *[]) {
bool b;
set_val(b, argc);
if (b) {
printf("value set\n");
}
}
62 changes: 62 additions & 0 deletions casr/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3080,6 +3080,68 @@ fn test_casr_san() {
panic!("Couldn't parse json report file.");
}

// Msan test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imho, this needs to be taken out into a separate test.

let paths = [
abs_path("tests/casr_tests/test_msan.cpp"),
abs_path("tests/tmp_tests_casr/test_msan"),
];

let clang = Command::new("bash")
.arg("-c")
.arg(format!(
"clang++ -fsanitize=memory -O0 {} -o {}",
&paths[0], &paths[1]
))
.status()
.expect("failed to execute clang++");

assert!(clang.success());

let output = Command::new(*EXE_CASR_SAN)
.args(["--stdout", "--", &paths[1]])
.output()
.expect("failed to start casr-san");

assert!(
output.status.success(),
"Stdout: {}\n. Stderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);

let report: Result<Value, _> = serde_json::from_slice(&output.stdout);
if let Ok(report) = report {
let severity_type = report["CrashSeverity"]["Type"].as_str().unwrap();
let severity_desc = report["CrashSeverity"]["ShortDescription"]
.as_str()
.unwrap()
.to_string();
let stacktrace = report["Stacktrace"]
.as_array()
.unwrap()
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>();

assert!(stacktrace.len() > 2);
assert!(stacktrace[0].contains("in main"));
assert_eq!(severity_type, "NOT_EXPLOITABLE");
assert_eq!(severity_desc, "use-of-uninitialized-value");
assert!(
report["CrashLine"]
.as_str()
.unwrap()
.eq("tests/casr_tests/test_msan.cpp:12:9")
// We build a test on ubuntu18 and run it on ubuntu20.
// Debug information is broken.
|| report["CrashLine"]
.as_str()
.unwrap()
.contains("test_msan+0x") // We can't hardcode the offset because we rebuild tests every time.
);
} else {
panic!("Couldn't parse json report file.");
}
let _ = std::fs::remove_file(&paths[1]);
// Test casr-san stdin
let paths = [
Expand Down
2 changes: 2 additions & 0 deletions libcasr/src/asan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ impl Severity for AsanContext {
}
if asan_report[0].contains("LeakSanitizer") {
ExecutionClass::find("memory-leaks")
} else if asan_report[0].contains("MemorySanitizer") {
ExecutionClass::find("use-of-uninitialized-value")
} else {
let summary =
Regex::new(r"SUMMARY: *(AddressSanitizer|libFuzzer): ([A-Za-z_\-\(\)]+)").unwrap();
Expand Down
8 changes: 7 additions & 1 deletion libcasr/src/execution_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub struct ExecutionClass {
/// Instances of `ExecutionClass` structure.
/// Add new classes to the end of array.
/// TODO: Think about adding some ID for array element.
pub const CLASSES: &[(&str, &str, &str, &str); 74] = &[
pub const CLASSES: &[(&str, &str, &str, &str); 75] = &[
(
"EXPLOITABLE",
"SegFaultOnPc",
Expand Down Expand Up @@ -485,6 +485,12 @@ pub const CLASSES: &[(&str, &str, &str, &str); 74] = &[
"Attempt to overwrite constant input",
"Fuzz target overwrites its constant input.",
),
(
"NOT_EXPLOITABLE",
"use-of-uninitialized-value",
"Use of uninitialized value",
"The target attempted to access memory that was not initialized.",
),
];

impl ExecutionClass {
Expand Down
20 changes: 19 additions & 1 deletion libcasr/src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,13 @@ pub struct CrashReport {
)]
#[cfg_attr(feature = "serde", serde(default))]
pub asan_report: Vec<String>,
/// Msan report.
#[cfg_attr(
feature = "serde",
serde(rename(serialize = "MsanReport", deserialize = "MsanReport"))
)]
#[cfg_attr(feature = "serde", serde(default))]
pub msan_report: Vec<String>,
/// Ubsan report.
#[cfg_attr(
feature = "serde",
Expand Down Expand Up @@ -584,7 +591,7 @@ impl CrashReport {
/// Filter frames from the stack trace that are not related to analyzed code containing crash
/// and return it as `Stacktrace` struct
pub fn filtered_stacktrace(&self) -> Result<Stacktrace> {
let mut rawtrace = if !self.asan_report.is_empty() {
let mut rawtrace = if !self.asan_report.is_empty() || !self.msan_report.is_empty() {
AsanStacktrace::parse_stacktrace(&self.stacktrace)?
} else if !self.python_report.is_empty() {
PythonStacktrace::parse_stacktrace(&self.stacktrace)?
Expand Down Expand Up @@ -743,6 +750,12 @@ impl fmt::Display for CrashReport {
report += &(self.asan_report.join("\n") + "\n");
}

// MSANreport
if !self.msan_report.is_empty() {
report += "\n===MsanReport===\n";
report += &(self.msan_report.join("\n") + "\n");
}

// UBSANreport
if !self.ubsan_report.is_empty() {
report += "\n===UbsanReport===\n";
Expand Down Expand Up @@ -892,6 +905,8 @@ mod tests {
"==363912==ERROR: AddressSanitizer: SEGV on unknown address 0xffffffffffffffe0 (pc 0x0000004ca0e0 bp 0x7fffffff9980 sp 0x7fffffff9928 T0)".to_string(),
"==363912==The signal is caused by a READ memory access.".to_string(),
];
report.msan_report =
vec!["==26629==WARNING: MemorySanitizer: use-of-uninitialized-value".to_string()];
report.ubsan_report = vec![
"/home/hkctkuy/github/casr/casr/tests/tmp_tests_casr/test_casr_ubsan/test_ubsan.cpp:4:29: runtime error: signed integer overflow: 65535 * 32769 cannot be represented in type 'int'".to_string(),
"SUMMARY: UndefinedBehaviorSanitizer: signed-integer-overflow /home/hkctkuy/github/casr/casr/tests/tmp_tests_casr/test_casr_ubsan/test_ubsan.cpp:4:29 in".to_string(),
Expand Down Expand Up @@ -986,6 +1001,9 @@ mod tests {
"==363912==ERROR: AddressSanitizer: SEGV on unknown address 0xffffffffffffffe0 (pc 0x0000004ca0e0 bp 0x7fffffff9980 sp 0x7fffffff9928 T0)".to_string(),
"==363912==The signal is caused by a READ memory access.".to_string(),
"".to_string(),
"===MsanReport===".to_string(),
"==26629==WARNING: MemorySanitizer: use-of-uninitialized-value".to_string(),
"".to_string(),
"===UbsanReport===".to_string(),
"/home/hkctkuy/github/casr/casr/tests/tmp_tests_casr/test_casr_ubsan/test_ubsan.cpp:4:29: runtime error: signed integer overflow: 65535 * 32769 cannot be represented in type 'int'".to_string(),
"SUMMARY: UndefinedBehaviorSanitizer: signed-integer-overflow /home/hkctkuy/github/casr/casr/tests/tmp_tests_casr/test_casr_ubsan/test_ubsan.cpp:4:29 in".to_string(),
Expand Down
Loading