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,
R: Rand,
{
/// Returns the number of elements
#[inline]
fn count(&self) -> usize {
self.entries().len()
}
/// Gets the next entry
#[inline]
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::marker::PhantomData;
use serde::{Deserialize, Serialize};
use std::{
fs,
path::{Path, PathBuf},
};
use crate::corpus::{Corpus, Testcase};
use crate::events::EventManager;
use crate::executors::{Executor, ExecutorsTuple, HasObservers};
use crate::feedbacks::FeedbacksTuple;
use crate::generators::Generator;
use crate::inputs::bytes::BytesInput;
use crate::inputs::Input;
use crate::observers::ObserversTuple;
use crate::serde_anymap::{SerdeAny, SerdeAnyMap};
use crate::stages::StagesTuple;
use crate::tuples::{tuple_list, tuple_list_type};
use crate::utils::{current_milliseconds, Rand};
use crate::AflError;
pub trait StateMetadata: Debug {
@ -44,6 +50,81 @@ where
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>
where
I: Input,

View File

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

View File

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

View File

@ -1,7 +1,12 @@
#include <stdio.h>
#include <stdint.h>
#define MAP_SIZE 65536
int orig_argc;
char **orig_argv;
char **orig_envp;
uint8_t __lafl_dummy_map[MAP_SIZE];
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();
int afl_libfuzzer_init() {
if (LLVMFuzzerInitialize)
return LLVMFuzzerInitialize(&orig_argc, &orig_argv);
else
return 0;
}
int main(int argc, char** argv) {
if (LLVMFuzzerInitialize)
LLVMFuzzerInitialize(&argc, &argv);
afl_libfuzzer_main();
return 0;

View File

@ -1,7 +1,14 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate clap;
extern crate alloc;
use clap::{App, Arg};
use std::env;
use std::path::PathBuf;
use afl::corpus::Corpus;
use afl::corpus::InMemoryCorpus;
use afl::engines::Engine;
use afl::engines::Fuzzer;
@ -24,6 +31,9 @@ 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;
@ -40,14 +50,69 @@ const NAME_COV_MAP: &str = "cov_map";
#[no_mangle]
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 generator = RandPrintablesGenerator::new(32);
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() {
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
mgr.broker_loop().unwrap();
@ -66,16 +131,35 @@ pub extern "C" fn afl_libfuzzer_main() {
let mut engine = Engine::new(executor);
state
.generate_initial_inputs(
&mut rand,
&mut corpus,
&mut generator,
&mut engine,
&mut mgr,
4,
)
.expect("Failed to load initial inputs");
// Call LLVMFUzzerInitialize() if present.
unsafe {
if afl_libfuzzer_init() == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1")
}
}
match input {
Some(x) => state
.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();
mutator.set_max_size(4096);

View File

@ -1,11 +1,21 @@
#!/bin/sh
cargo build --release
make -C runtime
cargo build --release || exit 1
make -C runtime || exit 1
./compiler -flto=thin -c test/test.c -o test_fuzz.o
./compiler -flto=thin -fuse-ld=lld test_fuzz.o -o test_fuzz.elf
rm -f test_fuzz.elf test_fuzz.o
./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