Merge pull request #7 from AFLplusplus/vh

first push
This commit is contained in:
Dominik Maier 2020-12-20 21:52:13 +01:00 committed by GitHub
commit 8ff3e8b7cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 225 additions and 24 deletions

View File

@ -149,6 +149,12 @@ where
I: Input, I: Input,
R: Rand, R: Rand,
{ {
/// Returns the number of elements
#[inline]
fn count(&self) -> usize {
self.entries().len()
}
/// Gets the next entry /// Gets the next entry
#[inline] #[inline]
fn next(&mut self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), AflError> { fn next(&mut self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), AflError> {

View File

@ -3,18 +3,24 @@
use core::fmt::Debug; use core::fmt::Debug;
use core::marker::PhantomData; use core::marker::PhantomData;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{
fs,
path::{Path, PathBuf},
};
use crate::corpus::{Corpus, Testcase}; use crate::corpus::{Corpus, Testcase};
use crate::events::EventManager; use crate::events::EventManager;
use crate::executors::{Executor, ExecutorsTuple, HasObservers}; use crate::executors::{Executor, ExecutorsTuple, HasObservers};
use crate::feedbacks::FeedbacksTuple; use crate::feedbacks::FeedbacksTuple;
use crate::generators::Generator; use crate::generators::Generator;
use crate::inputs::bytes::BytesInput;
use crate::inputs::Input; use crate::inputs::Input;
use crate::observers::ObserversTuple; use crate::observers::ObserversTuple;
use crate::serde_anymap::{SerdeAny, SerdeAnyMap}; use crate::serde_anymap::{SerdeAny, SerdeAnyMap};
use crate::stages::StagesTuple; use crate::stages::StagesTuple;
use crate::tuples::{tuple_list, tuple_list_type}; use crate::tuples::{tuple_list, tuple_list_type};
use crate::utils::{current_milliseconds, Rand}; use crate::utils::{current_milliseconds, Rand};
use crate::AflError; use crate::AflError;
pub trait StateMetadata: Debug { pub trait StateMetadata: Debug {
@ -44,6 +50,81 @@ where
phantom: PhantomData<(I, R, OT)>, phantom: PhantomData<(I, R, OT)>,
} }
impl<R, FT, OT> State<BytesInput, R, FT, OT>
where
R: Rand,
FT: FeedbacksTuple<BytesInput>,
OT: ObserversTuple,
{
pub fn load_from_directory<G, C, E, ET, EM>(
&mut self,
corpus: &mut C,
generator: &mut G,
engine: &mut Engine<E, OT, ET, BytesInput>,
manager: &mut EM,
in_dir: &Path,
) -> Result<(), AflError>
where
G: Generator<BytesInput, R>,
C: Corpus<BytesInput, R>,
E: Executor<BytesInput> + HasObservers<OT>,
ET: ExecutorsTuple<BytesInput>,
EM: EventManager<C, E, OT, FT, BytesInput, R>,
{
for entry in fs::read_dir(in_dir)? {
let entry = entry?;
let path = entry.path();
let attributes = fs::metadata(&path);
if !attributes.is_ok() {
continue;
}
let attr = attributes?;
if attr.is_file() && attr.len() > 0 {
println!("Loading file {:?} ...", &path);
let bytes = std::fs::read(&path)?;
let input = BytesInput::new(bytes);
let fitness = self.evaluate_input(&input, engine.executor_mut())?;
if self.add_if_interesting(corpus, input, fitness)?.is_none() {
println!("File {:?} was not interesting, skipped.", &path);
}
} else if attr.is_dir() {
self.load_from_directory(corpus, generator, engine, manager, &path)?;
}
}
Ok(())
}
pub fn load_initial_inputs<G, C, E, ET, EM>(
&mut self,
corpus: &mut C,
generator: &mut G,
engine: &mut Engine<E, OT, ET, BytesInput>,
manager: &mut EM,
in_dirs: &[PathBuf],
) -> Result<(), AflError>
where
G: Generator<BytesInput, R>,
C: Corpus<BytesInput, R>,
E: Executor<BytesInput> + HasObservers<OT>,
ET: ExecutorsTuple<BytesInput>,
EM: EventManager<C, E, OT, FT, BytesInput, R>,
{
for in_dir in in_dirs {
self.load_from_directory(corpus, generator, engine, manager, in_dir)?;
}
manager.log(
0,
format!("Loaded {} initial testcases.", corpus.count()), // get corpus count
)?;
manager.process(self, corpus)?;
Ok(())
}
}
impl<I, R, FT, OT> State<I, R, FT, OT> impl<I, R, FT, OT> State<I, R, FT, OT>
where where
I: Input, I: Input,

View File

@ -742,7 +742,7 @@ where
/// Else, it will act as client. /// Else, it will act as client.
pub fn new_on_port_std(stats: ST) -> Result<Self, AflError> { pub fn new_on_port_std(stats: ST) -> Result<Self, AflError> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpConnection::on_port(port)?, llmp: llmp::LlmpConnection::on_port(1337)?,
stats: stats, stats: stats,
phantom: PhantomData, phantom: PhantomData,
}) })

View File

@ -17,6 +17,7 @@ opt-level = 3
debug = true debug = true
[dependencies] [dependencies]
clap = "2.32.0"
afl = { path = "../../afl/" } afl = { path = "../../afl/" }
[lib] [lib]

View File

@ -1,7 +1,12 @@
#include <stdio.h>
#include <stdint.h> #include <stdint.h>
#define MAP_SIZE 65536 #define MAP_SIZE 65536
int orig_argc;
char **orig_argv;
char **orig_envp;
uint8_t __lafl_dummy_map[MAP_SIZE]; uint8_t __lafl_dummy_map[MAP_SIZE];
uint8_t *__lafl_edges_map = __lafl_dummy_map; uint8_t *__lafl_edges_map = __lafl_dummy_map;
@ -119,15 +124,29 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
} }
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
static void afl_libfuzzer_copy_args(int argc, char** argv, char** envp) {
orig_argc = argc;
orig_argv = argv;
orig_envp = envp;
}
__attribute__((section(".init_array"))) void (* p_afl_libfuzzer_copy_args)(int,char*[],char*[]) = &afl_libfuzzer_copy_args;
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
void afl_libfuzzer_main(); void afl_libfuzzer_main();
int afl_libfuzzer_init() {
if (LLVMFuzzerInitialize)
return LLVMFuzzerInitialize(&orig_argc, &orig_argv);
else
return 0;
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (LLVMFuzzerInitialize)
LLVMFuzzerInitialize(&argc, &argv);
afl_libfuzzer_main(); afl_libfuzzer_main();
return 0; return 0;

View File

@ -1,7 +1,14 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate clap;
extern crate alloc; extern crate alloc;
use clap::{App, Arg};
use std::env;
use std::path::PathBuf;
use afl::corpus::Corpus;
use afl::corpus::InMemoryCorpus; use afl::corpus::InMemoryCorpus;
use afl::engines::Engine; use afl::engines::Engine;
use afl::engines::Fuzzer; use afl::engines::Fuzzer;
@ -24,6 +31,9 @@ extern "C" {
/// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) /// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32; 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_edges_map: *mut u8;
static __lafl_cmp_map: *mut u8; static __lafl_cmp_map: *mut u8;
static __lafl_max_edges_size: u32; static __lafl_max_edges_size: u32;
@ -40,14 +50,69 @@ const NAME_COV_MAP: &str = "cov_map";
#[no_mangle] #[no_mangle]
pub extern "C" fn afl_libfuzzer_main() { pub extern "C" fn afl_libfuzzer_main() {
let mut rand = StdRand::new(0); let matches = App::new("libAFLrs fuzzer harness")
.about("libAFLrs fuzzer harness help options.")
.arg(
Arg::with_name("port")
.short("p")
.value_name("PORT")
.takes_value(true)
.help("Broker TCP port to use."),
)
.arg(
Arg::with_name("dictionary")
.short("x")
.value_name("DICTIONARY")
.takes_value(true)
.multiple(true)
.help("Dictionary file to use, can be specified multiple times."),
)
.arg(
Arg::with_name("statstime")
.short("T")
.value_name("STATSTIME")
.takes_value(true)
.help("How often to print statistics in seconds [default: 5, disable: 0]"),
)
.arg(Arg::with_name("workdir")
.help("Where to write the corpus, also reads the data on start. If more than one is supplied the first will be the work directory, all others will just be initially read from.")
.multiple(true)
.value_name("WORKDIR")
)
.get_matches();
let statstime = value_t!(matches, "statstime", u32).unwrap_or(5);
let broker_port = value_t!(matches, "port", u16).unwrap_or(1337);
let workdir = if matches.is_present("workdir") {
matches.value_of("workdir").unwrap().to_string()
} else {
env::current_dir().unwrap().to_string_lossy().to_string()
};
let mut dictionary: Option<Vec<PathBuf>> = None;
if matches.is_present("dictionary") {
dictionary = Some(values_t!(matches, "dictionary", PathBuf).unwrap_or_else(|e| e.exit()));
}
let mut input: Option<Vec<PathBuf>> = None;
if matches.is_present("workdir") {
input = Some(values_t!(matches, "workdir", PathBuf).unwrap_or_else(|e| e.exit()));
}
if dictionary != None || input != None {
println!("Information: the first process started is the broker and only processes the \'-p PORT\' option if present.");
}
println!("Workdir: {:?}", workdir);
let mut rand = StdRand::new(0);
let mut corpus = InMemoryCorpus::new(); let mut corpus = InMemoryCorpus::new();
let mut generator = RandPrintablesGenerator::new(32); let mut generator = RandPrintablesGenerator::new(32);
let stats = SimpleStats::new(|s| println!("{}", s)); let stats = SimpleStats::new(|s| println!("{}", s));
let mut mgr = LlmpEventManager::new_on_port_std(broker_port, stats).unwrap();
let mut mgr = LlmpEventManager::new_on_port_std(1337, stats).unwrap();
if mgr.is_broker() { if mgr.is_broker() {
println!("Doing broker things. Run this tool again to start fuzzing in a client."); println!("Doing broker things. Run this tool again to start fuzzing in a client.");
mgr.broker_loop().unwrap(); mgr.broker_loop().unwrap();
@ -66,16 +131,35 @@ pub extern "C" fn afl_libfuzzer_main() {
let mut engine = Engine::new(executor); let mut engine = Engine::new(executor);
state // Call LLVMFUzzerInitialize() if present.
.generate_initial_inputs( unsafe {
&mut rand, if afl_libfuzzer_init() == -1 {
&mut corpus, println!("Warning: LLVMFuzzerInitialize failed with -1")
&mut generator, }
&mut engine, }
&mut mgr,
4, match input {
) Some(x) => state
.expect("Failed to load initial inputs"); .load_initial_inputs(&mut corpus, &mut generator, &mut engine, &mut mgr, &x)
.expect("Failed to load initial corpus"),
None => (),
}
if corpus.count() < 1 {
println!("Generating random inputs");
state
.generate_initial_inputs(
&mut rand,
&mut corpus,
&mut generator,
&mut engine,
&mut mgr,
4,
)
.expect("Failed to generate initial inputs");
}
println!("We have {} inputs.", corpus.count());
let mut mutator = HavocBytesMutator::new_default(); let mut mutator = HavocBytesMutator::new_default();
mutator.set_max_size(4096); mutator.set_max_size(4096);

View File

@ -1,11 +1,21 @@
#!/bin/sh #!/bin/sh
cargo build --release cargo build --release || exit 1
make -C runtime make -C runtime || exit 1
./compiler -flto=thin -c test/test.c -o test_fuzz.o rm -f test_fuzz.elf test_fuzz.o
./compiler -flto=thin -fuse-ld=lld test_fuzz.o -o test_fuzz.elf ./compiler -flto=thin -c test/test.c -o test_fuzz.o || exit 1
./compiler -flto=thin test_fuzz.o -o test_fuzz.elf || exit 1
RUST_BACKTRACE=1 ./test_fuzz.elf RUST_BACKTRACE=1 ./test_fuzz.elf &
test "$!" -gt 0 && {
usleep 250
RUST_BACKTRACE=1 ./test_fuzz.elf -x a -x b -T5 in1 in2 &
}
sleep 10
killall test_fuzz.elf
#rm ./test_fuzz.elf