clang wrapper extend api
This commit is contained in:
commit
414a66382b
10
.github/workflows/build_and_test.yml
vendored
10
.github/workflows/build_and_test.yml
vendored
@ -63,5 +63,11 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Windows Build
|
- name: Windows Build
|
||||||
run: cargo build --verbose
|
run: cargo build --verbose
|
||||||
- name: Windows Test
|
# TODO: Figure out how to properly build stuff with clang
|
||||||
run: cargo test --verbose
|
#- 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/frida_libpng",
|
||||||
"fuzzers/libfuzzer_libmozjpeg",
|
"fuzzers/libfuzzer_libmozjpeg",
|
||||||
"fuzzers/libfuzzer_libpng_cmpalloc",
|
"fuzzers/libfuzzer_libpng_cmpalloc",
|
||||||
|
"fuzzers/libfuzzer_windows",
|
||||||
]
|
]
|
||||||
|
@ -90,7 +90,7 @@ fn main() {
|
|||||||
.to_command()
|
.to_command()
|
||||||
.current_dir(&cwd)
|
.current_dir(&cwd)
|
||||||
.arg("-I")
|
.arg("-I")
|
||||||
.arg(format!("{}", &libpng))
|
.arg(&libpng)
|
||||||
//.arg("-D")
|
//.arg("-D")
|
||||||
//.arg("HAS_DUMMY_CRASH=1")
|
//.arg("HAS_DUMMY_CRASH=1")
|
||||||
.arg("-fPIC")
|
.arg("-fPIC")
|
||||||
|
@ -34,8 +34,6 @@ use frida_gum::{
|
|||||||
};
|
};
|
||||||
use frida_gum::{Gum, MemoryRange, Module, NativePointer, PageProtection};
|
use frida_gum::{Gum, MemoryRange, Module, NativePointer, PageProtection};
|
||||||
|
|
||||||
use libloading;
|
|
||||||
|
|
||||||
use std::{cell::RefCell, env, ffi::c_void, path::PathBuf};
|
use std::{cell::RefCell, env, ffi::c_void, path::PathBuf};
|
||||||
|
|
||||||
/// An helper that feeds FridaInProcessExecutor with user-supplied instrumentation
|
/// An helper that feeds FridaInProcessExecutor with user-supplied instrumentation
|
||||||
@ -351,9 +349,9 @@ where
|
|||||||
));
|
));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
base: base,
|
base,
|
||||||
stalker: stalker,
|
stalker,
|
||||||
helper: helper,
|
helper,
|
||||||
followed: false,
|
followed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,10 +462,10 @@ unsafe fn fuzz(
|
|||||||
if state.metadata().get::<Tokens>().is_none() {
|
if state.metadata().get::<Tokens>().is_none() {
|
||||||
state.add_metadata(Tokens::new(vec![
|
state.add_metadata(Tokens::new(vec![
|
||||||
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
|
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
|
||||||
"IHDR".as_bytes().to_vec(),
|
b"IHDR".to_vec(),
|
||||||
"IDAT".as_bytes().to_vec(),
|
b"IDAT".to_vec(),
|
||||||
"PLTE".as_bytes().to_vec(),
|
b"PLTE".to_vec(),
|
||||||
"IEND".as_bytes().to_vec(),
|
b"IEND".to_vec(),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,10 @@ fn main() {
|
|||||||
.include(&libpng_path)
|
.include(&libpng_path)
|
||||||
.cpp(true)
|
.cpp(true)
|
||||||
.flag("-fsanitize-coverage=trace-pc-guard")
|
.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")
|
// .define("HAS_DUMMY_CRASH", "1")
|
||||||
.file("./harness.cc")
|
.file("./harness.cc")
|
||||||
.compile("libfuzzer-harness");
|
.compile("libfuzzer-harness");
|
||||||
|
@ -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) {
|
void *malloc(size_t size) {
|
||||||
|
|
||||||
uintptr_t k = (uintptr_t)__builtin_return_address(0);
|
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,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
use super::shmem::HasFd;
|
use super::shmem::HasFd;
|
||||||
|
|
||||||
/// We'll start off with 256 megabyte maps per fuzzer client
|
/// 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>
|
impl<SH> LlmpConnection<SH>
|
||||||
where
|
where
|
||||||
SH: ShMem + HasFd,
|
SH: ShMem + HasFd,
|
||||||
@ -1888,6 +1890,7 @@ where
|
|||||||
/// `n` clients connect to a broker. They share an outgoing map with the broker,
|
/// `n` clients connect to a broker. They share an outgoing map with the broker,
|
||||||
/// and get incoming messages from the shared broker bus
|
/// and get incoming messages from the shared broker bus
|
||||||
/// If the Shm has a fd, we can attach to it.
|
/// If the Shm has a fd, we can attach to it.
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
impl<SH> LlmpClient<SH>
|
impl<SH> LlmpClient<SH>
|
||||||
where
|
where
|
||||||
SH: ShMem + HasFd,
|
SH: ShMem + HasFd,
|
||||||
|
@ -307,6 +307,8 @@ unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_PO
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Setup Win32 exception handlers in a somewhat rusty way.
|
/// 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> {
|
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
|
||||||
let exceptions = handler.exceptions();
|
let exceptions = handler.exceptions();
|
||||||
for exception_code in exceptions {
|
for exception_code in exceptions {
|
||||||
|
@ -98,6 +98,7 @@ pub trait ShMem: Sized + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// shared maps that have an id can use this trait
|
/// shared maps that have an id can use this trait
|
||||||
|
//#[cfg(all(unix, feature = "std"))]
|
||||||
pub trait HasFd {
|
pub trait HasFd {
|
||||||
/// Retrieve the id of this shared map
|
/// Retrieve the id of this shared map
|
||||||
fn shm_id(&self) -> i32;
|
fn shm_id(&self) -> i32;
|
||||||
@ -519,9 +520,8 @@ pub mod shmem {
|
|||||||
String::from_utf8_lossy(map_str_bytes)
|
String::from_utf8_lossy(map_str_bytes)
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let map =
|
let map = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||||
MapViewOfFile(handle.clone(), FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
if map.is_null() {
|
||||||
if map == ptr::null_mut() {
|
|
||||||
return Err(Error::Unknown(format!(
|
return Err(Error::Unknown(format!(
|
||||||
"Cannot map shared memory {}",
|
"Cannot map shared memory {}",
|
||||||
String::from_utf8_lossy(map_str_bytes)
|
String::from_utf8_lossy(map_str_bytes)
|
||||||
@ -558,8 +558,7 @@ pub mod shmem {
|
|||||||
String::from_utf8_lossy(map_str_bytes)
|
String::from_utf8_lossy(map_str_bytes)
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let map =
|
let map = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
||||||
MapViewOfFile(handle.clone(), FILE_MAP_ALL_ACCESS, 0, 0, map_size) as *mut u8;
|
|
||||||
if map == ptr::null_mut() {
|
if map == ptr::null_mut() {
|
||||||
return Err(Error::Unknown(format!(
|
return Err(Error::Unknown(format!(
|
||||||
"Cannot map shared memory {}",
|
"Cannot map shared memory {}",
|
||||||
@ -568,9 +567,9 @@ pub mod shmem {
|
|||||||
}
|
}
|
||||||
let mut ret = Self {
|
let mut ret = Self {
|
||||||
shm_str: [0; 20],
|
shm_str: [0; 20],
|
||||||
handle: handle,
|
handle,
|
||||||
map: map,
|
map,
|
||||||
map_size: map_size,
|
map_size,
|
||||||
};
|
};
|
||||||
ret.shm_str.clone_from_slice(&map_str_bytes[0..20]);
|
ret.shm_str.clone_from_slice(&map_str_bytes[0..20]);
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
|
@ -16,10 +16,14 @@ use crate::utils::{fork, ForkResult};
|
|||||||
|
|
||||||
#[cfg(all(feature = "std", unix))]
|
#[cfg(all(feature = "std", unix))]
|
||||||
use crate::bolts::shmem::UnixShMem;
|
use crate::bolts::shmem::UnixShMem;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
use crate::bolts::shmem::HasFd;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{
|
bolts::{
|
||||||
llmp::{self, LlmpClient, LlmpClientDescription, LlmpSender, Tag},
|
llmp::{self, LlmpClient, LlmpClientDescription, LlmpSender, Tag},
|
||||||
shmem::{HasFd, ShMem},
|
shmem::ShMem,
|
||||||
},
|
},
|
||||||
corpus::CorpusScheduler,
|
corpus::CorpusScheduler,
|
||||||
events::{BrokerEventResult, Event, EventManager},
|
events::{BrokerEventResult, Event, EventManager},
|
||||||
@ -304,6 +308,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
impl<I, S, SH, ST> LlmpEventManager<I, S, SH, ST>
|
impl<I, S, SH, ST> LlmpEventManager<I, S, SH, ST>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
@ -511,7 +516,7 @@ pub fn setup_restarting_mgr<I, S, SH, ST>(
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
S: DeserializeOwned + IfInteresting<I>,
|
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,
|
ST: Stats,
|
||||||
{
|
{
|
||||||
let mut mgr;
|
let mut mgr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user