diff --git a/casr/src/bin/casr-csharp.rs b/casr/src/bin/casr-csharp.rs index ce26ac2d..48c5b1e8 100644 --- a/casr/src/bin/casr-csharp.rs +++ b/casr/src/bin/casr-csharp.rs @@ -141,6 +141,9 @@ fn main() -> Result<()> { if let Some(exception) = CSharpException::parse_exception(&report_str) { report.execution_class = exception; } + } else { + // Call casr-san + return util::call_casr_san(&matches, &argv, "casr-csharp"); } let stacktrace = CSharpStacktrace::parse_stacktrace(&report.stacktrace)?; diff --git a/casr/src/triage.rs b/casr/src/triage.rs index 1dd4fd31..99d59df2 100644 --- a/casr/src/triage.rs +++ b/casr/src/triage.rs @@ -223,7 +223,10 @@ pub fn fuzzing_crash_triage_pipeline( .join(". ") ); } else { - bail!("{}", String::from_utf8_lossy(&casr_cluster_d.stderr)); + bail!( + "{}", + String::from_utf8_lossy(&casr_cluster_d.stderr).trim_end() + ); } if !matches.get_flag("no-cluster") { @@ -251,7 +254,10 @@ pub fn fuzzing_crash_triage_pipeline( String::from_utf8_lossy(&casr_cluster_c.stdout).trim_end() ); } else { - error!("{}", String::from_utf8_lossy(&casr_cluster_c.stderr)); + error!( + "{}", + String::from_utf8_lossy(&casr_cluster_c.stderr).trim_end() + ); } // Remove reports from deduplication phase. They are in clusters now. diff --git a/casr/tests/casr_tests/csharp/test_casr_csharp_native/native.cpp b/casr/tests/casr_tests/csharp/test_casr_csharp_native/native.cpp new file mode 100644 index 00000000..201bad9f --- /dev/null +++ b/casr/tests/casr_tests/csharp/test_casr_csharp_native/native.cpp @@ -0,0 +1,7 @@ +#include + +extern "C" void seg(int len) +{ + int a[10]; + a[len] = -1; +} diff --git a/casr/tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.cs b/casr/tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.cs new file mode 100644 index 00000000..2f626725 --- /dev/null +++ b/casr/tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.cs @@ -0,0 +1,19 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +public class Program +{ + public static void Seg() + { + [DllImport("native.so", EntryPoint="seg")] + static extern void seg(int size); + + seg(100000000); + } + + public static void Main(string[] args) + { + Seg(); + } +} diff --git a/casr/tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.csproj b/casr/tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.csproj new file mode 100644 index 00000000..c1368a7f --- /dev/null +++ b/casr/tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + disable + + + diff --git a/casr/tests/tests.rs b/casr/tests/tests.rs index 2367305d..61b4f68d 100644 --- a/casr/tests/tests.rs +++ b/casr/tests/tests.rs @@ -5724,6 +5724,73 @@ fn test_casr_csharp() { } } +#[test] +#[cfg(target_arch = "x86_64")] +fn test_casr_csharp_native() { + let paths = [ + abs_path("tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.cs"), + abs_path("tests/casr_tests/csharp/test_casr_csharp_native/test_casr_csharp_native.csproj"), + abs_path("tests/casr_tests/csharp/test_casr_csharp_native/native.cpp"), + abs_path("tests/tmp_tests_casr/test_casr_csharp_native"), + abs_path("tests/tmp_tests_casr/test_casr_csharp_native/test_casr_csharp_native.cs"), + abs_path("tests/tmp_tests_casr/test_casr_csharp_native/test_casr_csharp_native.csproj"), + abs_path("tests/tmp_tests_casr/test_casr_csharp_native/native.so"), + ]; + let _ = std::fs::create_dir_all(&paths[3]); + let _ = fs::copy(&paths[0], &paths[4]); + let _ = fs::copy(&paths[1], &paths[5]); + let Ok(dotnet_path) = which::which("dotnet") else { + panic!("No dotnet is found."); + }; + + let _ = Command::new("clang++") + .args([&paths[2], "-g", "-fPIC", "-shared", "-o", &paths[6]]) + .output() + .expect("failed to compile .so library"); + + let _ = Command::new("dotnet") + .args(["build", &paths[5]]) + .output() + .expect("failed to build test"); + + let output = Command::new(*EXE_CASR_CSHARP.read().unwrap()) + .args([ + "--stdout", + "--", + (dotnet_path.to_str().unwrap()), + format!("{}/bin/Debug/net8.0/test_casr_csharp_native.dll", &paths[3]).as_str(), + ]) + .env("LD_LIBRARY_PATH", &paths[3]) + .output() + .expect("failed to start casr-csharp"); + + assert!( + output.status.success(), + "Stdout {}.\n Stderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + + let report: Result = 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(); + + assert_eq!(19, report["Stacktrace"].as_array().unwrap().iter().count()); + assert_eq!(severity_type, "NOT_EXPLOITABLE"); + assert_eq!(severity_desc, "AccessViolation"); + assert!(report["CrashLine"] + .as_str() + .unwrap() + .contains("native.cpp:6")); + } else { + panic!("Couldn't parse json report file."); + } +} + #[test] #[cfg(target_arch = "x86_64")] fn test_casr_afl_csharp() {