TinyInst Update (#968)
* tmp * more * save * TODO * fix * update to tinyinst on crates * dep * fmt * shmem done * cpp fmt * clp * fmt * why?? * ver * more makefile.toml * windows test * Update build_and_test.yml * fix * a * install * fmt * fix * only macos and win * more * The order matters * remove * fmt * chg * typo Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
This commit is contained in:
parent
3b68399cc9
commit
fe51286586
9
.github/workflows/build_and_test.yml
vendored
9
.github/workflows/build_and_test.yml
vendored
@ -173,6 +173,9 @@ jobs:
|
|||||||
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||||
- name: Add no_std toolchain
|
- name: Add no_std toolchain
|
||||||
run: rustup toolchain install nightly-x86_64-unknown-linux-gnu ; rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
run: rustup toolchain install nightly-x86_64-unknown-linux-gnu ; rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
||||||
|
- name: Install cxxbridge
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: cargo install cxxbridge-cmd
|
||||||
- name: Install python (macOS)
|
- name: Install python (macOS)
|
||||||
# Removing macOS things already installed in CI against failed linking
|
# Removing macOS things already installed in CI against failed linking
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
@ -255,10 +258,14 @@ jobs:
|
|||||||
- name: install cargo-make
|
- name: install cargo-make
|
||||||
run: cargo install --force cargo-make
|
run: cargo install --force cargo-make
|
||||||
- uses: ilammy/msvc-dev-cmd@v1
|
- uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
- name: install cxx bridge
|
||||||
|
run: cargo install cxxbridge-cmd
|
||||||
- name: Build fuzzers/frida_libpng
|
- name: Build fuzzers/frida_libpng
|
||||||
run: cd fuzzers/frida_libpng/ && cargo make test
|
run: cd fuzzers/frida_libpng/ && cargo make test
|
||||||
- name: Build fuzzers/frida_gdiplus
|
- name: Build fuzzers/frida_gdiplus
|
||||||
run: cd fuzzers/frida_gdiplus/ && cargo make test
|
run: cd fuzzers/frida_gdiplus/ && cargo make test
|
||||||
|
- name: Build fuzzers/tinyinst_simple
|
||||||
|
run: cd fuzzers/tinyinst_simple/ && cargo make test
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
runs-on: macOS-latest
|
runs-on: macOS-latest
|
||||||
@ -271,6 +278,8 @@ jobs:
|
|||||||
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: brew install z3 gtk+3
|
run: brew install z3 gtk+3
|
||||||
|
- name: Install cxxbridge
|
||||||
|
run: cargo install cxxbridge-cmd
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- name: MacOS Build
|
- name: MacOS Build
|
||||||
|
@ -6,8 +6,8 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { version = "0.8.1", path = "../../libafl", features = ["tui"] }
|
libafl = { version = "0.8.2", path = "../../libafl", features = ["introspection"] }
|
||||||
libafl_tinyinst = { version = "0.8.1", path = "../../libafl_tinyinst" }
|
libafl_tinyinst = { version = "0.8.2", path = "../../libafl_tinyinst" }
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
@ -1,8 +1,56 @@
|
|||||||
[tasks.build_test]
|
[tasks.unsupported]
|
||||||
command = "cl"
|
script_runner="@shell"
|
||||||
args = ["./test/test.c", "-o", "./test/test.exe"]
|
script='''
|
||||||
|
echo "Cargo-make not integrated yet on this"
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Harness
|
||||||
|
[tasks.harness]
|
||||||
|
linux_alias = "unsupported"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "harness_windows"
|
||||||
|
|
||||||
|
[tasks.harness_windows]
|
||||||
|
script='''
|
||||||
|
cl test\test.cpp -o test.exe
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Fuzzer
|
||||||
|
[tasks.fuzzer]
|
||||||
|
linux_alias = "unsupported"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "fuzzer_windows"
|
||||||
|
|
||||||
|
[tasks.fuzzer_windows]
|
||||||
|
dependencies = ["harness"]
|
||||||
|
command = "cargo"
|
||||||
|
args = ["build", "--release"]
|
||||||
|
|
||||||
|
# Run the fuzzer
|
||||||
[tasks.run]
|
[tasks.run]
|
||||||
dependencies = ["build_test"]
|
linux_alias = "unsupported"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "run_windows"
|
||||||
|
|
||||||
|
[tasks.run_windows]
|
||||||
|
dependencies = ["harness", "fuzzer"]
|
||||||
command = "cargo"
|
command = "cargo"
|
||||||
args = ["run", "--release"]
|
args = ["run", "--release"]
|
||||||
|
|
||||||
|
|
||||||
|
# Run the fuzzer
|
||||||
|
[tasks.test]
|
||||||
|
linux_alias = "unsupported"
|
||||||
|
mac_alias = "unsupported"
|
||||||
|
windows_alias = "test_windows"
|
||||||
|
|
||||||
|
[tasks.test_windows]
|
||||||
|
script_runner = "@shell"
|
||||||
|
script='''
|
||||||
|
copy .\target\release\tinyinst_simple.exe .
|
||||||
|
start "" "tinyinst_simple.exe"
|
||||||
|
#ping is for timeout
|
||||||
|
ping -n 10 127.0.0.1>NUL && taskkill /im tinyinst_simple.exe /F
|
||||||
|
>nul 2>nul dir /a-d "corpus_discovered\*" && (echo Files exist) || (exit /b 1337)
|
||||||
|
'''
|
||||||
|
dependencies = [ "harness", "fuzzer" ]
|
@ -1,3 +1,11 @@
|
|||||||
# Run Instruction
|
# Tinyinst example
|
||||||
|
This is a fuzzer example to show how libafl_tinyinst works
|
||||||
|
|
||||||
|
## How to build
|
||||||
|
1. Build the harness with `cl test\test.cpp -o test.exe`
|
||||||
|
2. Build the fuzzer with `cargo build --release`. The fuzzer is `target\release\tinyinst_simple.exe`
|
||||||
|
|
||||||
|
## Run with cargo-make
|
||||||
|
Or, you can simple run it using cargo-make
|
||||||
1. Open up developer powershell so that you have access to cl (Windows Default Compiler)
|
1. Open up developer powershell so that you have access to cl (Windows Default Compiler)
|
||||||
2. Run `cargo make run` to run the fuzzer
|
2. Run `cargo make run` to run the fuzzer
|
@ -1,8 +1,13 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
use libafl::bolts::shmem::UnixShMemProvider;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use libafl::bolts::shmem::Win32ShMemProvider;
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::{
|
bolts::{
|
||||||
rands::{RandomSeed, StdRand},
|
rands::{RandomSeed, StdRand},
|
||||||
|
shmem::ShMemProvider,
|
||||||
tuples::tuple_list,
|
tuples::tuple_list,
|
||||||
},
|
},
|
||||||
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus, Testcase},
|
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus, Testcase},
|
||||||
@ -17,17 +22,30 @@ use libafl::{
|
|||||||
state::StdState,
|
state::StdState,
|
||||||
Fuzzer, StdFuzzer,
|
Fuzzer, StdFuzzer,
|
||||||
};
|
};
|
||||||
use libafl_tinyinst::executor::TinyInstExecutor;
|
use libafl_tinyinst::executor::TinyInstExecutorBuilder;
|
||||||
static mut COVERAGE: Vec<u64> = vec![];
|
static mut COVERAGE: Vec<u64> = vec![];
|
||||||
|
|
||||||
|
#[cfg(not(any(target_vendor = "apple", windows)))]
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
#[cfg(any(target_vendor = "apple", windows))]
|
||||||
fn main() {
|
fn main() {
|
||||||
// Tinyinst things
|
// Tinyinst things
|
||||||
let tinyinst_args = vec!["-instrument_module".to_string(), "test.exe".to_string()];
|
let tinyinst_args = vec!["-instrument_module".to_string(), "test.exe".to_string()];
|
||||||
|
|
||||||
let args = vec![".\\test\\test.exe".to_string(), "@@".to_string()];
|
// use shmem to pass testcases
|
||||||
|
let args = vec!["test.exe".to_string(), "-m".to_string(), "@@".to_string()];
|
||||||
|
|
||||||
|
// use file to pass testcases
|
||||||
|
// let args = vec!["test.exe".to_string(), "-f".to_string(), "@@".to_string()];
|
||||||
|
|
||||||
let observer = unsafe { ListObserver::new("cov", &mut COVERAGE) };
|
let observer = unsafe { ListObserver::new("cov", &mut COVERAGE) };
|
||||||
let mut feedback = ListFeedback::with_observer(&observer);
|
let mut feedback = ListFeedback::with_observer(&observer);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let mut shmem_provider = Win32ShMemProvider::new().unwrap();
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
let mut shmem_provider = UnixShMemProvider::new().unwrap();
|
||||||
|
|
||||||
let input = BytesInput::new(b"bad".to_vec());
|
let input = BytesInput::new(b"bad".to_vec());
|
||||||
let rand = StdRand::new();
|
let rand = StdRand::new();
|
||||||
@ -46,13 +64,15 @@ fn main() {
|
|||||||
|
|
||||||
let mut mgr = SimpleEventManager::new(monitor);
|
let mut mgr = SimpleEventManager::new(monitor);
|
||||||
let mut executor = unsafe {
|
let mut executor = unsafe {
|
||||||
TinyInstExecutor::new(
|
TinyInstExecutorBuilder::new()
|
||||||
&mut COVERAGE,
|
.tinyinst_args(tinyinst_args)
|
||||||
tinyinst_args,
|
.program_args(args)
|
||||||
args,
|
.use_shmem()
|
||||||
5000,
|
.persistent("test.exe".to_string(), "fuzz".to_string(), 1, 10000)
|
||||||
tuple_list!(observer),
|
.timeout(std::time::Duration::new(5, 0))
|
||||||
)
|
.shmem_provider(&mut shmem_provider)
|
||||||
|
.build(&mut COVERAGE, tuple_list!(observer))
|
||||||
|
.unwrap()
|
||||||
};
|
};
|
||||||
let mutator = StdScheduledMutator::new(havoc_mutations());
|
let mutator = StdScheduledMutator::new(havoc_mutations());
|
||||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void pass1(char *buf, int buf_size) {
|
|
||||||
char target[0x10];
|
|
||||||
if (buf[0] == 'b') {
|
|
||||||
if (buf[1] == 'a') {
|
|
||||||
if (buf[2] == 'd') {
|
|
||||||
if (buf[3] == '1') {
|
|
||||||
if (buf[4] == '2') {
|
|
||||||
printf("You got me\n");
|
|
||||||
memcpy(target, buf, 0x1000000);
|
|
||||||
printf("GG\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
FILE *fp;
|
|
||||||
char buf[0x1000];
|
|
||||||
if (argc == 2) {
|
|
||||||
fp = fopen(argv[1], "r");
|
|
||||||
if (fp == NULL) {
|
|
||||||
printf("File not found\n");
|
|
||||||
printf("Received filename %s\n", argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
fscanf(fp, "%s", buf);
|
|
||||||
|
|
||||||
pass1(buf, sizeof(buf));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
printf("there is nothing\n");
|
|
||||||
}
|
|
||||||
}
|
|
163
fuzzers/tinyinst_simple/test/test.cpp
Normal file
163
fuzzers/tinyinst_simple/test/test.cpp
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Google LLC
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
// shared memory stuff
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_SAMPLE_SIZE 1000000
|
||||||
|
#define SHM_SIZE (4 + MAX_SAMPLE_SIZE)
|
||||||
|
unsigned char *shm_data;
|
||||||
|
|
||||||
|
bool use_shared_memory;
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
|
||||||
|
|
||||||
|
int setup_shmem(const char *name) {
|
||||||
|
HANDLE map_file;
|
||||||
|
|
||||||
|
map_file = OpenFileMapping(FILE_MAP_ALL_ACCESS, // read/write access
|
||||||
|
FALSE, // do not inherit the name
|
||||||
|
name); // name of mapping object
|
||||||
|
|
||||||
|
if (map_file == NULL) {
|
||||||
|
printf("Error accessing shared memory\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
shm_data = (unsigned char *)MapViewOfFile(
|
||||||
|
map_file, // handle to map object
|
||||||
|
FILE_MAP_ALL_ACCESS, // read/write permission
|
||||||
|
0, 0, SHM_SIZE);
|
||||||
|
|
||||||
|
if (shm_data == NULL) {
|
||||||
|
printf("Error accessing shared memory\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int setup_shmem(const char *name) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
// get shared memory file descriptor (NOT a file)
|
||||||
|
fd = shm_open(name, O_RDONLY, S_IRUSR | S_IWUSR);
|
||||||
|
if (fd == -1) {
|
||||||
|
printf("Error in shm_open\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// map shared memory to process address space
|
||||||
|
shm_data =
|
||||||
|
(unsigned char *)mmap(NULL, SHM_SIZE, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
if (shm_data == MAP_FAILED) {
|
||||||
|
printf("Error in mmap\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// used to force a crash
|
||||||
|
char *crash = NULL;
|
||||||
|
|
||||||
|
// ensure we can find the target
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
|
||||||
|
#define FUZZ_TARGET_MODIFIERS __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define FUZZ_TARGET_MODIFIERS __attribute__((noinline))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// actual target function
|
||||||
|
|
||||||
|
void FUZZ_TARGET_MODIFIERS fuzz(char *name) {
|
||||||
|
char *sample_bytes = NULL;
|
||||||
|
uint32_t sample_size = 0;
|
||||||
|
|
||||||
|
// read the sample either from file or
|
||||||
|
// shared memory
|
||||||
|
if (use_shared_memory) {
|
||||||
|
sample_size = *(uint32_t *)(shm_data);
|
||||||
|
if (sample_size > MAX_SAMPLE_SIZE) sample_size = MAX_SAMPLE_SIZE;
|
||||||
|
sample_bytes = (char *)malloc(sample_size);
|
||||||
|
memcpy(sample_bytes, shm_data + sizeof(uint32_t), sample_size);
|
||||||
|
} else {
|
||||||
|
FILE *fp = fopen(name, "rb");
|
||||||
|
if (!fp) {
|
||||||
|
printf("Error opening %s a\n", name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
sample_size = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
sample_bytes = (char *)malloc(sample_size);
|
||||||
|
fread(sample_bytes, 1, sample_size, fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
// printf("sample_bytes: %s", sample_bytes);
|
||||||
|
if (sample_size >= 4) {
|
||||||
|
// check if the sample spells "test"
|
||||||
|
if (*(uint32_t *)(sample_bytes) == 0x74736574) {
|
||||||
|
// if so, crash
|
||||||
|
crash[0] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sample_bytes) free(sample_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("Usage: %s <-f|-m> <file or shared memory name>\n", argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strcmp(argv[1], "-m")) {
|
||||||
|
use_shared_memory = true;
|
||||||
|
} else if (!strcmp(argv[1], "-f")) {
|
||||||
|
use_shared_memory = false;
|
||||||
|
} else {
|
||||||
|
printf("Usage: %s <-f|-m> <file or shared memory name>\n", argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// map shared memory here as we don't want to do it
|
||||||
|
// for every operation
|
||||||
|
if (use_shared_memory) {
|
||||||
|
if (!setup_shmem(argv[2])) { printf("Error mapping shared memory\n"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzz(argv[2]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -254,7 +254,7 @@ where
|
|||||||
phantom: _,
|
phantom: _,
|
||||||
} => {
|
} => {
|
||||||
// TODO: The monitor buffer should be added on client add.
|
// TODO: The monitor buffer should be added on client add.
|
||||||
let client = &mut monitor.client_stats_mut()[0];
|
let client = monitor.client_stats_mut_for(0);
|
||||||
client.update_executions(*executions as u64, *time);
|
client.update_executions(*executions as u64, *time);
|
||||||
client.update_introspection_monitor((**introspection_monitor).clone());
|
client.update_introspection_monitor((**introspection_monitor).clone());
|
||||||
monitor.display(event.name().to_string(), 0);
|
monitor.display(event.name().to_string(), 0);
|
||||||
|
@ -537,7 +537,7 @@ where
|
|||||||
.field("target", &self.target)
|
.field("target", &self.target)
|
||||||
.field("args", &self.args)
|
.field("args", &self.args)
|
||||||
.field("input_file", &self.input_file)
|
.field("input_file", &self.input_file)
|
||||||
.field("use_shmem_testcase", &self.uses_shmem_testcase)
|
.field("uses_shmem_testcase", &self.uses_shmem_testcase)
|
||||||
.field("forkserver", &self.forkserver)
|
.field("forkserver", &self.forkserver)
|
||||||
.field("observers", &self.observers)
|
.field("observers", &self.observers)
|
||||||
.field("map", &self.map)
|
.field("map", &self.map)
|
||||||
|
@ -17,7 +17,7 @@ libafl = { path = "../libafl", version = "0.8.0", features = [
|
|||||||
"std",
|
"std",
|
||||||
"libafl_derive",
|
"libafl_derive",
|
||||||
] }
|
] }
|
||||||
tinyinst-rs = { git = "https://github.com/elbiazo/tinyinst-rs" }
|
tinyinst = { git = "https://github.com/AFLplusplus/tinyinst-rs" }
|
||||||
# tinyinst-rs = { path = "../../tinyinst-rs" }
|
# tinyinst-rs = { path = "../../tinyinst-rs" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
# Requirements
|
# Requirements
|
||||||
- you need `Visual Studio 17 2022`, though it's not tested, it should work on older versions.
|
- `Visual Studio 17 2022`. It's not tested, it *should* work on older versions too.
|
||||||
- you need `cxxbridge-cmd` to generate bridge files between Rust and c++, you can install this via `cargo install cxxbridge-cmd`
|
- `cxxbridge-cmd` to generate bridge files between Rust and c++, you can install this with `cargo install cxxbridge-cmd`.
|
||||||
|
- `cmake` is needed to build tinyinst.
|
@ -1,27 +1,38 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::fs::{InputFile, INPUTFILE_STD},
|
bolts::{
|
||||||
|
fs::{InputFile, INPUTFILE_STD},
|
||||||
|
shmem::{ShMem, ShMemProvider, StdShMemProvider},
|
||||||
|
AsMutSlice, AsSlice,
|
||||||
|
},
|
||||||
executors::{Executor, ExitKind, HasObservers},
|
executors::{Executor, ExitKind, HasObservers},
|
||||||
inputs::{HasTargetBytes, UsesInput},
|
inputs::{HasTargetBytes, UsesInput},
|
||||||
observers::{ObserversTuple, UsesObservers},
|
observers::{ObserversTuple, UsesObservers},
|
||||||
prelude::AsSlice,
|
|
||||||
state::{State, UsesState},
|
state::{State, UsesState},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
use tinyinst_rs::tinyinst::{litecov::RunResult, TinyInst};
|
use tinyinst::tinyinst::{litecov::RunResult, TinyInst};
|
||||||
|
|
||||||
pub struct TinyInstExecutor<'a, S, OT> {
|
/// Tinyinst executor
|
||||||
|
pub struct TinyInstExecutor<'a, S, SP, OT>
|
||||||
|
where
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
tinyinst: TinyInst,
|
tinyinst: TinyInst,
|
||||||
coverage: &'a mut Vec<u64>,
|
coverage: &'a mut Vec<u64>,
|
||||||
timeout: u32,
|
timeout: Duration,
|
||||||
observers: OT,
|
observers: OT,
|
||||||
phantom: PhantomData<S>,
|
phantom: PhantomData<S>,
|
||||||
cur_input: InputFile,
|
cur_input: InputFile,
|
||||||
use_stdin: bool,
|
map: Option<<SP as ShMemProvider>::ShMem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S, OT> std::fmt::Debug for TinyInstExecutor<'a, S, OT> {
|
impl<'a, S, SP, OT> std::fmt::Debug for TinyInstExecutor<'a, S, SP, OT>
|
||||||
|
where
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("TinyInstExecutor")
|
f.debug_struct("TinyInstExecutor")
|
||||||
.field("timeout", &self.timeout)
|
.field("timeout", &self.timeout)
|
||||||
@ -29,11 +40,12 @@ impl<'a, S, OT> std::fmt::Debug for TinyInstExecutor<'a, S, OT> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, EM, S, Z, OT> Executor<EM, Z> for TinyInstExecutor<'a, S, OT>
|
impl<'a, EM, S, SP, OT, Z> Executor<EM, Z> for TinyInstExecutor<'a, S, SP, OT>
|
||||||
where
|
where
|
||||||
EM: UsesState<State = S>,
|
EM: UsesState<State = S>,
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
S::Input: HasTargetBytes,
|
S::Input: HasTargetBytes,
|
||||||
|
SP: ShMemProvider,
|
||||||
Z: UsesState<State = S>,
|
Z: UsesState<State = S>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -44,9 +56,23 @@ where
|
|||||||
_mgr: &mut EM,
|
_mgr: &mut EM,
|
||||||
input: &Self::Input,
|
input: &Self::Input,
|
||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
if !self.use_stdin {
|
match &self.map {
|
||||||
|
Some(_) => {
|
||||||
|
// use shmem to pass testcase
|
||||||
|
let shmem = unsafe { self.map.as_mut().unwrap_unchecked() };
|
||||||
|
let target_bytes = input.target_bytes();
|
||||||
|
let size = target_bytes.as_slice().len();
|
||||||
|
let size_in_bytes = size.to_ne_bytes();
|
||||||
|
// The first four bytes tells the size of the shmem.
|
||||||
|
shmem.as_mut_slice()[..SHMEM_FUZZ_HDR_SIZE]
|
||||||
|
.copy_from_slice(&size_in_bytes[..SHMEM_FUZZ_HDR_SIZE]);
|
||||||
|
shmem.as_mut_slice()[SHMEM_FUZZ_HDR_SIZE..(SHMEM_FUZZ_HDR_SIZE + size)]
|
||||||
|
.copy_from_slice(target_bytes.as_slice());
|
||||||
|
}
|
||||||
|
None => {
|
||||||
self.cur_input.write_buf(input.target_bytes().as_slice())?;
|
self.cur_input.write_buf(input.target_bytes().as_slice())?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused_assignments)]
|
#[allow(unused_assignments)]
|
||||||
let mut status = RunResult::OK;
|
let mut status = RunResult::OK;
|
||||||
@ -66,53 +92,211 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S, OT> TinyInstExecutor<'a, S, OT>
|
/// Builder for `TinyInstExecutor`
|
||||||
where
|
#[derive(Debug)]
|
||||||
OT: ObserversTuple<S>,
|
pub struct TinyInstExecutorBuilder<'a, SP> {
|
||||||
S: UsesInput,
|
|
||||||
{
|
|
||||||
/// # Safety
|
|
||||||
pub unsafe fn new(
|
|
||||||
coverage: &'a mut Vec<u64>,
|
|
||||||
tinyinst_args: Vec<String>,
|
tinyinst_args: Vec<String>,
|
||||||
program_args: Vec<String>,
|
program_args: Vec<String>,
|
||||||
timeout: u32,
|
timeout: Duration,
|
||||||
observers: OT,
|
shmem_provider: Option<&'a mut SP>,
|
||||||
) -> Self {
|
}
|
||||||
let mut use_stdin = true;
|
|
||||||
|
|
||||||
let program_args = program_args
|
const MAX_FILE: usize = 1024 * 1024;
|
||||||
|
const SHMEM_FUZZ_HDR_SIZE: usize = 4;
|
||||||
|
|
||||||
|
impl<'a> Default for TinyInstExecutorBuilder<'a, StdShMemProvider> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TinyInstExecutorBuilder<'a, StdShMemProvider> {
|
||||||
|
/// Constructor
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> TinyInstExecutorBuilder<'a, StdShMemProvider> {
|
||||||
|
Self {
|
||||||
|
tinyinst_args: vec![],
|
||||||
|
program_args: vec![],
|
||||||
|
timeout: Duration::new(3, 0),
|
||||||
|
shmem_provider: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Argument for tinyinst instrumentation
|
||||||
|
#[must_use]
|
||||||
|
pub fn tinyinst_arg(mut self, arg: String) -> Self {
|
||||||
|
self.tinyinst_args.push(arg);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Arguments for tinyinst instrumentation
|
||||||
|
#[must_use]
|
||||||
|
pub fn tinyinst_args(mut self, args: Vec<String>) -> Self {
|
||||||
|
for arg in args {
|
||||||
|
self.tinyinst_args.push(arg);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The module to instrument.
|
||||||
|
#[must_use]
|
||||||
|
pub fn instrument_module(mut self, module: Vec<String>) -> Self {
|
||||||
|
for modname in module {
|
||||||
|
self.tinyinst_args.push("-instrument_module".to_string());
|
||||||
|
self.tinyinst_args.push(modname);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use shmem
|
||||||
|
#[must_use]
|
||||||
|
pub fn use_shmem(mut self) -> Self {
|
||||||
|
self.tinyinst_args.push("-delivery".to_string());
|
||||||
|
self.tinyinst_args.push("shmem".to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Persistent mode
|
||||||
|
#[must_use]
|
||||||
|
pub fn persistent(
|
||||||
|
mut self,
|
||||||
|
target_module: String,
|
||||||
|
target_method: String,
|
||||||
|
nargs: usize,
|
||||||
|
iterations: usize,
|
||||||
|
) -> Self {
|
||||||
|
self.tinyinst_args.push("-target_module".to_string());
|
||||||
|
self.tinyinst_args.push(target_module);
|
||||||
|
|
||||||
|
self.tinyinst_args.push("-target_method".to_string());
|
||||||
|
self.tinyinst_args.push(target_method);
|
||||||
|
|
||||||
|
self.tinyinst_args.push("-nargs".to_string());
|
||||||
|
self.tinyinst_args.push(nargs.to_string());
|
||||||
|
|
||||||
|
self.tinyinst_args.push("-iterations".to_string());
|
||||||
|
self.tinyinst_args.push(iterations.to_string());
|
||||||
|
|
||||||
|
self.tinyinst_args.push("-persist".to_string());
|
||||||
|
self.tinyinst_args.push("-loop".to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Program arg
|
||||||
|
#[must_use]
|
||||||
|
pub fn program_arg(mut self, arg: String) -> Self {
|
||||||
|
self.program_args.push(arg);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Program args
|
||||||
|
#[must_use]
|
||||||
|
pub fn program_args(mut self, args: Vec<String>) -> Self {
|
||||||
|
for arg in args {
|
||||||
|
self.program_args.push(arg);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set timeout
|
||||||
|
#[must_use]
|
||||||
|
pub fn timeout(mut self, timeout: Duration) -> Self {
|
||||||
|
self.timeout = timeout;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use this to enable shmem testcase passing.
|
||||||
|
#[must_use]
|
||||||
|
pub fn shmem_provider<SP: ShMemProvider>(
|
||||||
|
self,
|
||||||
|
shmem_provider: &'a mut SP,
|
||||||
|
) -> TinyInstExecutorBuilder<'a, SP> {
|
||||||
|
TinyInstExecutorBuilder {
|
||||||
|
tinyinst_args: self.tinyinst_args,
|
||||||
|
program_args: self.program_args,
|
||||||
|
timeout: self.timeout,
|
||||||
|
shmem_provider: Some(shmem_provider),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, SP> TinyInstExecutorBuilder<'a, SP>
|
||||||
|
where
|
||||||
|
SP: ShMemProvider,
|
||||||
|
{
|
||||||
|
/// Build tinyinst executor
|
||||||
|
pub fn build<OT, S>(
|
||||||
|
&mut self,
|
||||||
|
coverage: &'a mut Vec<u64>,
|
||||||
|
observers: OT,
|
||||||
|
) -> Result<TinyInstExecutor<'a, S, SP, OT>, Error> {
|
||||||
|
let (map, shmem_id) = match &mut self.shmem_provider {
|
||||||
|
Some(provider) => {
|
||||||
|
// setup shared memory
|
||||||
|
let mut shmem = provider.new_shmem(MAX_FILE + SHMEM_FUZZ_HDR_SIZE)?;
|
||||||
|
let shmem_id = shmem.id();
|
||||||
|
// println!("{:#?}", shmem.id());
|
||||||
|
// shmem.write_to_env("__TINY_SHM_FUZZ_ID")?;
|
||||||
|
|
||||||
|
let size_in_bytes = (MAX_FILE + SHMEM_FUZZ_HDR_SIZE).to_ne_bytes();
|
||||||
|
shmem.as_mut_slice()[..4].clone_from_slice(&size_in_bytes[..4]);
|
||||||
|
|
||||||
|
(Some(shmem), Some(shmem_id))
|
||||||
|
}
|
||||||
|
None => (None, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut has_input = false;
|
||||||
|
let program_args: Vec<String> = self
|
||||||
|
.program_args
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|arg| {
|
.map(|arg| {
|
||||||
if arg == "@@" {
|
if arg == "@@" {
|
||||||
println!("Not using stdin");
|
has_input = true;
|
||||||
use_stdin = false;
|
match shmem_id {
|
||||||
INPUTFILE_STD.to_string()
|
Some(shmem_name) => shmem_name.to_string(),
|
||||||
|
None => INPUTFILE_STD.to_string(),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
arg
|
arg
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let cur_input = InputFile::create(INPUTFILE_STD).expect("Unable to create cur_file");
|
if !has_input {
|
||||||
println!("post init");
|
return Err(Error::unknown(
|
||||||
let tinyinst = TinyInst::new(tinyinst_args, program_args, timeout);
|
"No input file or shmem provided".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
println!("tinyinst args: {:#?}", &self.tinyinst_args);
|
||||||
|
|
||||||
Self {
|
let cur_input = InputFile::create(INPUTFILE_STD).expect("Unable to create cur_file");
|
||||||
|
|
||||||
|
let tinyinst = unsafe {
|
||||||
|
TinyInst::new(
|
||||||
|
&self.tinyinst_args,
|
||||||
|
&program_args,
|
||||||
|
self.timeout.as_millis() as u32,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(TinyInstExecutor {
|
||||||
tinyinst,
|
tinyinst,
|
||||||
coverage,
|
coverage,
|
||||||
timeout,
|
timeout: self.timeout,
|
||||||
observers,
|
observers,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
cur_input,
|
cur_input,
|
||||||
use_stdin,
|
map,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S, OT> HasObservers for TinyInstExecutor<'a, S, OT>
|
impl<'a, S, SP, OT> HasObservers for TinyInstExecutor<'a, S, SP, OT>
|
||||||
where
|
where
|
||||||
S: State,
|
S: State,
|
||||||
|
SP: ShMemProvider,
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
{
|
{
|
||||||
fn observers(&self) -> &OT {
|
fn observers(&self) -> &OT {
|
||||||
@ -123,16 +307,18 @@ where
|
|||||||
&mut self.observers
|
&mut self.observers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, S, OT> UsesState for TinyInstExecutor<'a, S, OT>
|
impl<'a, S, SP, OT> UsesState for TinyInstExecutor<'a, S, SP, OT>
|
||||||
where
|
where
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
|
SP: ShMemProvider,
|
||||||
{
|
{
|
||||||
type State = S;
|
type State = S;
|
||||||
}
|
}
|
||||||
impl<'a, S, OT> UsesObservers for TinyInstExecutor<'a, S, OT>
|
impl<'a, S, SP, OT> UsesObservers for TinyInstExecutor<'a, S, SP, OT>
|
||||||
where
|
where
|
||||||
OT: ObserversTuple<S>,
|
OT: ObserversTuple<S>,
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
|
SP: ShMemProvider,
|
||||||
{
|
{
|
||||||
type Observers = OT;
|
type Observers = OT;
|
||||||
}
|
}
|
||||||
|
@ -1 +1,69 @@
|
|||||||
|
/*!
|
||||||
|
The tinyinst module for `LibAFL`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#![warn(clippy::cargo)]
|
||||||
|
#![deny(clippy::cargo_common_metadata)]
|
||||||
|
#![deny(rustdoc::broken_intra_doc_links)]
|
||||||
|
#![deny(clippy::all)]
|
||||||
|
#![deny(clippy::pedantic)]
|
||||||
|
#![allow(
|
||||||
|
clippy::unreadable_literal,
|
||||||
|
clippy::type_repetition_in_bounds,
|
||||||
|
clippy::missing_errors_doc,
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::used_underscore_binding,
|
||||||
|
clippy::ptr_as_ptr,
|
||||||
|
clippy::missing_panics_doc,
|
||||||
|
clippy::missing_docs_in_private_items,
|
||||||
|
clippy::module_name_repetitions,
|
||||||
|
clippy::unreadable_literal
|
||||||
|
)]
|
||||||
|
#![cfg_attr(not(test), warn(
|
||||||
|
missing_debug_implementations,
|
||||||
|
missing_docs,
|
||||||
|
//trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
unused_extern_crates,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_qualifications,
|
||||||
|
//unused_results
|
||||||
|
))]
|
||||||
|
#![cfg_attr(test, deny(
|
||||||
|
missing_debug_implementations,
|
||||||
|
missing_docs,
|
||||||
|
//trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
unused_extern_crates,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_qualifications,
|
||||||
|
unused_must_use,
|
||||||
|
missing_docs,
|
||||||
|
//unused_results
|
||||||
|
))]
|
||||||
|
#![cfg_attr(
|
||||||
|
test,
|
||||||
|
deny(
|
||||||
|
bad_style,
|
||||||
|
dead_code,
|
||||||
|
improper_ctypes,
|
||||||
|
non_shorthand_field_patterns,
|
||||||
|
no_mangle_generic_items,
|
||||||
|
overflowing_literals,
|
||||||
|
path_statements,
|
||||||
|
patterns_in_fns_without_body,
|
||||||
|
private_in_public,
|
||||||
|
unconditional_recursion,
|
||||||
|
unused,
|
||||||
|
unused_allocation,
|
||||||
|
unused_comparisons,
|
||||||
|
unused_parens,
|
||||||
|
while_true
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
// Till they fix this buggy lint in clippy
|
||||||
|
#![allow(clippy::borrow_as_ptr)]
|
||||||
|
#![allow(clippy::borrow_deref_ref)]
|
||||||
|
|
||||||
|
/// Tinyinst executor
|
||||||
pub mod executor;
|
pub mod executor;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user