clang wrapper extend api
This commit is contained in:
commit
414a66382b
140
.github/workflows/build_and_test.yml
vendored
140
.github/workflows/build_and_test.yml
vendored
@ -1,67 +1,73 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, dev ]
|
||||
pull_request:
|
||||
branches: [ main, dev ]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: clippy-cargo-${{ hashFiles('**/Cargo.toml') }}
|
||||
- name: Add clippy
|
||||
run: rustup component add clippy
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --all
|
||||
ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Default Build
|
||||
run: cargo build --verbose
|
||||
- name: Default Test
|
||||
run: cargo test --verbose
|
||||
- name: Build all features
|
||||
run: cd libafl && cargo build --all-features --verbose
|
||||
- name: Test all features
|
||||
run: cd libafl && cargo test --all-features --verbose
|
||||
- name: Build no_std
|
||||
run: cd libafl && cargo build --no-default-features --verbose
|
||||
- name: Test no_std
|
||||
run: cd libafl && cargo test --no-default-features --verbose
|
||||
- name: Build examples
|
||||
run: cargo build --examples --verbose
|
||||
- uses: actions/checkout@v2
|
||||
- name: Format
|
||||
run: cargo fmt -- --check
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build Docs
|
||||
run: cargo doc
|
||||
- name: Test Docs
|
||||
run: cargo test --doc
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Windows Build
|
||||
run: cargo build --verbose
|
||||
- name: Windows Test
|
||||
run: cargo test --verbose
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, dev ]
|
||||
pull_request:
|
||||
branches: [ main, dev ]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache cargo registry
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
key: clippy-cargo-${{ hashFiles('**/Cargo.toml') }}
|
||||
- name: Add clippy
|
||||
run: rustup component add clippy
|
||||
- name: Run clippy
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: --all
|
||||
ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Default Build
|
||||
run: cargo build --verbose
|
||||
- name: Default Test
|
||||
run: cargo test --verbose
|
||||
- name: Build all features
|
||||
run: cd libafl && cargo build --all-features --verbose
|
||||
- name: Test all features
|
||||
run: cd libafl && cargo test --all-features --verbose
|
||||
- name: Build no_std
|
||||
run: cd libafl && cargo build --no-default-features --verbose
|
||||
- name: Test no_std
|
||||
run: cd libafl && cargo test --no-default-features --verbose
|
||||
- name: Build examples
|
||||
run: cargo build --examples --verbose
|
||||
- uses: actions/checkout@v2
|
||||
- name: Format
|
||||
run: cargo fmt -- --check
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build Docs
|
||||
run: cargo doc
|
||||
- name: Test Docs
|
||||
run: cargo test --doc
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Windows Build
|
||||
run: cargo build --verbose
|
||||
# TODO: Figure out how to properly build stuff with clang
|
||||
#- name: Add clang path to $PATH env
|
||||
# if: runner.os == 'Windows'
|
||||
# run: echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8
|
||||
#- name: Try if clang works
|
||||
# run: clang -v
|
||||
#- name: Windows Test
|
||||
# run: C:\Rust\.cargo\bin\cargo.exe test --verbose
|
||||
|
@ -15,4 +15,5 @@ members = [
|
||||
"fuzzers/frida_libpng",
|
||||
"fuzzers/libfuzzer_libmozjpeg",
|
||||
"fuzzers/libfuzzer_libpng_cmpalloc",
|
||||
"fuzzers/libfuzzer_windows",
|
||||
]
|
||||
|
@ -1,114 +1,114 @@
|
||||
// build.rs
|
||||
|
||||
use std::{
|
||||
env,
|
||||
path::Path,
|
||||
process::{exit, Command},
|
||||
};
|
||||
|
||||
const LIBPNG_URL: &str =
|
||||
"https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz";
|
||||
|
||||
fn main() {
|
||||
if cfg!(windows) {
|
||||
println!("cargo:warning=Skipping libpng frida example on Windows");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
||||
let out_dir = out_dir.to_string_lossy().to_string();
|
||||
let out_dir_path = Path::new(&out_dir);
|
||||
std::fs::create_dir_all(&out_dir).expect(&format!("Failed to create {}", &out_dir));
|
||||
|
||||
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||
println!("cargo:rerun-if-changed=harness.cc");
|
||||
|
||||
let libpng = format!("{}/libpng-1.6.37", &out_dir);
|
||||
let libpng_path = Path::new(&libpng);
|
||||
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
||||
|
||||
// Enforce clang for its -fsanitize-coverage support.
|
||||
std::env::set_var("CC", "clang");
|
||||
std::env::set_var("CXX", "clang++");
|
||||
let ldflags = match env::var("LDFLAGS") {
|
||||
Ok(val) => val,
|
||||
Err(_) => "".to_string(),
|
||||
};
|
||||
|
||||
// println!("cargo:warning=output path is {}", libpng);
|
||||
if !libpng_path.is_dir() {
|
||||
if !Path::new(&libpng_tar).is_file() {
|
||||
println!("cargo:warning=Libpng not found, downloading...");
|
||||
// Download libpng
|
||||
Command::new("wget")
|
||||
.arg("-c")
|
||||
.arg(LIBPNG_URL)
|
||||
.arg("-O")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
Command::new("tar")
|
||||
.current_dir(&out_dir_path)
|
||||
.arg("xvf")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new(format!("{}/configure", &libpng))
|
||||
.current_dir(&libpng_path)
|
||||
.args(&[
|
||||
"--disable-shared",
|
||||
&format!("--host={}", env::var("TARGET").unwrap())[..],
|
||||
])
|
||||
.env("CC", "clang")
|
||||
.env("CXX", "clang++")
|
||||
.env(
|
||||
"CFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
||||
)
|
||||
.env(
|
||||
"CXXFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
||||
)
|
||||
.env(
|
||||
"LDFLAGS",
|
||||
//format!("-g -fPIE -fsanitize=address {}", ldflags),
|
||||
format!("-g -fPIE {}", ldflags),
|
||||
)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new("make")
|
||||
.current_dir(&libpng_path)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let status = cc::Build::new()
|
||||
.cpp(true)
|
||||
.get_compiler()
|
||||
.to_command()
|
||||
.current_dir(&cwd)
|
||||
.arg("-I")
|
||||
.arg(format!("{}", &libpng))
|
||||
//.arg("-D")
|
||||
//.arg("HAS_DUMMY_CRASH=1")
|
||||
.arg("-fPIC")
|
||||
.arg("-shared")
|
||||
.arg(if env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" {
|
||||
"-static-libstdc++"
|
||||
} else {
|
||||
""
|
||||
})
|
||||
.arg("-o")
|
||||
.arg(format!("{}/libpng-harness.so", &out_dir))
|
||||
.arg("./harness.cc")
|
||||
.arg(format!("{}/.libs/libpng16.a", &libpng))
|
||||
.arg("-l")
|
||||
.arg("z")
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(status.success());
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
// build.rs
|
||||
|
||||
use std::{
|
||||
env,
|
||||
path::Path,
|
||||
process::{exit, Command},
|
||||
};
|
||||
|
||||
const LIBPNG_URL: &str =
|
||||
"https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz";
|
||||
|
||||
fn main() {
|
||||
if cfg!(windows) {
|
||||
println!("cargo:warning=Skipping libpng frida example on Windows");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
||||
let out_dir = out_dir.to_string_lossy().to_string();
|
||||
let out_dir_path = Path::new(&out_dir);
|
||||
std::fs::create_dir_all(&out_dir).expect(&format!("Failed to create {}", &out_dir));
|
||||
|
||||
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||
println!("cargo:rerun-if-changed=harness.cc");
|
||||
|
||||
let libpng = format!("{}/libpng-1.6.37", &out_dir);
|
||||
let libpng_path = Path::new(&libpng);
|
||||
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
||||
|
||||
// Enforce clang for its -fsanitize-coverage support.
|
||||
std::env::set_var("CC", "clang");
|
||||
std::env::set_var("CXX", "clang++");
|
||||
let ldflags = match env::var("LDFLAGS") {
|
||||
Ok(val) => val,
|
||||
Err(_) => "".to_string(),
|
||||
};
|
||||
|
||||
// println!("cargo:warning=output path is {}", libpng);
|
||||
if !libpng_path.is_dir() {
|
||||
if !Path::new(&libpng_tar).is_file() {
|
||||
println!("cargo:warning=Libpng not found, downloading...");
|
||||
// Download libpng
|
||||
Command::new("wget")
|
||||
.arg("-c")
|
||||
.arg(LIBPNG_URL)
|
||||
.arg("-O")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
Command::new("tar")
|
||||
.current_dir(&out_dir_path)
|
||||
.arg("xvf")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new(format!("{}/configure", &libpng))
|
||||
.current_dir(&libpng_path)
|
||||
.args(&[
|
||||
"--disable-shared",
|
||||
&format!("--host={}", env::var("TARGET").unwrap())[..],
|
||||
])
|
||||
.env("CC", "clang")
|
||||
.env("CXX", "clang++")
|
||||
.env(
|
||||
"CFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
||||
)
|
||||
.env(
|
||||
"CXXFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIC -fno-omit-frame-pointer",
|
||||
)
|
||||
.env(
|
||||
"LDFLAGS",
|
||||
//format!("-g -fPIE -fsanitize=address {}", ldflags),
|
||||
format!("-g -fPIE {}", ldflags),
|
||||
)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new("make")
|
||||
.current_dir(&libpng_path)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let status = cc::Build::new()
|
||||
.cpp(true)
|
||||
.get_compiler()
|
||||
.to_command()
|
||||
.current_dir(&cwd)
|
||||
.arg("-I")
|
||||
.arg(&libpng)
|
||||
//.arg("-D")
|
||||
//.arg("HAS_DUMMY_CRASH=1")
|
||||
.arg("-fPIC")
|
||||
.arg("-shared")
|
||||
.arg(if env::var("CARGO_CFG_TARGET_OS").unwrap() == "android" {
|
||||
"-static-libstdc++"
|
||||
} else {
|
||||
""
|
||||
})
|
||||
.arg("-o")
|
||||
.arg(format!("{}/libpng-harness.so", &out_dir))
|
||||
.arg("./harness.cc")
|
||||
.arg(format!("{}/.libs/libpng16.a", &libpng))
|
||||
.arg("-l")
|
||||
.arg("z")
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(status.success());
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
|
@ -34,8 +34,6 @@ use frida_gum::{
|
||||
};
|
||||
use frida_gum::{Gum, MemoryRange, Module, NativePointer, PageProtection};
|
||||
|
||||
use libloading;
|
||||
|
||||
use std::{cell::RefCell, env, ffi::c_void, path::PathBuf};
|
||||
|
||||
/// An helper that feeds FridaInProcessExecutor with user-supplied instrumentation
|
||||
@ -351,9 +349,9 @@ where
|
||||
));
|
||||
|
||||
Self {
|
||||
base: base,
|
||||
stalker: stalker,
|
||||
helper: helper,
|
||||
base,
|
||||
stalker,
|
||||
helper,
|
||||
followed: false,
|
||||
}
|
||||
}
|
||||
@ -464,10 +462,10 @@ unsafe fn fuzz(
|
||||
if state.metadata().get::<Tokens>().is_none() {
|
||||
state.add_metadata(Tokens::new(vec![
|
||||
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
|
||||
"IHDR".as_bytes().to_vec(),
|
||||
"IDAT".as_bytes().to_vec(),
|
||||
"PLTE".as_bytes().to_vec(),
|
||||
"IEND".as_bytes().to_vec(),
|
||||
b"IHDR".to_vec(),
|
||||
b"IDAT".to_vec(),
|
||||
b"PLTE".to_vec(),
|
||||
b"IEND".to_vec(),
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -1,109 +1,113 @@
|
||||
// build.rs
|
||||
|
||||
use std::{
|
||||
env,
|
||||
path::Path,
|
||||
process::{exit, Command},
|
||||
};
|
||||
|
||||
const LIBPNG_URL: &str =
|
||||
"https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz";
|
||||
|
||||
fn main() {
|
||||
if cfg!(windows) {
|
||||
println!("cargo:warning=Skipping libpng example on Windows");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
||||
let out_dir = out_dir.to_string_lossy().to_string();
|
||||
let out_dir_path = Path::new(&out_dir);
|
||||
|
||||
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||
println!("cargo:rerun-if-changed=harness.cc");
|
||||
|
||||
let libpng = format!("{}/libpng-1.6.37", &out_dir);
|
||||
let libpng_path = Path::new(&libpng);
|
||||
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
||||
|
||||
// Enforce clang for its -fsanitize-coverage support.
|
||||
std::env::set_var("CC", "clang");
|
||||
std::env::set_var("CXX", "clang++");
|
||||
let ldflags = match env::var("LDFLAGS") {
|
||||
Ok(val) => val,
|
||||
Err(_) => "".to_string(),
|
||||
};
|
||||
|
||||
if !libpng_path.is_dir() {
|
||||
if !Path::new(&libpng_tar).is_file() {
|
||||
println!("cargo:warning=Libpng not found, downloading...");
|
||||
// Download libpng
|
||||
Command::new("wget")
|
||||
.arg("-c")
|
||||
.arg(LIBPNG_URL)
|
||||
.arg("-O")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
Command::new("tar")
|
||||
.current_dir(&out_dir_path)
|
||||
.arg("-xvf")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new(format!("{}/configure", &libpng))
|
||||
.current_dir(&libpng_path)
|
||||
.args(&[
|
||||
"--disable-shared",
|
||||
&format!("--host={}", env::var("TARGET").unwrap())[..],
|
||||
])
|
||||
.env("CC", "clang")
|
||||
.env("CXX", "clang++")
|
||||
.env(
|
||||
"CFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard",
|
||||
)
|
||||
.env(
|
||||
"CXXFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard",
|
||||
)
|
||||
.env(
|
||||
"LDFLAGS",
|
||||
format!("-g -fPIE -fsanitize-coverage=trace-pc-guard {}", ldflags),
|
||||
)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new("make")
|
||||
.current_dir(&libpng_path)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
cc::Build::new()
|
||||
.file("../libfuzzer_runtime/rt.c")
|
||||
.compile("libfuzzer-sys");
|
||||
|
||||
cc::Build::new()
|
||||
.include(&libpng_path)
|
||||
.cpp(true)
|
||||
.flag("-fsanitize-coverage=trace-pc-guard")
|
||||
// .define("HAS_DUMMY_CRASH", "1")
|
||||
.file("./harness.cc")
|
||||
.compile("libfuzzer-harness");
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||
println!("cargo:rustc-link-search=native={}/.libs", &libpng);
|
||||
println!("cargo:rustc-link-lib=static=png16");
|
||||
|
||||
//Deps for libpng: -pthread -lz -lm
|
||||
println!("cargo:rustc-link-lib=dylib=m");
|
||||
println!("cargo:rustc-link-lib=dylib=z");
|
||||
|
||||
//For the C++ harness
|
||||
//must by dylib for android
|
||||
println!("cargo:rustc-link-lib=dylib=stdc++");
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
// build.rs
|
||||
|
||||
use std::{
|
||||
env,
|
||||
path::Path,
|
||||
process::{exit, Command},
|
||||
};
|
||||
|
||||
const LIBPNG_URL: &str =
|
||||
"https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz";
|
||||
|
||||
fn main() {
|
||||
if cfg!(windows) {
|
||||
println!("cargo:warning=Skipping libpng example on Windows");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
||||
let out_dir = out_dir.to_string_lossy().to_string();
|
||||
let out_dir_path = Path::new(&out_dir);
|
||||
|
||||
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||
println!("cargo:rerun-if-changed=harness.cc");
|
||||
|
||||
let libpng = format!("{}/libpng-1.6.37", &out_dir);
|
||||
let libpng_path = Path::new(&libpng);
|
||||
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
||||
|
||||
// Enforce clang for its -fsanitize-coverage support.
|
||||
std::env::set_var("CC", "clang");
|
||||
std::env::set_var("CXX", "clang++");
|
||||
let ldflags = match env::var("LDFLAGS") {
|
||||
Ok(val) => val,
|
||||
Err(_) => "".to_string(),
|
||||
};
|
||||
|
||||
if !libpng_path.is_dir() {
|
||||
if !Path::new(&libpng_tar).is_file() {
|
||||
println!("cargo:warning=Libpng not found, downloading...");
|
||||
// Download libpng
|
||||
Command::new("wget")
|
||||
.arg("-c")
|
||||
.arg(LIBPNG_URL)
|
||||
.arg("-O")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
Command::new("tar")
|
||||
.current_dir(&out_dir_path)
|
||||
.arg("-xvf")
|
||||
.arg(&libpng_tar)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new(format!("{}/configure", &libpng))
|
||||
.current_dir(&libpng_path)
|
||||
.args(&[
|
||||
"--disable-shared",
|
||||
&format!("--host={}", env::var("TARGET").unwrap())[..],
|
||||
])
|
||||
.env("CC", "clang")
|
||||
.env("CXX", "clang++")
|
||||
.env(
|
||||
"CFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard",
|
||||
)
|
||||
.env(
|
||||
"CXXFLAGS",
|
||||
"-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard",
|
||||
)
|
||||
.env(
|
||||
"LDFLAGS",
|
||||
format!("-g -fPIE -fsanitize-coverage=trace-pc-guard {}", ldflags),
|
||||
)
|
||||
.status()
|
||||
.unwrap();
|
||||
Command::new("make")
|
||||
.current_dir(&libpng_path)
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
cc::Build::new()
|
||||
.file("../libfuzzer_runtime/rt.c")
|
||||
.compile("libfuzzer-sys");
|
||||
|
||||
cc::Build::new()
|
||||
.include(&libpng_path)
|
||||
.cpp(true)
|
||||
.flag("-fsanitize-coverage=trace-pc-guard")
|
||||
.flag("-Wno-void-pointer-to-int-cast")
|
||||
.flag("-Wno-int-to-pointer-cast")
|
||||
.flag("-Wno-sign-compare")
|
||||
.flag("-Wno-format")
|
||||
// .define("HAS_DUMMY_CRASH", "1")
|
||||
.file("./harness.cc")
|
||||
.compile("libfuzzer-harness");
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||
println!("cargo:rustc-link-search=native={}/.libs", &libpng);
|
||||
println!("cargo:rustc-link-lib=static=png16");
|
||||
|
||||
//Deps for libpng: -pthread -lz -lm
|
||||
println!("cargo:rustc-link-lib=dylib=m");
|
||||
println!("cargo:rustc-link-lib=dylib=z");
|
||||
|
||||
//For the C++ harness
|
||||
//must by dylib for android
|
||||
println!("cargo:rustc-link-lib=dylib=stdc++");
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
|
@ -131,6 +131,10 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno)
|
||||
#endif
|
||||
|
||||
void *malloc(size_t size) {
|
||||
|
||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
||||
|
1
fuzzers/libfuzzer_windows/.gitignore
vendored
Normal file
1
fuzzers/libfuzzer_windows/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
libpng-*
|
31
fuzzers/libfuzzer_windows/Cargo.toml
Normal file
31
fuzzers/libfuzzer_windows/Cargo.toml
Normal file
@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "libfuzzer_windows"
|
||||
version = "0.1.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
#[profile.release]
|
||||
#lto = true
|
||||
#codegen-units = 1
|
||||
#opt-level = 3
|
||||
#debug = true
|
||||
|
||||
[build-dependencies]
|
||||
cc = { version = "1.0", features = ["parallel"] }
|
||||
num_cpus = "1.0"
|
||||
|
||||
[dependencies]
|
||||
libafl = { path = "../../libafl/" }
|
||||
|
||||
[[example]]
|
||||
name = "libfuzzer_windows"
|
||||
path = "./src/fuzzer.rs"
|
||||
test = false
|
||||
bench = false
|
25
fuzzers/libfuzzer_windows/README.md
Normal file
25
fuzzers/libfuzzer_windows/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Libfuzzer for libpng
|
||||
|
||||
This folder contains an example fuzzer for libpng, using LLMP for fast multi-process fuzzing and crash detection.
|
||||
To show off crash detection, we added a ud2 instruction to the harness, edit harness.cc if you want a non-crashing example.
|
||||
It has been tested on Linux.
|
||||
|
||||
## Build
|
||||
|
||||
To build this example, run `cargo build --example libfuzzer_libpng --release`.
|
||||
This will call (the build.rs)[./builld.rs], which in turn downloads a libpng archive from the web.
|
||||
Then, it will link (the fuzzer)[./src/fuzzer.rs] against (the C++ harness)[./harness.cc] and the instrumented `libpng`.
|
||||
Afterwards, the fuzzer will be ready to run, from `../../target/examples/libfuzzer_libpng`.
|
||||
|
||||
## Run
|
||||
|
||||
The first time you run the binary, the broker will open a tcp port (currently on port `1337`), waiting for fuzzer clients to connect. This port is local and only used for the initial handshake. All further communication happens via shared map, to be independent of the kernel.
|
||||
|
||||
Each following execution will run a fuzzer client.
|
||||
As this example uses in-process fuzzing, we added a Restarting Event Manager (`setup_restarting_mgr`).
|
||||
This means each client will start itself again to listen for crashes and timeouts.
|
||||
By restarting the actual fuzzer, it can recover from these exit conditions.
|
||||
|
||||
In any real-world scenario, you should use `taskset` to pin each client to an empty CPU core, the lib does not pick an empty core automatically (yet).
|
||||
|
||||
For convenience, you may just run `./test.sh` in this folder to test it.
|
58
fuzzers/libfuzzer_windows/build.rs
Normal file
58
fuzzers/libfuzzer_windows/build.rs
Normal file
@ -0,0 +1,58 @@
|
||||
// build.rs
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::env;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn main() {
|
||||
println!("cargo:warning=Skipping libpng windows example on non-Windows");
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn main() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let out_dir = out_dir.to_string_lossy().to_string();
|
||||
|
||||
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||
println!("cargo:rerun-if-changed=harness.cc");
|
||||
|
||||
// Enforce clang for its -fsanitize-coverage support.
|
||||
std::env::set_var("CC", "clang");
|
||||
std::env::set_var("CXX", "clang++");
|
||||
/*let ldflags = match env::var("LDFLAGS") {
|
||||
Ok(val) => val,
|
||||
Err(_) => "".to_string(),
|
||||
};*/
|
||||
|
||||
cc::Build::new()
|
||||
.file("../libfuzzer_runtime/rt.c")
|
||||
.compile("libfuzzer-sys");
|
||||
|
||||
cc::Build::new()
|
||||
.cpp(true)
|
||||
.flag("-fsanitize-coverage=trace-pc-guard")
|
||||
// .define("HAS_DUMMY_CRASH", "1")
|
||||
.flag("-Wno-void-pointer-to-int-cast")
|
||||
.flag("-Wno-pointer-to-int-cast")
|
||||
.flag("-Wno-int-to-pointer-cast")
|
||||
.flag("-Wno-sign-compare")
|
||||
.flag("-Wno-format")
|
||||
.flag("-Wno-unused-variable")
|
||||
.file("./harness.cc")
|
||||
.compile("windows-harness");
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||
//println!("cargo:rustc-link-search=native={}/.libs", &libpng);
|
||||
//println!("cargo:rustc-link-lib=static=png16");
|
||||
|
||||
//Deps for libpng: -pthread -lz -lm
|
||||
//println!("cargo:rustc-link-lib=dylib=m");
|
||||
//println!("cargo:rustc-link-lib=dylib=z");
|
||||
|
||||
//For the C++ harness
|
||||
//must by dylib for android
|
||||
//println!("cargo:rustc-link-lib=dylib=stdc++");
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty.png
Normal file
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 B |
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty_alpha.png
Normal file
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty_alpha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 376 B |
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty_gamma.png
Normal file
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty_gamma.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 228 B |
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty_icc.png
Normal file
BIN
fuzzers/libfuzzer_windows/corpus/not_kitty_icc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 427 B |
231
fuzzers/libfuzzer_windows/harness.cc
Normal file
231
fuzzers/libfuzzer_windows/harness.cc
Normal file
@ -0,0 +1,231 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define STBI_ASSERT(x)
|
||||
#define STBI_NO_SIMD
|
||||
#define STBI_NO_LINEAR
|
||||
#define STBI_NO_STDIO
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
int target_func(const uint8_t *buf, size_t size) {
|
||||
|
||||
/*printf("BUF (%ld): ", size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
printf("%02X", buf[i]);
|
||||
}
|
||||
printf("\n");*/
|
||||
|
||||
if (size == 0) return 0;
|
||||
|
||||
switch (buf[0]) {
|
||||
|
||||
case 1:
|
||||
if (buf[1] == 0x44) {
|
||||
//__builtin_trap();
|
||||
return 8;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0xff:
|
||||
if (buf[2] == 0xff) {
|
||||
if (buf[1] == 0x44) {
|
||||
//*(char *)(0xdeadbeef) = 1;
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int parse_pe(const uint8_t *data, int size)
|
||||
{
|
||||
HANDLE file = NULL;
|
||||
DWORD fileSize = NULL;
|
||||
DWORD bytesRead = NULL;
|
||||
LPVOID fileData = NULL;
|
||||
PIMAGE_DOS_HEADER dosHeader = {};
|
||||
PIMAGE_NT_HEADERS imageNTHeaders = {};
|
||||
PIMAGE_SECTION_HEADER sectionHeader = {};
|
||||
PIMAGE_SECTION_HEADER importSection = {};
|
||||
IMAGE_IMPORT_DESCRIPTOR* importDescriptor = {};
|
||||
PIMAGE_THUNK_DATA thunkData = {};
|
||||
DWORD thunk = NULL;
|
||||
DWORD rawOffset = NULL;
|
||||
|
||||
// allocate heap
|
||||
fileSize = size;
|
||||
fileData = (void *)data;
|
||||
|
||||
// IMAGE_DOS_HEADER
|
||||
dosHeader = (PIMAGE_DOS_HEADER)fileData;
|
||||
|
||||
printf("******* DOS HEADER *******\n");
|
||||
printf("\t0x%x\t\tMagic number\n", dosHeader->e_magic);
|
||||
/*
|
||||
printf("\t0x%x\t\tBytes on last page of file\n", dosHeader->e_cblp);
|
||||
printf("\t0x%x\t\tPages in file\n", dosHeader->e_cp);
|
||||
printf("\t0x%x\t\tRelocations\n", dosHeader->e_crlc);
|
||||
printf("\t0x%x\t\tSize of header in paragraphs\n", dosHeader->e_cparhdr);
|
||||
printf("\t0x%x\t\tMinimum extra paragraphs needed\n", dosHeader->e_minalloc);
|
||||
printf("\t0x%x\t\tMaximum extra paragraphs needed\n", dosHeader->e_maxalloc);
|
||||
printf("\t0x%x\t\tInitial (relative) SS value\n", dosHeader->e_ss);
|
||||
printf("\t0x%x\t\tInitial SP value\n", dosHeader->e_sp);
|
||||
printf("\t0x%x\t\tInitial SP value\n", dosHeader->e_sp);
|
||||
printf("\t0x%x\t\tChecksum\n", dosHeader->e_csum);
|
||||
printf("\t0x%x\t\tInitial IP value\n", dosHeader->e_ip);
|
||||
printf("\t0x%x\t\tInitial (relative) CS value\n", dosHeader->e_cs);
|
||||
printf("\t0x%x\t\tFile address of relocation table\n", dosHeader->e_lfarlc);
|
||||
printf("\t0x%x\t\tOverlay number\n", dosHeader->e_ovno);
|
||||
printf("\t0x%x\t\tOEM identifier (for e_oeminfo)\n", dosHeader->e_oemid);
|
||||
printf("\t0x%x\t\tOEM information; e_oemid specific\n", dosHeader->e_oeminfo);
|
||||
printf("\t0x%x\t\tFile address of new exe header\n", dosHeader->e_lfanew);
|
||||
*/
|
||||
// IMAGE_NT_HEADERS
|
||||
imageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)fileData + dosHeader->e_lfanew);
|
||||
/*
|
||||
printf("\n******* NT HEADERS *******\n");
|
||||
printf("\t%x\t\tSignature\n", imageNTHeaders->Signature);
|
||||
|
||||
// FILE_HEADER
|
||||
printf("\n******* FILE HEADER *******\n");
|
||||
printf("\t0x%x\t\tMachine\n", imageNTHeaders->FileHeader.Machine);
|
||||
printf("\t0x%x\t\tNumber of Sections\n", imageNTHeaders->FileHeader.NumberOfSections);
|
||||
printf("\t0x%x\tTime Stamp\n", imageNTHeaders->FileHeader.TimeDateStamp);
|
||||
printf("\t0x%x\t\tPointer to Symbol Table\n", imageNTHeaders->FileHeader.PointerToSymbolTable);
|
||||
printf("\t0x%x\t\tNumber of Symbols\n", imageNTHeaders->FileHeader.NumberOfSymbols);
|
||||
printf("\t0x%x\t\tSize of Optional Header\n", imageNTHeaders->FileHeader.SizeOfOptionalHeader);
|
||||
printf("\t0x%x\t\tCharacteristics\n", imageNTHeaders->FileHeader.Characteristics);
|
||||
|
||||
// OPTIONAL_HEADER
|
||||
printf("\n******* OPTIONAL HEADER *******\n");
|
||||
printf("\t0x%x\t\tMagic\n", imageNTHeaders->OptionalHeader.Magic);
|
||||
printf("\t0x%x\t\tMajor Linker Version\n", imageNTHeaders->OptionalHeader.MajorLinkerVersion);
|
||||
printf("\t0x%x\t\tMinor Linker Version\n", imageNTHeaders->OptionalHeader.MinorLinkerVersion);
|
||||
printf("\t0x%x\t\tSize Of Code\n", imageNTHeaders->OptionalHeader.SizeOfCode);
|
||||
printf("\t0x%x\t\tSize Of Initialized Data\n", imageNTHeaders->OptionalHeader.SizeOfInitializedData);
|
||||
printf("\t0x%x\t\tSize Of UnInitialized Data\n", imageNTHeaders->OptionalHeader.SizeOfUninitializedData);
|
||||
printf("\t0x%x\t\tAddress Of Entry Point (.text)\n", imageNTHeaders->OptionalHeader.AddressOfEntryPoint);
|
||||
printf("\t0x%x\t\tBase Of Code\n", imageNTHeaders->OptionalHeader.BaseOfCode);
|
||||
//printf("\t0x%x\t\tBase Of Data\n", imageNTHeaders->OptionalHeader.BaseOfData);
|
||||
printf("\t0x%x\t\tImage Base\n", imageNTHeaders->OptionalHeader.ImageBase);
|
||||
printf("\t0x%x\t\tSection Alignment\n", imageNTHeaders->OptionalHeader.SectionAlignment);
|
||||
printf("\t0x%x\t\tFile Alignment\n", imageNTHeaders->OptionalHeader.FileAlignment);
|
||||
printf("\t0x%x\t\tMajor Operating System Version\n", imageNTHeaders->OptionalHeader.MajorOperatingSystemVersion);
|
||||
printf("\t0x%x\t\tMinor Operating System Version\n", imageNTHeaders->OptionalHeader.MinorOperatingSystemVersion);
|
||||
printf("\t0x%x\t\tMajor Image Version\n", imageNTHeaders->OptionalHeader.MajorImageVersion);
|
||||
printf("\t0x%x\t\tMinor Image Version\n", imageNTHeaders->OptionalHeader.MinorImageVersion);
|
||||
printf("\t0x%x\t\tMajor Subsystem Version\n", imageNTHeaders->OptionalHeader.MajorSubsystemVersion);
|
||||
printf("\t0x%x\t\tMinor Subsystem Version\n", imageNTHeaders->OptionalHeader.MinorSubsystemVersion);
|
||||
printf("\t0x%x\t\tWin32 Version Value\n", imageNTHeaders->OptionalHeader.Win32VersionValue);
|
||||
printf("\t0x%x\t\tSize Of Image\n", imageNTHeaders->OptionalHeader.SizeOfImage);
|
||||
printf("\t0x%x\t\tSize Of Headers\n", imageNTHeaders->OptionalHeader.SizeOfHeaders);
|
||||
printf("\t0x%x\t\tCheckSum\n", imageNTHeaders->OptionalHeader.CheckSum);
|
||||
printf("\t0x%x\t\tSubsystem\n", imageNTHeaders->OptionalHeader.Subsystem);
|
||||
printf("\t0x%x\t\tDllCharacteristics\n", imageNTHeaders->OptionalHeader.DllCharacteristics);
|
||||
printf("\t0x%x\t\tSize Of Stack Reserve\n", imageNTHeaders->OptionalHeader.SizeOfStackReserve);
|
||||
printf("\t0x%x\t\tSize Of Stack Commit\n", imageNTHeaders->OptionalHeader.SizeOfStackCommit);
|
||||
printf("\t0x%x\t\tSize Of Heap Reserve\n", imageNTHeaders->OptionalHeader.SizeOfHeapReserve);
|
||||
printf("\t0x%x\t\tSize Of Heap Commit\n", imageNTHeaders->OptionalHeader.SizeOfHeapCommit);
|
||||
printf("\t0x%x\t\tLoader Flags\n", imageNTHeaders->OptionalHeader.LoaderFlags);
|
||||
printf("\t0x%x\t\tNumber Of Rva And Sizes\n", imageNTHeaders->OptionalHeader.NumberOfRvaAndSizes);
|
||||
|
||||
// DATA_DIRECTORIES
|
||||
printf("\n******* DATA DIRECTORIES *******\n");
|
||||
printf("\tExport Directory Address: 0x%x; Size: 0x%x\n", imageNTHeaders->OptionalHeader.DataDirectory[0].VirtualAddress, imageNTHeaders->OptionalHeader.DataDirectory[0].Size);
|
||||
printf("\tImport Directory Address: 0x%x; Size: 0x%x\n", imageNTHeaders->OptionalHeader.DataDirectory[1].VirtualAddress, imageNTHeaders->OptionalHeader.DataDirectory[1].Size);
|
||||
*/
|
||||
return 0;
|
||||
// SECTION_HEADERS
|
||||
printf("\n******* SECTION HEADERS *******\n");
|
||||
// get offset to first section headeer
|
||||
DWORD sectionLocation = (DWORD)imageNTHeaders + sizeof(DWORD) + (DWORD)(sizeof(IMAGE_FILE_HEADER)) + (DWORD)imageNTHeaders->FileHeader.SizeOfOptionalHeader;
|
||||
DWORD sectionSize = (DWORD)sizeof(IMAGE_SECTION_HEADER);
|
||||
|
||||
// get offset to the import directory RVA
|
||||
DWORD importDirectoryRVA = imageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
||||
// print section data
|
||||
for (int i = 0; i < imageNTHeaders->FileHeader.NumberOfSections; i++) {
|
||||
sectionHeader = (PIMAGE_SECTION_HEADER)sectionLocation;
|
||||
printf("\t%s\n", sectionHeader->Name);
|
||||
printf("\t\t0x%x\t\tVirtual Size\n", sectionHeader->Misc.VirtualSize);
|
||||
printf("\t\t0x%x\t\tVirtual Address\n", sectionHeader->VirtualAddress);
|
||||
/*
|
||||
printf("\t\t0x%x\t\tSize Of Raw Data\n", sectionHeader->SizeOfRawData);
|
||||
printf("\t\t0x%x\t\tPointer To Raw Data\n", sectionHeader->PointerToRawData);
|
||||
printf("\t\t0x%x\t\tPointer To Relocations\n", sectionHeader->PointerToRelocations);
|
||||
printf("\t\t0x%x\t\tPointer To Line Numbers\n", sectionHeader->PointerToLinenumbers);
|
||||
printf("\t\t0x%x\t\tNumber Of Relocations\n", sectionHeader->NumberOfRelocations);
|
||||
printf("\t\t0x%x\t\tNumber Of Line Numbers\n", sectionHeader->NumberOfLinenumbers);
|
||||
printf("\t\t0x%x\tCharacteristics\n", sectionHeader->Characteristics);
|
||||
*/
|
||||
// save section that contains import directory table
|
||||
if (importDirectoryRVA >= sectionHeader->VirtualAddress && importDirectoryRVA < sectionHeader->VirtualAddress + sectionHeader->Misc.VirtualSize) {
|
||||
importSection = sectionHeader;
|
||||
}
|
||||
sectionLocation += sectionSize;
|
||||
}
|
||||
|
||||
// get file offset to import table
|
||||
rawOffset = (DWORD)fileData + importSection->PointerToRawData;
|
||||
|
||||
// get pointer to import descriptor's file offset. Note that the formula for calculating file offset is: imageBaseAddress + pointerToRawDataOfTheSectionContainingRVAofInterest + (RVAofInterest - SectionContainingRVAofInterest.VirtualAddress)
|
||||
importDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)(rawOffset + (imageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - importSection->VirtualAddress));
|
||||
|
||||
printf("\n******* DLL IMPORTS *******\n");
|
||||
for (; importDescriptor->Name != 0; importDescriptor++) {
|
||||
// imported dll modules
|
||||
printf("\t%s\n", rawOffset + (importDescriptor->Name - importSection->VirtualAddress));
|
||||
thunk = importDescriptor->OriginalFirstThunk == 0 ? importDescriptor->FirstThunk : importDescriptor->OriginalFirstThunk;
|
||||
thunkData = (PIMAGE_THUNK_DATA)(rawOffset + (thunk - importSection->VirtualAddress));
|
||||
|
||||
// dll exported functions
|
||||
for (; thunkData->u1.AddressOfData != 0; thunkData++) {
|
||||
//a cheap and probably non-reliable way of checking if the function is imported via its ordinal number ¯\_(ツ)_/¯
|
||||
if (thunkData->u1.AddressOfData > 0x80000000) {
|
||||
//show lower bits of the value to get the ordinal ¯\_(ツ)_/¯
|
||||
printf("\t\tOrdinal: %x\n", (WORD)thunkData->u1.AddressOfData);
|
||||
} else {
|
||||
printf("\t\t%s\n", (rawOffset + (thunkData->u1.AddressOfData - importSection->VirtualAddress + 2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int load_stbi(const uint8_t *data, int size)
|
||||
{
|
||||
int w;
|
||||
int h;
|
||||
int channels;
|
||||
|
||||
const unsigned char * img = stbi_load_from_memory(data, size, &w, &h, &channels, 0);
|
||||
if (img) { stbi_image_free((void *)img); }
|
||||
// STBI_FREE((void *)img); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
//return target_func(Data, Size);
|
||||
|
||||
if(Size > 0x4000) return 0;
|
||||
|
||||
int size = Size;
|
||||
const unsigned char * data = Data;
|
||||
//return load_stbi(data, size);
|
||||
return parse_pe(data, size);
|
||||
}
|
||||
|
180
fuzzers/libfuzzer_windows/src/fuzzer.rs
Normal file
180
fuzzers/libfuzzer_windows/src/fuzzer.rs
Normal file
@ -0,0 +1,180 @@
|
||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||
//! The example harness is built for libpng.
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
#[cfg(windows)]
|
||||
use libafl::{
|
||||
bolts::{shmem::Win32ShMem, tuples::tuple_list},
|
||||
corpus::{
|
||||
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
||||
QueueCorpusScheduler,
|
||||
},
|
||||
events::setup_restarting_mgr,
|
||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||
fuzzer::{Fuzzer, HasCorpusScheduler, StdFuzzer},
|
||||
mutators::{scheduled::HavocBytesMutator, token_mutations::Tokens},
|
||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||
stages::mutational::StdMutationalStage,
|
||||
state::{HasCorpus, HasMetadata, State},
|
||||
stats::SimpleStats,
|
||||
utils::{current_nanos, StdRand},
|
||||
Error,
|
||||
};
|
||||
|
||||
/// We will interact with a C++ target, so use external c functionality
|
||||
#[cfg(windows)]
|
||||
extern "C" {
|
||||
/// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
|
||||
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32;
|
||||
|
||||
// afl_libfuzzer_init calls LLVMFUzzerInitialize()
|
||||
fn afl_libfuzzer_init() -> i32;
|
||||
|
||||
static __lafl_edges_map: *mut u8;
|
||||
static __lafl_cmp_map: *mut u8;
|
||||
static __lafl_max_edges_size: u32;
|
||||
}
|
||||
|
||||
/// The main fn, usually parsing parameters, and starting the fuzzer
|
||||
pub fn main() {
|
||||
// Registry the metadata types used in this fuzzer
|
||||
// Needed only on no_std
|
||||
//RegistryBuilder::register::<Tokens>();
|
||||
|
||||
#[cfg(windows)]
|
||||
println!(
|
||||
"Workdir: {:?}",
|
||||
env::current_dir().unwrap().to_string_lossy().to_string()
|
||||
);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
todo!("Example currently only supports Windows.");
|
||||
|
||||
#[cfg(windows)]
|
||||
fuzz(
|
||||
vec![PathBuf::from("./corpus")],
|
||||
PathBuf::from("./crashes"),
|
||||
1337,
|
||||
)
|
||||
.expect("An error occurred while fuzzing");
|
||||
}
|
||||
|
||||
/// Not supported on unix right now
|
||||
//#[cfg(cfg)]
|
||||
//fn fuzz(_corpus_dirs: Vec<PathBuf>, _objective_dir: PathBuf, _broker_port: u16) -> Result<(), ()> {
|
||||
// todo!("Example not supported on Unix");
|
||||
//}
|
||||
|
||||
/// The actual fuzzer
|
||||
#[cfg(windows)]
|
||||
fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> {
|
||||
// The wrapped harness function, calling out to the LLVM-style harness
|
||||
let mut harness = |buf: &[u8]| {
|
||||
unsafe { LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()) };
|
||||
ExitKind::Ok
|
||||
};
|
||||
|
||||
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
|
||||
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||
|
||||
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
||||
let (state, mut restarting_mgr) =
|
||||
match setup_restarting_mgr::<_, _, Win32ShMem, _>(stats, broker_port) {
|
||||
Ok(res) => res,
|
||||
Err(err) => match err {
|
||||
Error::ShuttingDown => {
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
panic!("Failed to setup the restarter: {}", err);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
let edges_observer = HitcountsMapObserver::new(unsafe {
|
||||
StdMapObserver::new_from_ptr("edges", __lafl_edges_map, __lafl_max_edges_size as usize)
|
||||
});
|
||||
|
||||
// If not restarting, create a State from scratch
|
||||
let mut state = state.unwrap_or_else(|| {
|
||||
State::new(
|
||||
// RNG
|
||||
StdRand::with_seed(current_nanos()),
|
||||
// Corpus that will be evolved, we keep it in memory for performance
|
||||
InMemoryCorpus::new(),
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
tuple_list!(
|
||||
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||
TimeFeedback::new()
|
||||
),
|
||||
// Corpus in which we store solutions (crashes in this example),
|
||||
// on disk so the user can get them after stopping the fuzzer
|
||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
||||
// Feedbacks to recognize an input as solution
|
||||
tuple_list!(CrashFeedback::new(), TimeoutFeedback::new()),
|
||||
)
|
||||
});
|
||||
|
||||
println!("We're a client, let's fuzz :)");
|
||||
|
||||
// Create a PNG dictionary if not existing
|
||||
if state.metadata().get::<Tokens>().is_none() {
|
||||
state.add_metadata(Tokens::new(vec![
|
||||
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
|
||||
"IHDR".as_bytes().to_vec(),
|
||||
"IDAT".as_bytes().to_vec(),
|
||||
"PLTE".as_bytes().to_vec(),
|
||||
"IEND".as_bytes().to_vec(),
|
||||
]));
|
||||
}
|
||||
|
||||
// Setup a basic mutator with a mutational stage
|
||||
let mutator = HavocBytesMutator::default();
|
||||
let stage = StdMutationalStage::new(mutator);
|
||||
|
||||
// A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus
|
||||
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||
let fuzzer = StdFuzzer::new(scheduler, tuple_list!(stage));
|
||||
|
||||
// Create the executor for an in-process function with just one observer for edge coverage
|
||||
let mut executor = InProcessExecutor::new(
|
||||
"in-process(edges)",
|
||||
&mut harness,
|
||||
tuple_list!(edges_observer, TimeObserver::new("time")),
|
||||
&mut state,
|
||||
&mut restarting_mgr,
|
||||
)?;
|
||||
|
||||
// The actual target run starts here.
|
||||
// Call LLVMFUzzerInitialize() if present.
|
||||
unsafe {
|
||||
if afl_libfuzzer_init() == -1 {
|
||||
println!("Warning: LLVMFuzzerInitialize failed with -1")
|
||||
}
|
||||
}
|
||||
|
||||
// In case the corpus is empty (on first run), reset
|
||||
if state.corpus().count() < 1 {
|
||||
state
|
||||
.load_initial_inputs(
|
||||
&mut executor,
|
||||
&mut restarting_mgr,
|
||||
fuzzer.scheduler(),
|
||||
&corpus_dirs,
|
||||
)
|
||||
.expect(&format!(
|
||||
"Failed to load initial corpus at {:?}",
|
||||
&corpus_dirs
|
||||
));
|
||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||
}
|
||||
|
||||
fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?;
|
||||
|
||||
// Never reached
|
||||
Ok(())
|
||||
}
|
7762
fuzzers/libfuzzer_windows/stb_image.h
Normal file
7762
fuzzers/libfuzzer_windows/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
20
fuzzers/libfuzzer_windows/test.bat
Normal file
20
fuzzers/libfuzzer_windows/test.bat
Normal file
@ -0,0 +1,20 @@
|
||||
mkdir crashes
|
||||
del .\.libfuzzer_test.elf
|
||||
|
||||
cargo build --example libfuzzer_windows --release
|
||||
timeout /T 1
|
||||
cp ..\..\target\release\examples\libfuzzer_windows.exe .\.libfuzzer_test.exe
|
||||
timeout /T 1
|
||||
|
||||
# The broker
|
||||
start .\.libfuzzer_test.exe
|
||||
# Give the broker time to spawn
|
||||
timeout /T 1
|
||||
echo "Spawning client"
|
||||
start .\.libfuzzer_test.exe
|
||||
# .\.libfuzzer_test.exe > nul
|
||||
|
||||
timeout /T 10
|
||||
echo "Finished fuzzing for a bit"
|
||||
TASKKILL /IM .libfuzzer_test.exe
|
||||
del .libfuzzer_test.exe
|
@ -102,6 +102,7 @@ use crate::{
|
||||
Error,
|
||||
};
|
||||
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
use super::shmem::HasFd;
|
||||
|
||||
/// We'll start off with 256 megabyte maps per fuzzer client
|
||||
@ -450,6 +451,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
impl<SH> LlmpConnection<SH>
|
||||
where
|
||||
SH: ShMem + HasFd,
|
||||
@ -1888,6 +1890,7 @@ where
|
||||
/// `n` clients connect to a broker. They share an outgoing map with the broker,
|
||||
/// and get incoming messages from the shared broker bus
|
||||
/// If the Shm has a fd, we can attach to it.
|
||||
#[cfg(all(unix, feature = "std"))]
|
||||
impl<SH> LlmpClient<SH>
|
||||
where
|
||||
SH: ShMem + HasFd,
|
||||
|
@ -1,332 +1,334 @@
|
||||
pub use crate::bolts::bindings::windows::win32::debug::EXCEPTION_POINTERS;
|
||||
|
||||
use crate::{bolts::bindings::windows::win32::debug::SetUnhandledExceptionFilter, Error};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
convert::TryFrom,
|
||||
fmt::{self, Display, Formatter},
|
||||
ptr::write_volatile,
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
use std::os::raw::{c_long, c_void};
|
||||
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
|
||||
//const EXCEPTION_CONTINUE_EXECUTION: c_long = -1;
|
||||
//const EXCEPTION_CONTINUE_SEARCH: c_long = 0;
|
||||
const EXCEPTION_EXECUTE_HANDLER: c_long = 1;
|
||||
|
||||
// From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611
|
||||
pub const STATUS_WAIT_0: u32 = 0x00000000;
|
||||
pub const STATUS_ABANDONED_WAIT_0: u32 = 0x00000080;
|
||||
pub const STATUS_USER_APC: u32 = 0x000000C0;
|
||||
pub const STATUS_TIMEOUT: u32 = 0x00000102;
|
||||
pub const STATUS_PENDING: u32 = 0x00000103;
|
||||
pub const STATUS_SEGMENT_NOTIFICATION: u32 = 0x40000005;
|
||||
pub const STATUS_FATAL_APP_EXIT: u32 = 0x40000015;
|
||||
pub const STATUS_GUARD_PAGE_VIOLATION: u32 = 0x80000001;
|
||||
pub const STATUS_DATATYPE_MISALIGNMENT: u32 = 0x80000002;
|
||||
pub const STATUS_BREAKPOINT: u32 = 0x80000003;
|
||||
pub const STATUS_SINGLE_STEP: u32 = 0x80000004;
|
||||
pub const STATUS_LONGJUMP: u32 = 0x80000026;
|
||||
pub const STATUS_UNWIND_CONSOLIDATE: u32 = 0x80000029;
|
||||
pub const STATUS_ACCESS_VIOLATION: u32 = 0xC0000005;
|
||||
pub const STATUS_IN_PAGE_ERROR: u32 = 0xC0000006;
|
||||
pub const STATUS_INVALID_HANDLE: u32 = 0xC0000008;
|
||||
pub const STATUS_NO_MEMORY: u32 = 0xC0000017;
|
||||
pub const STATUS_ILLEGAL_INSTRUCTION: u32 = 0xC000001D;
|
||||
pub const STATUS_NONCONTINUABLE_EXCEPTION: u32 = 0xC0000025;
|
||||
pub const STATUS_INVALID_DISPOSITION: u32 = 0xC0000026;
|
||||
pub const STATUS_ARRAY_BOUNDS_EXCEEDED: u32 = 0xC000008C;
|
||||
pub const STATUS_FLOAT_DENORMAL_OPERAND: u32 = 0xC000008D;
|
||||
pub const STATUS_FLOAT_DIVIDE_BY_ZERO: u32 = 0xC000008E;
|
||||
pub const STATUS_FLOAT_INEXACT_RESULT: u32 = 0xC000008F;
|
||||
pub const STATUS_FLOAT_INVALID_OPERATION: u32 = 0xC0000090;
|
||||
pub const STATUS_FLOAT_OVERFLOW: u32 = 0xC0000091;
|
||||
pub const STATUS_FLOAT_STACK_CHECK: u32 = 0xC0000092;
|
||||
pub const STATUS_FLOAT_UNDERFLOW: u32 = 0xC0000093;
|
||||
pub const STATUS_INTEGER_DIVIDE_BY_ZERO: u32 = 0xC0000094;
|
||||
pub const STATUS_INTEGER_OVERFLOW: u32 = 0xC0000095;
|
||||
pub const STATUS_PRIVILEGED_INSTRUCTION: u32 = 0xC0000096;
|
||||
pub const STATUS_STACK_OVERFLOW: u32 = 0xC00000FD;
|
||||
pub const STATUS_DLL_NOT_FOUND: u32 = 0xC0000135;
|
||||
pub const STATUS_ORDINAL_NOT_FOUND: u32 = 0xC0000138;
|
||||
pub const STATUS_ENTRYPOINT_NOT_FOUND: u32 = 0xC0000139;
|
||||
pub const STATUS_CONTROL_C_EXIT: u32 = 0xC000013A;
|
||||
pub const STATUS_DLL_INIT_FAILED: u32 = 0xC0000142;
|
||||
pub const STATUS_FLOAT_MULTIPLE_FAULTS: u32 = 0xC00002B4;
|
||||
pub const STATUS_FLOAT_MULTIPLE_TRAPS: u32 = 0xC00002B5;
|
||||
pub const STATUS_REG_NAT_CONSUMPTION: u32 = 0xC00002C9;
|
||||
pub const STATUS_HEAP_CORRUPTION: u32 = 0xC0000374;
|
||||
pub const STATUS_STACK_BUFFER_OVERRUN: u32 = 0xC0000409;
|
||||
pub const STATUS_INVALID_CRUNTIME_PARAMETER: u32 = 0xC0000417;
|
||||
pub const STATUS_ASSERTION_FAILURE: u32 = 0xC0000420;
|
||||
pub const STATUS_SXS_EARLY_DEACTIVATION: u32 = 0xC015000F;
|
||||
pub const STATUS_SXS_INVALID_DEACTIVATION: u32 = 0xC0150010;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
pub enum ExceptionCode {
|
||||
// From https://docs.microsoft.com/en-us/windows/win32/debug/getexceptioncode
|
||||
AccessViolation = STATUS_ACCESS_VIOLATION,
|
||||
ArrayBoundsExceeded = STATUS_ARRAY_BOUNDS_EXCEEDED,
|
||||
Breakpoint = STATUS_BREAKPOINT,
|
||||
DatatypeMisalignment = STATUS_DATATYPE_MISALIGNMENT,
|
||||
FltDenormalOperand = STATUS_FLOAT_DENORMAL_OPERAND,
|
||||
FltDivideByZero = STATUS_FLOAT_DIVIDE_BY_ZERO,
|
||||
FltInexactResult = STATUS_FLOAT_INEXACT_RESULT,
|
||||
FltInvalidOperation = STATUS_FLOAT_INVALID_OPERATION,
|
||||
FltOverflow = STATUS_FLOAT_OVERFLOW,
|
||||
FltStackCheck = STATUS_FLOAT_STACK_CHECK,
|
||||
FltUnderflow = STATUS_FLOAT_UNDERFLOW,
|
||||
GuardPageViolation = STATUS_GUARD_PAGE_VIOLATION,
|
||||
IllegalInstruction = STATUS_ILLEGAL_INSTRUCTION,
|
||||
InPageError = STATUS_IN_PAGE_ERROR,
|
||||
IntegerDivideByZero = STATUS_INTEGER_DIVIDE_BY_ZERO,
|
||||
IntegerOverflow = STATUS_INTEGER_OVERFLOW,
|
||||
InvalidDisposition = STATUS_INVALID_DISPOSITION,
|
||||
InvalidHandle = STATUS_INVALID_HANDLE,
|
||||
NoncontinuableException = STATUS_NONCONTINUABLE_EXCEPTION,
|
||||
PrivilegedInstruction = STATUS_PRIVILEGED_INSTRUCTION,
|
||||
SingleStep = STATUS_SINGLE_STEP,
|
||||
StackOverflow = STATUS_STACK_OVERFLOW,
|
||||
UnwindConsolidate = STATUS_UNWIND_CONSOLIDATE,
|
||||
// Addition exceptions
|
||||
Wait0 = STATUS_WAIT_0,
|
||||
AbandonedWait0 = STATUS_ABANDONED_WAIT_0,
|
||||
UserAPC = STATUS_USER_APC,
|
||||
Timeout = STATUS_TIMEOUT,
|
||||
Pending = STATUS_PENDING,
|
||||
SegmentNotification = STATUS_SEGMENT_NOTIFICATION,
|
||||
FatalAppExit = STATUS_FATAL_APP_EXIT,
|
||||
Longjump = STATUS_LONGJUMP,
|
||||
DLLNotFound = STATUS_DLL_NOT_FOUND,
|
||||
OrdinalNotFound = STATUS_ORDINAL_NOT_FOUND,
|
||||
EntryPointNotFound = STATUS_ENTRYPOINT_NOT_FOUND,
|
||||
ControlCExit = STATUS_CONTROL_C_EXIT,
|
||||
DllInitFailed = STATUS_DLL_INIT_FAILED,
|
||||
FltMultipleFaults = STATUS_FLOAT_MULTIPLE_FAULTS,
|
||||
FltMultipleTraps = STATUS_FLOAT_MULTIPLE_TRAPS,
|
||||
RegNatConsumption = STATUS_REG_NAT_CONSUMPTION,
|
||||
HeapCorruption = STATUS_HEAP_CORRUPTION,
|
||||
StackBufferOverrun = STATUS_STACK_BUFFER_OVERRUN,
|
||||
InvalidCRuntimeParameter = STATUS_INVALID_CRUNTIME_PARAMETER,
|
||||
AssertionFailure = STATUS_ASSERTION_FAILURE,
|
||||
SXSEarlyDeactivation = STATUS_SXS_EARLY_DEACTIVATION,
|
||||
SXSInvalidDeactivation = STATUS_SXS_INVALID_DEACTIVATION,
|
||||
}
|
||||
|
||||
pub static CRASH_EXCEPTIONS: &[ExceptionCode] = &[
|
||||
ExceptionCode::AccessViolation,
|
||||
ExceptionCode::ArrayBoundsExceeded,
|
||||
ExceptionCode::FltDivideByZero,
|
||||
ExceptionCode::GuardPageViolation,
|
||||
ExceptionCode::IllegalInstruction,
|
||||
ExceptionCode::InPageError,
|
||||
ExceptionCode::IntegerDivideByZero,
|
||||
ExceptionCode::InvalidHandle,
|
||||
ExceptionCode::NoncontinuableException,
|
||||
ExceptionCode::PrivilegedInstruction,
|
||||
ExceptionCode::StackOverflow,
|
||||
ExceptionCode::HeapCorruption,
|
||||
ExceptionCode::StackBufferOverrun,
|
||||
ExceptionCode::AssertionFailure,
|
||||
];
|
||||
|
||||
impl PartialEq for ExceptionCode {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self as u32 == *other as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ExceptionCode {}
|
||||
|
||||
unsafe impl Sync for ExceptionCode {}
|
||||
|
||||
impl Display for ExceptionCode {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
ExceptionCode::AccessViolation => write!(f, "STATUS_ACCESS_VIOLATION")?,
|
||||
ExceptionCode::ArrayBoundsExceeded => write!(f, "STATUS_ARRAY_BOUNDS_EXCEEDED")?,
|
||||
ExceptionCode::Breakpoint => write!(f, "STATUS_BREAKPOINT")?,
|
||||
ExceptionCode::DatatypeMisalignment => write!(f, "STATUS_DATATYPE_MISALIGNMENT")?,
|
||||
ExceptionCode::FltDenormalOperand => write!(f, "STATUS_FLOAT_DENORMAL_OPERAND")?,
|
||||
ExceptionCode::FltDivideByZero => write!(f, "STATUS_FLOAT_DIVIDE_BY_ZERO")?,
|
||||
ExceptionCode::FltInexactResult => write!(f, "STATUS_FLOAT_INEXACT_RESULT")?,
|
||||
ExceptionCode::FltInvalidOperation => write!(f, "STATUS_FLOAT_INVALID_OPERATION")?,
|
||||
ExceptionCode::FltOverflow => write!(f, "STATUS_FLOAT_OVERFLOW")?,
|
||||
ExceptionCode::FltStackCheck => write!(f, "STATUS_FLOAT_STACK_CHECK")?,
|
||||
ExceptionCode::FltUnderflow => write!(f, "STATUS_FLOAT_UNDERFLOW")?,
|
||||
ExceptionCode::GuardPageViolation => write!(f, "STATUS_GUARD_PAGE_VIOLATION")?,
|
||||
ExceptionCode::IllegalInstruction => write!(f, "STATUS_ILLEGAL_INSTRUCTION")?,
|
||||
ExceptionCode::InPageError => write!(f, "STATUS_IN_PAGE_ERROR")?,
|
||||
ExceptionCode::IntegerDivideByZero => write!(f, "STATUS_INTEGER_DIVIDE_BY_ZERO")?,
|
||||
ExceptionCode::IntegerOverflow => write!(f, "STATUS_INTEGER_OVERFLOW")?,
|
||||
ExceptionCode::InvalidDisposition => write!(f, "STATUS_INVALID_DISPOSITION")?,
|
||||
ExceptionCode::InvalidHandle => write!(f, "STATUS_INVALID_HANDLE")?,
|
||||
ExceptionCode::NoncontinuableException => write!(f, "STATUS_NONCONTINUABLE_EXCEPTION")?,
|
||||
ExceptionCode::PrivilegedInstruction => write!(f, "STATUS_PRIVILEGED_INSTRUCTION")?,
|
||||
ExceptionCode::SingleStep => write!(f, "STATUS_SINGLE_STEP")?,
|
||||
ExceptionCode::StackOverflow => write!(f, "STATUS_STACK_OVERFLOW")?,
|
||||
ExceptionCode::UnwindConsolidate => write!(f, "STATUS_UNWIND_CONSOLIDATE")?,
|
||||
ExceptionCode::Wait0 => write!(f, "STATUS_WAIT_0")?,
|
||||
ExceptionCode::AbandonedWait0 => write!(f, "STATUS_ABANDONED_WAIT_0")?,
|
||||
ExceptionCode::UserAPC => write!(f, "STATUS_USER_APC")?,
|
||||
ExceptionCode::Timeout => write!(f, "STATUS_TIMEOUT")?,
|
||||
ExceptionCode::Pending => write!(f, "STATUS_PENDING")?,
|
||||
ExceptionCode::SegmentNotification => write!(f, "STATUS_SEGMENT_NOTIFICATION")?,
|
||||
ExceptionCode::FatalAppExit => write!(f, "STATUS_FATAL_APP_EXIT")?,
|
||||
ExceptionCode::Longjump => write!(f, "STATUS_LONGJUMP")?,
|
||||
ExceptionCode::DLLNotFound => write!(f, "STATUS_DLL_NOT_FOUND")?,
|
||||
ExceptionCode::OrdinalNotFound => write!(f, "STATUS_ORDINAL_NOT_FOUND")?,
|
||||
ExceptionCode::EntryPointNotFound => write!(f, "STATUS_ENTRYPOINT_NOT_FOUND")?,
|
||||
ExceptionCode::ControlCExit => write!(f, "STATUS_CONTROL_C_EXIT")?,
|
||||
ExceptionCode::DllInitFailed => write!(f, "STATUS_DLL_INIT_FAILED")?,
|
||||
ExceptionCode::FltMultipleFaults => write!(f, "STATUS_FLOAT_MULTIPLE_FAULTS")?,
|
||||
ExceptionCode::FltMultipleTraps => write!(f, "STATUS_FLOAT_MULTIPLE_TRAPS")?,
|
||||
ExceptionCode::RegNatConsumption => write!(f, "STATUS_REG_NAT_CONSUMPTION")?,
|
||||
ExceptionCode::HeapCorruption => write!(f, "STATUS_HEAP_CORRUPTION")?,
|
||||
ExceptionCode::StackBufferOverrun => write!(f, "STATUS_STACK_BUFFER_OVERRUN")?,
|
||||
ExceptionCode::InvalidCRuntimeParameter => {
|
||||
write!(f, "STATUS_INVALID_CRUNTIME_PARAMETER")?
|
||||
}
|
||||
ExceptionCode::AssertionFailure => write!(f, "STATUS_ASSERTION_FAILURE")?,
|
||||
ExceptionCode::SXSEarlyDeactivation => write!(f, "STATUS_SXS_EARLY_DEACTIVATION")?,
|
||||
ExceptionCode::SXSInvalidDeactivation => write!(f, "STATUS_SXS_INVALID_DEACTIVATION")?,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub static EXCEPTION_CODES_MAPPING: [ExceptionCode; 45] = [
|
||||
ExceptionCode::AccessViolation,
|
||||
ExceptionCode::ArrayBoundsExceeded,
|
||||
ExceptionCode::Breakpoint,
|
||||
ExceptionCode::DatatypeMisalignment,
|
||||
ExceptionCode::FltDenormalOperand,
|
||||
ExceptionCode::FltDivideByZero,
|
||||
ExceptionCode::FltInexactResult,
|
||||
ExceptionCode::FltInvalidOperation,
|
||||
ExceptionCode::FltOverflow,
|
||||
ExceptionCode::FltStackCheck,
|
||||
ExceptionCode::FltUnderflow,
|
||||
ExceptionCode::GuardPageViolation,
|
||||
ExceptionCode::IllegalInstruction,
|
||||
ExceptionCode::InPageError,
|
||||
ExceptionCode::IntegerDivideByZero,
|
||||
ExceptionCode::IntegerOverflow,
|
||||
ExceptionCode::InvalidDisposition,
|
||||
ExceptionCode::InvalidHandle,
|
||||
ExceptionCode::NoncontinuableException,
|
||||
ExceptionCode::PrivilegedInstruction,
|
||||
ExceptionCode::SingleStep,
|
||||
ExceptionCode::StackOverflow,
|
||||
ExceptionCode::UnwindConsolidate,
|
||||
ExceptionCode::Wait0,
|
||||
ExceptionCode::AbandonedWait0,
|
||||
ExceptionCode::UserAPC,
|
||||
ExceptionCode::Timeout,
|
||||
ExceptionCode::Pending,
|
||||
ExceptionCode::SegmentNotification,
|
||||
ExceptionCode::FatalAppExit,
|
||||
ExceptionCode::Longjump,
|
||||
ExceptionCode::DLLNotFound,
|
||||
ExceptionCode::OrdinalNotFound,
|
||||
ExceptionCode::EntryPointNotFound,
|
||||
ExceptionCode::ControlCExit,
|
||||
ExceptionCode::DllInitFailed,
|
||||
ExceptionCode::FltMultipleFaults,
|
||||
ExceptionCode::FltMultipleTraps,
|
||||
ExceptionCode::RegNatConsumption,
|
||||
ExceptionCode::HeapCorruption,
|
||||
ExceptionCode::StackBufferOverrun,
|
||||
ExceptionCode::InvalidCRuntimeParameter,
|
||||
ExceptionCode::AssertionFailure,
|
||||
ExceptionCode::SXSEarlyDeactivation,
|
||||
ExceptionCode::SXSInvalidDeactivation,
|
||||
];
|
||||
|
||||
pub trait Handler {
|
||||
/// Handle an exception
|
||||
fn handle(
|
||||
&mut self,
|
||||
exception_code: ExceptionCode,
|
||||
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||
);
|
||||
/// Return a list of exceptions to handle
|
||||
fn exceptions(&self) -> Vec<ExceptionCode>;
|
||||
}
|
||||
|
||||
struct HandlerHolder {
|
||||
handler: UnsafeCell<*mut dyn Handler>,
|
||||
}
|
||||
|
||||
unsafe impl Send for HandlerHolder {}
|
||||
|
||||
/// Keep track of which handler is registered for which exception
|
||||
static mut EXCEPTION_HANDLERS: [Option<HandlerHolder>; 64] = [
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
];
|
||||
|
||||
type NativeHandlerType = extern "system" fn(*mut EXCEPTION_POINTERS) -> c_long;
|
||||
static mut PREVIOUS_HANDLER: Option<NativeHandlerType> = None;
|
||||
|
||||
/// Internal function that is being called whenever an exception arrives (stdcall).
|
||||
unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_POINTERS) -> c_long {
|
||||
let code = exception_pointers
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.exception_record
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.exception_code;
|
||||
let exception_code = ExceptionCode::try_from(code).unwrap();
|
||||
let index = EXCEPTION_CODES_MAPPING
|
||||
.iter()
|
||||
.position(|x| *x == exception_code)
|
||||
.unwrap();
|
||||
let ret = match &EXCEPTION_HANDLERS[index] {
|
||||
Some(handler_holder) => {
|
||||
let handler = &mut **handler_holder.handler.get();
|
||||
handler.handle(exception_code, exception_pointers);
|
||||
EXCEPTION_EXECUTE_HANDLER
|
||||
}
|
||||
None => EXCEPTION_EXECUTE_HANDLER,
|
||||
};
|
||||
if let Some(prev_handler) = PREVIOUS_HANDLER {
|
||||
prev_handler(exception_pointers)
|
||||
} else {
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/// Setup Win32 exception handlers in a somewhat rusty way.
|
||||
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
|
||||
let exceptions = handler.exceptions();
|
||||
for exception_code in exceptions {
|
||||
let index = EXCEPTION_CODES_MAPPING
|
||||
.iter()
|
||||
.position(|x| *x == exception_code)
|
||||
.unwrap();
|
||||
write_volatile(
|
||||
&mut EXCEPTION_HANDLERS[index],
|
||||
Some(HandlerHolder {
|
||||
handler: UnsafeCell::new(handler as *mut dyn Handler),
|
||||
}),
|
||||
);
|
||||
}
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
if let Some(prev) = SetUnhandledExceptionFilter(Some(core::mem::transmute(
|
||||
handle_exception as *const c_void,
|
||||
))) {
|
||||
PREVIOUS_HANDLER = Some(core::mem::transmute(prev as *const c_void));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub use crate::bolts::bindings::windows::win32::debug::EXCEPTION_POINTERS;
|
||||
|
||||
use crate::{bolts::bindings::windows::win32::debug::SetUnhandledExceptionFilter, Error};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
convert::TryFrom,
|
||||
fmt::{self, Display, Formatter},
|
||||
ptr::write_volatile,
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
use std::os::raw::{c_long, c_void};
|
||||
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
|
||||
//const EXCEPTION_CONTINUE_EXECUTION: c_long = -1;
|
||||
//const EXCEPTION_CONTINUE_SEARCH: c_long = 0;
|
||||
const EXCEPTION_EXECUTE_HANDLER: c_long = 1;
|
||||
|
||||
// From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611
|
||||
pub const STATUS_WAIT_0: u32 = 0x00000000;
|
||||
pub const STATUS_ABANDONED_WAIT_0: u32 = 0x00000080;
|
||||
pub const STATUS_USER_APC: u32 = 0x000000C0;
|
||||
pub const STATUS_TIMEOUT: u32 = 0x00000102;
|
||||
pub const STATUS_PENDING: u32 = 0x00000103;
|
||||
pub const STATUS_SEGMENT_NOTIFICATION: u32 = 0x40000005;
|
||||
pub const STATUS_FATAL_APP_EXIT: u32 = 0x40000015;
|
||||
pub const STATUS_GUARD_PAGE_VIOLATION: u32 = 0x80000001;
|
||||
pub const STATUS_DATATYPE_MISALIGNMENT: u32 = 0x80000002;
|
||||
pub const STATUS_BREAKPOINT: u32 = 0x80000003;
|
||||
pub const STATUS_SINGLE_STEP: u32 = 0x80000004;
|
||||
pub const STATUS_LONGJUMP: u32 = 0x80000026;
|
||||
pub const STATUS_UNWIND_CONSOLIDATE: u32 = 0x80000029;
|
||||
pub const STATUS_ACCESS_VIOLATION: u32 = 0xC0000005;
|
||||
pub const STATUS_IN_PAGE_ERROR: u32 = 0xC0000006;
|
||||
pub const STATUS_INVALID_HANDLE: u32 = 0xC0000008;
|
||||
pub const STATUS_NO_MEMORY: u32 = 0xC0000017;
|
||||
pub const STATUS_ILLEGAL_INSTRUCTION: u32 = 0xC000001D;
|
||||
pub const STATUS_NONCONTINUABLE_EXCEPTION: u32 = 0xC0000025;
|
||||
pub const STATUS_INVALID_DISPOSITION: u32 = 0xC0000026;
|
||||
pub const STATUS_ARRAY_BOUNDS_EXCEEDED: u32 = 0xC000008C;
|
||||
pub const STATUS_FLOAT_DENORMAL_OPERAND: u32 = 0xC000008D;
|
||||
pub const STATUS_FLOAT_DIVIDE_BY_ZERO: u32 = 0xC000008E;
|
||||
pub const STATUS_FLOAT_INEXACT_RESULT: u32 = 0xC000008F;
|
||||
pub const STATUS_FLOAT_INVALID_OPERATION: u32 = 0xC0000090;
|
||||
pub const STATUS_FLOAT_OVERFLOW: u32 = 0xC0000091;
|
||||
pub const STATUS_FLOAT_STACK_CHECK: u32 = 0xC0000092;
|
||||
pub const STATUS_FLOAT_UNDERFLOW: u32 = 0xC0000093;
|
||||
pub const STATUS_INTEGER_DIVIDE_BY_ZERO: u32 = 0xC0000094;
|
||||
pub const STATUS_INTEGER_OVERFLOW: u32 = 0xC0000095;
|
||||
pub const STATUS_PRIVILEGED_INSTRUCTION: u32 = 0xC0000096;
|
||||
pub const STATUS_STACK_OVERFLOW: u32 = 0xC00000FD;
|
||||
pub const STATUS_DLL_NOT_FOUND: u32 = 0xC0000135;
|
||||
pub const STATUS_ORDINAL_NOT_FOUND: u32 = 0xC0000138;
|
||||
pub const STATUS_ENTRYPOINT_NOT_FOUND: u32 = 0xC0000139;
|
||||
pub const STATUS_CONTROL_C_EXIT: u32 = 0xC000013A;
|
||||
pub const STATUS_DLL_INIT_FAILED: u32 = 0xC0000142;
|
||||
pub const STATUS_FLOAT_MULTIPLE_FAULTS: u32 = 0xC00002B4;
|
||||
pub const STATUS_FLOAT_MULTIPLE_TRAPS: u32 = 0xC00002B5;
|
||||
pub const STATUS_REG_NAT_CONSUMPTION: u32 = 0xC00002C9;
|
||||
pub const STATUS_HEAP_CORRUPTION: u32 = 0xC0000374;
|
||||
pub const STATUS_STACK_BUFFER_OVERRUN: u32 = 0xC0000409;
|
||||
pub const STATUS_INVALID_CRUNTIME_PARAMETER: u32 = 0xC0000417;
|
||||
pub const STATUS_ASSERTION_FAILURE: u32 = 0xC0000420;
|
||||
pub const STATUS_SXS_EARLY_DEACTIVATION: u32 = 0xC015000F;
|
||||
pub const STATUS_SXS_INVALID_DEACTIVATION: u32 = 0xC0150010;
|
||||
|
||||
#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)]
|
||||
#[repr(u32)]
|
||||
pub enum ExceptionCode {
|
||||
// From https://docs.microsoft.com/en-us/windows/win32/debug/getexceptioncode
|
||||
AccessViolation = STATUS_ACCESS_VIOLATION,
|
||||
ArrayBoundsExceeded = STATUS_ARRAY_BOUNDS_EXCEEDED,
|
||||
Breakpoint = STATUS_BREAKPOINT,
|
||||
DatatypeMisalignment = STATUS_DATATYPE_MISALIGNMENT,
|
||||
FltDenormalOperand = STATUS_FLOAT_DENORMAL_OPERAND,
|
||||
FltDivideByZero = STATUS_FLOAT_DIVIDE_BY_ZERO,
|
||||
FltInexactResult = STATUS_FLOAT_INEXACT_RESULT,
|
||||
FltInvalidOperation = STATUS_FLOAT_INVALID_OPERATION,
|
||||
FltOverflow = STATUS_FLOAT_OVERFLOW,
|
||||
FltStackCheck = STATUS_FLOAT_STACK_CHECK,
|
||||
FltUnderflow = STATUS_FLOAT_UNDERFLOW,
|
||||
GuardPageViolation = STATUS_GUARD_PAGE_VIOLATION,
|
||||
IllegalInstruction = STATUS_ILLEGAL_INSTRUCTION,
|
||||
InPageError = STATUS_IN_PAGE_ERROR,
|
||||
IntegerDivideByZero = STATUS_INTEGER_DIVIDE_BY_ZERO,
|
||||
IntegerOverflow = STATUS_INTEGER_OVERFLOW,
|
||||
InvalidDisposition = STATUS_INVALID_DISPOSITION,
|
||||
InvalidHandle = STATUS_INVALID_HANDLE,
|
||||
NoncontinuableException = STATUS_NONCONTINUABLE_EXCEPTION,
|
||||
PrivilegedInstruction = STATUS_PRIVILEGED_INSTRUCTION,
|
||||
SingleStep = STATUS_SINGLE_STEP,
|
||||
StackOverflow = STATUS_STACK_OVERFLOW,
|
||||
UnwindConsolidate = STATUS_UNWIND_CONSOLIDATE,
|
||||
// Addition exceptions
|
||||
Wait0 = STATUS_WAIT_0,
|
||||
AbandonedWait0 = STATUS_ABANDONED_WAIT_0,
|
||||
UserAPC = STATUS_USER_APC,
|
||||
Timeout = STATUS_TIMEOUT,
|
||||
Pending = STATUS_PENDING,
|
||||
SegmentNotification = STATUS_SEGMENT_NOTIFICATION,
|
||||
FatalAppExit = STATUS_FATAL_APP_EXIT,
|
||||
Longjump = STATUS_LONGJUMP,
|
||||
DLLNotFound = STATUS_DLL_NOT_FOUND,
|
||||
OrdinalNotFound = STATUS_ORDINAL_NOT_FOUND,
|
||||
EntryPointNotFound = STATUS_ENTRYPOINT_NOT_FOUND,
|
||||
ControlCExit = STATUS_CONTROL_C_EXIT,
|
||||
DllInitFailed = STATUS_DLL_INIT_FAILED,
|
||||
FltMultipleFaults = STATUS_FLOAT_MULTIPLE_FAULTS,
|
||||
FltMultipleTraps = STATUS_FLOAT_MULTIPLE_TRAPS,
|
||||
RegNatConsumption = STATUS_REG_NAT_CONSUMPTION,
|
||||
HeapCorruption = STATUS_HEAP_CORRUPTION,
|
||||
StackBufferOverrun = STATUS_STACK_BUFFER_OVERRUN,
|
||||
InvalidCRuntimeParameter = STATUS_INVALID_CRUNTIME_PARAMETER,
|
||||
AssertionFailure = STATUS_ASSERTION_FAILURE,
|
||||
SXSEarlyDeactivation = STATUS_SXS_EARLY_DEACTIVATION,
|
||||
SXSInvalidDeactivation = STATUS_SXS_INVALID_DEACTIVATION,
|
||||
}
|
||||
|
||||
pub static CRASH_EXCEPTIONS: &[ExceptionCode] = &[
|
||||
ExceptionCode::AccessViolation,
|
||||
ExceptionCode::ArrayBoundsExceeded,
|
||||
ExceptionCode::FltDivideByZero,
|
||||
ExceptionCode::GuardPageViolation,
|
||||
ExceptionCode::IllegalInstruction,
|
||||
ExceptionCode::InPageError,
|
||||
ExceptionCode::IntegerDivideByZero,
|
||||
ExceptionCode::InvalidHandle,
|
||||
ExceptionCode::NoncontinuableException,
|
||||
ExceptionCode::PrivilegedInstruction,
|
||||
ExceptionCode::StackOverflow,
|
||||
ExceptionCode::HeapCorruption,
|
||||
ExceptionCode::StackBufferOverrun,
|
||||
ExceptionCode::AssertionFailure,
|
||||
];
|
||||
|
||||
impl PartialEq for ExceptionCode {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self as u32 == *other as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ExceptionCode {}
|
||||
|
||||
unsafe impl Sync for ExceptionCode {}
|
||||
|
||||
impl Display for ExceptionCode {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
match self {
|
||||
ExceptionCode::AccessViolation => write!(f, "STATUS_ACCESS_VIOLATION")?,
|
||||
ExceptionCode::ArrayBoundsExceeded => write!(f, "STATUS_ARRAY_BOUNDS_EXCEEDED")?,
|
||||
ExceptionCode::Breakpoint => write!(f, "STATUS_BREAKPOINT")?,
|
||||
ExceptionCode::DatatypeMisalignment => write!(f, "STATUS_DATATYPE_MISALIGNMENT")?,
|
||||
ExceptionCode::FltDenormalOperand => write!(f, "STATUS_FLOAT_DENORMAL_OPERAND")?,
|
||||
ExceptionCode::FltDivideByZero => write!(f, "STATUS_FLOAT_DIVIDE_BY_ZERO")?,
|
||||
ExceptionCode::FltInexactResult => write!(f, "STATUS_FLOAT_INEXACT_RESULT")?,
|
||||
ExceptionCode::FltInvalidOperation => write!(f, "STATUS_FLOAT_INVALID_OPERATION")?,
|
||||
ExceptionCode::FltOverflow => write!(f, "STATUS_FLOAT_OVERFLOW")?,
|
||||
ExceptionCode::FltStackCheck => write!(f, "STATUS_FLOAT_STACK_CHECK")?,
|
||||
ExceptionCode::FltUnderflow => write!(f, "STATUS_FLOAT_UNDERFLOW")?,
|
||||
ExceptionCode::GuardPageViolation => write!(f, "STATUS_GUARD_PAGE_VIOLATION")?,
|
||||
ExceptionCode::IllegalInstruction => write!(f, "STATUS_ILLEGAL_INSTRUCTION")?,
|
||||
ExceptionCode::InPageError => write!(f, "STATUS_IN_PAGE_ERROR")?,
|
||||
ExceptionCode::IntegerDivideByZero => write!(f, "STATUS_INTEGER_DIVIDE_BY_ZERO")?,
|
||||
ExceptionCode::IntegerOverflow => write!(f, "STATUS_INTEGER_OVERFLOW")?,
|
||||
ExceptionCode::InvalidDisposition => write!(f, "STATUS_INVALID_DISPOSITION")?,
|
||||
ExceptionCode::InvalidHandle => write!(f, "STATUS_INVALID_HANDLE")?,
|
||||
ExceptionCode::NoncontinuableException => write!(f, "STATUS_NONCONTINUABLE_EXCEPTION")?,
|
||||
ExceptionCode::PrivilegedInstruction => write!(f, "STATUS_PRIVILEGED_INSTRUCTION")?,
|
||||
ExceptionCode::SingleStep => write!(f, "STATUS_SINGLE_STEP")?,
|
||||
ExceptionCode::StackOverflow => write!(f, "STATUS_STACK_OVERFLOW")?,
|
||||
ExceptionCode::UnwindConsolidate => write!(f, "STATUS_UNWIND_CONSOLIDATE")?,
|
||||
ExceptionCode::Wait0 => write!(f, "STATUS_WAIT_0")?,
|
||||
ExceptionCode::AbandonedWait0 => write!(f, "STATUS_ABANDONED_WAIT_0")?,
|
||||
ExceptionCode::UserAPC => write!(f, "STATUS_USER_APC")?,
|
||||
ExceptionCode::Timeout => write!(f, "STATUS_TIMEOUT")?,
|
||||
ExceptionCode::Pending => write!(f, "STATUS_PENDING")?,
|
||||
ExceptionCode::SegmentNotification => write!(f, "STATUS_SEGMENT_NOTIFICATION")?,
|
||||
ExceptionCode::FatalAppExit => write!(f, "STATUS_FATAL_APP_EXIT")?,
|
||||
ExceptionCode::Longjump => write!(f, "STATUS_LONGJUMP")?,
|
||||
ExceptionCode::DLLNotFound => write!(f, "STATUS_DLL_NOT_FOUND")?,
|
||||
ExceptionCode::OrdinalNotFound => write!(f, "STATUS_ORDINAL_NOT_FOUND")?,
|
||||
ExceptionCode::EntryPointNotFound => write!(f, "STATUS_ENTRYPOINT_NOT_FOUND")?,
|
||||
ExceptionCode::ControlCExit => write!(f, "STATUS_CONTROL_C_EXIT")?,
|
||||
ExceptionCode::DllInitFailed => write!(f, "STATUS_DLL_INIT_FAILED")?,
|
||||
ExceptionCode::FltMultipleFaults => write!(f, "STATUS_FLOAT_MULTIPLE_FAULTS")?,
|
||||
ExceptionCode::FltMultipleTraps => write!(f, "STATUS_FLOAT_MULTIPLE_TRAPS")?,
|
||||
ExceptionCode::RegNatConsumption => write!(f, "STATUS_REG_NAT_CONSUMPTION")?,
|
||||
ExceptionCode::HeapCorruption => write!(f, "STATUS_HEAP_CORRUPTION")?,
|
||||
ExceptionCode::StackBufferOverrun => write!(f, "STATUS_STACK_BUFFER_OVERRUN")?,
|
||||
ExceptionCode::InvalidCRuntimeParameter => {
|
||||
write!(f, "STATUS_INVALID_CRUNTIME_PARAMETER")?
|
||||
}
|
||||
ExceptionCode::AssertionFailure => write!(f, "STATUS_ASSERTION_FAILURE")?,
|
||||
ExceptionCode::SXSEarlyDeactivation => write!(f, "STATUS_SXS_EARLY_DEACTIVATION")?,
|
||||
ExceptionCode::SXSInvalidDeactivation => write!(f, "STATUS_SXS_INVALID_DEACTIVATION")?,
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub static EXCEPTION_CODES_MAPPING: [ExceptionCode; 45] = [
|
||||
ExceptionCode::AccessViolation,
|
||||
ExceptionCode::ArrayBoundsExceeded,
|
||||
ExceptionCode::Breakpoint,
|
||||
ExceptionCode::DatatypeMisalignment,
|
||||
ExceptionCode::FltDenormalOperand,
|
||||
ExceptionCode::FltDivideByZero,
|
||||
ExceptionCode::FltInexactResult,
|
||||
ExceptionCode::FltInvalidOperation,
|
||||
ExceptionCode::FltOverflow,
|
||||
ExceptionCode::FltStackCheck,
|
||||
ExceptionCode::FltUnderflow,
|
||||
ExceptionCode::GuardPageViolation,
|
||||
ExceptionCode::IllegalInstruction,
|
||||
ExceptionCode::InPageError,
|
||||
ExceptionCode::IntegerDivideByZero,
|
||||
ExceptionCode::IntegerOverflow,
|
||||
ExceptionCode::InvalidDisposition,
|
||||
ExceptionCode::InvalidHandle,
|
||||
ExceptionCode::NoncontinuableException,
|
||||
ExceptionCode::PrivilegedInstruction,
|
||||
ExceptionCode::SingleStep,
|
||||
ExceptionCode::StackOverflow,
|
||||
ExceptionCode::UnwindConsolidate,
|
||||
ExceptionCode::Wait0,
|
||||
ExceptionCode::AbandonedWait0,
|
||||
ExceptionCode::UserAPC,
|
||||
ExceptionCode::Timeout,
|
||||
ExceptionCode::Pending,
|
||||
ExceptionCode::SegmentNotification,
|
||||
ExceptionCode::FatalAppExit,
|
||||
ExceptionCode::Longjump,
|
||||
ExceptionCode::DLLNotFound,
|
||||
ExceptionCode::OrdinalNotFound,
|
||||
ExceptionCode::EntryPointNotFound,
|
||||
ExceptionCode::ControlCExit,
|
||||
ExceptionCode::DllInitFailed,
|
||||
ExceptionCode::FltMultipleFaults,
|
||||
ExceptionCode::FltMultipleTraps,
|
||||
ExceptionCode::RegNatConsumption,
|
||||
ExceptionCode::HeapCorruption,
|
||||
ExceptionCode::StackBufferOverrun,
|
||||
ExceptionCode::InvalidCRuntimeParameter,
|
||||
ExceptionCode::AssertionFailure,
|
||||
ExceptionCode::SXSEarlyDeactivation,
|
||||
ExceptionCode::SXSInvalidDeactivation,
|
||||
];
|
||||
|
||||
pub trait Handler {
|
||||
/// Handle an exception
|
||||
fn handle(
|
||||
&mut self,
|
||||
exception_code: ExceptionCode,
|
||||
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||
);
|
||||
/// Return a list of exceptions to handle
|
||||
fn exceptions(&self) -> Vec<ExceptionCode>;
|
||||
}
|
||||
|
||||
struct HandlerHolder {
|
||||
handler: UnsafeCell<*mut dyn Handler>,
|
||||
}
|
||||
|
||||
unsafe impl Send for HandlerHolder {}
|
||||
|
||||
/// Keep track of which handler is registered for which exception
|
||||
static mut EXCEPTION_HANDLERS: [Option<HandlerHolder>; 64] = [
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||||
];
|
||||
|
||||
type NativeHandlerType = extern "system" fn(*mut EXCEPTION_POINTERS) -> c_long;
|
||||
static mut PREVIOUS_HANDLER: Option<NativeHandlerType> = None;
|
||||
|
||||
/// Internal function that is being called whenever an exception arrives (stdcall).
|
||||
unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_POINTERS) -> c_long {
|
||||
let code = exception_pointers
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.exception_record
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.exception_code;
|
||||
let exception_code = ExceptionCode::try_from(code).unwrap();
|
||||
let index = EXCEPTION_CODES_MAPPING
|
||||
.iter()
|
||||
.position(|x| *x == exception_code)
|
||||
.unwrap();
|
||||
let ret = match &EXCEPTION_HANDLERS[index] {
|
||||
Some(handler_holder) => {
|
||||
let handler = &mut **handler_holder.handler.get();
|
||||
handler.handle(exception_code, exception_pointers);
|
||||
EXCEPTION_EXECUTE_HANDLER
|
||||
}
|
||||
None => EXCEPTION_EXECUTE_HANDLER,
|
||||
};
|
||||
if let Some(prev_handler) = PREVIOUS_HANDLER {
|
||||
prev_handler(exception_pointers)
|
||||
} else {
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/// Setup Win32 exception handlers in a somewhat rusty way.
|
||||
/// # Safety
|
||||
/// Exception handlers are usually ugly, handle with care!
|
||||
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
|
||||
let exceptions = handler.exceptions();
|
||||
for exception_code in exceptions {
|
||||
let index = EXCEPTION_CODES_MAPPING
|
||||
.iter()
|
||||
.position(|x| *x == exception_code)
|
||||
.unwrap();
|
||||
write_volatile(
|
||||
&mut EXCEPTION_HANDLERS[index],
|
||||
Some(HandlerHolder {
|
||||
handler: UnsafeCell::new(handler as *mut dyn Handler),
|
||||
}),
|
||||
);
|
||||
}
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
if let Some(prev) = SetUnhandledExceptionFilter(Some(core::mem::transmute(
|
||||
handle_exception as *const c_void,
|
||||
))) {
|
||||
PREVIOUS_HANDLER = Some(core::mem::transmute(prev as *const c_void));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ pub trait ShMem: Sized + Debug {
|
||||
}
|
||||
|
||||
/// shared maps that have an id can use this trait
|
||||
//#[cfg(all(unix, feature = "std"))]
|
||||
pub trait HasFd {
|
||||
/// Retrieve the id of this shared map
|
||||
fn shm_id(&self) -> i32;
|
||||
@ -519,9 +520,8 @@ pub mod shmem {
|
||||
String::from_utf8_lossy(map_str_bytes)
|
||||
)));
|
||||
}
|
||||
let map =
|
||||
MapViewOfFile(handle.clone(), FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||
if map == ptr::null_mut() {
|
||||
let map = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||
if map.is_null() {
|
||||
return Err(Error::Unknown(format!(
|
||||
"Cannot map shared memory {}",
|
||||
String::from_utf8_lossy(map_str_bytes)
|
||||
@ -558,8 +558,7 @@ pub mod shmem {
|
||||
String::from_utf8_lossy(map_str_bytes)
|
||||
)));
|
||||
}
|
||||
let map =
|
||||
MapViewOfFile(handle.clone(), FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||
let map = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||
if map == ptr::null_mut() {
|
||||
return Err(Error::Unknown(format!(
|
||||
"Cannot map shared memory {}",
|
||||
@ -568,9 +567,9 @@ pub mod shmem {
|
||||
}
|
||||
let mut ret = Self {
|
||||
shm_str: [0; 20],
|
||||
handle: handle,
|
||||
map: map,
|
||||
map_size: map_size,
|
||||
handle,
|
||||
map,
|
||||
map_size,
|
||||
};
|
||||
ret.shm_str.clone_from_slice(&map_str_bytes[0..20]);
|
||||
Ok(ret)
|
||||
|
@ -16,10 +16,14 @@ use crate::utils::{fork, ForkResult};
|
||||
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
use crate::bolts::shmem::UnixShMem;
|
||||
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
use crate::bolts::shmem::HasFd;
|
||||
|
||||
use crate::{
|
||||
bolts::{
|
||||
llmp::{self, LlmpClient, LlmpClientDescription, LlmpSender, Tag},
|
||||
shmem::{HasFd, ShMem},
|
||||
shmem::ShMem,
|
||||
},
|
||||
corpus::CorpusScheduler,
|
||||
events::{BrokerEventResult, Event, EventManager},
|
||||
@ -304,6 +308,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "std", unix))]
|
||||
impl<I, S, SH, ST> LlmpEventManager<I, S, SH, ST>
|
||||
where
|
||||
I: Input,
|
||||
@ -511,7 +516,7 @@ pub fn setup_restarting_mgr<I, S, SH, ST>(
|
||||
where
|
||||
I: Input,
|
||||
S: DeserializeOwned + IfInteresting<I>,
|
||||
SH: ShMem + HasFd, // Todo: HasFd is only needed for Android
|
||||
SH: ShMem, // Todo: HasFd is only needed for Android
|
||||
ST: Stats,
|
||||
{
|
||||
let mut mgr;
|
||||
|
Loading…
x
Reference in New Issue
Block a user