Use Structopt instead of yaml for example fuzzers, introduce Cores API (#420)
* reworked generic_inmemory to structopt * moved core parsing to a struct * added Cores * added structopt to libpng_ctx * improved libafl, added structopt to libpng launcher * fix deexit ub * move more to structopt * improve llvm-config detection * move construct_automata to structopt * clippy, fixes, ... * no_std * clippy * frida core parsing * fixed no-fork cores * updated clap * added missing import * missing borrow * reworked frida to structopt * fixed build * using Cores api for atheris Co-authored-by: Dominik Maier <d.maier@avm.de>
This commit is contained in:
parent
b4c2551544
commit
217a7dee1d
@ -17,4 +17,4 @@ opt-level = 3
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["default"] }
|
clap = { version = "3.0.0-rc.4", features = ["default"] }
|
@ -38,7 +38,7 @@ libc = "0.2"
|
|||||||
libloading = "0.7.0"
|
libloading = "0.7.0"
|
||||||
num-traits = "0.2.14"
|
num-traits = "0.2.14"
|
||||||
rangemap = "0.1.10"
|
rangemap = "0.1.10"
|
||||||
clap = "2.33"
|
structopt = "0.3.25"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
|
|
||||||
backtrace = "0.3"
|
backtrace = "0.3"
|
||||||
|
@ -47,34 +47,30 @@ fn main() {
|
|||||||
let zlib_path = Path::new(&zlib);
|
let zlib_path = Path::new(&zlib);
|
||||||
let zlib_tar = format!("{}/zlib-1.2.11.tar.gz", &cwd);
|
let zlib_tar = format!("{}/zlib-1.2.11.tar.gz", &cwd);
|
||||||
|
|
||||||
if !libpng_path.is_dir() {
|
if !libpng_path.is_dir() && !Path::new(&libpng_tar).is_file() {
|
||||||
if !Path::new(&libpng_tar).is_file() {
|
println!("cargo:warning=Libpng not found, downloading...");
|
||||||
println!("cargo:warning=Libpng not found, downloading...");
|
// Download libpng
|
||||||
// Download libpng
|
let mut resp = reqwest::blocking::get(LIBPNG_URL).expect("Libpng download failed");
|
||||||
let mut resp = reqwest::blocking::get(LIBPNG_URL).expect("Libpng download failed");
|
let mut out = File::create(&libpng_tar).expect("Libpng download failed");
|
||||||
let mut out = File::create(&libpng_tar).expect("Libpng download failed");
|
io::copy(&mut resp, &mut out).expect("Libpng downlaod failed");
|
||||||
io::copy(&mut resp, &mut out).expect("Libpng downlaod failed");
|
|
||||||
|
|
||||||
let tar_xz = File::open(&libpng_tar).expect("Libpng extraction failed");
|
let tar_xz = File::open(&libpng_tar).expect("Libpng extraction failed");
|
||||||
let tar = XzDecoder::new(tar_xz);
|
let tar = XzDecoder::new(tar_xz);
|
||||||
let mut archive = Archive::new(tar);
|
let mut archive = Archive::new(tar);
|
||||||
archive.unpack(&cwd).expect("Libpng extraction failed");
|
archive.unpack(&cwd).expect("Libpng extraction failed");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !zlib_path.is_dir() {
|
if !zlib_path.is_dir() && !Path::new(&zlib_tar).is_file() {
|
||||||
if !Path::new(&zlib_tar).is_file() {
|
println!("cargo:warning=Zlib not found, downloading...");
|
||||||
println!("cargo:warning=Zlib not found, downloading...");
|
// Download Zlib
|
||||||
// Download Zlib
|
let mut resp = reqwest::blocking::get(ZLIB_URL).expect("Zlib download failed");
|
||||||
let mut resp = reqwest::blocking::get(ZLIB_URL).expect("Zlib download failed");
|
let mut out = File::create(&zlib_tar).expect("Zlib download failed");
|
||||||
let mut out = File::create(&zlib_tar).expect("Zlib download failed");
|
io::copy(&mut resp, &mut out).expect("Zlib downlaod failed");
|
||||||
io::copy(&mut resp, &mut out).expect("Zlib downlaod failed");
|
|
||||||
|
|
||||||
let tar_gz = File::open(&zlib_tar).expect("Zlib extraction failed");
|
let tar_gz = File::open(&zlib_tar).expect("Zlib extraction failed");
|
||||||
let tar = GzDecoder::new(tar_gz);
|
let tar = GzDecoder::new(tar_gz);
|
||||||
let mut archive = Archive::new(tar);
|
let mut archive = Archive::new(tar);
|
||||||
archive.unpack(&cwd).expect("Zlib extraction failed");
|
archive.unpack(&cwd).expect("Zlib extraction failed");
|
||||||
rename(zlib_1_2_11, zlib).expect("Zlib extraction failed");
|
rename(zlib_1_2_11, zlib).expect("Zlib extraction failed");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("cargo:warning=Now compile libpng with either visual studio or msys2");
|
println!("cargo:warning=Now compile libpng with either visual studio or msys2");
|
||||||
@ -128,7 +124,7 @@ fn main() {
|
|||||||
.arg(&libpng_tar)
|
.arg(&libpng_tar)
|
||||||
.status()
|
.status()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Command::new(format!("{}/configure", &libpng))
|
Command::new("./configure")
|
||||||
.current_dir(&libpng_path)
|
.current_dir(&libpng_path)
|
||||||
.args(&[
|
.args(&[
|
||||||
"--disable-shared",
|
"--disable-shared",
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||||
//! The example harness is built for libpng.
|
//! The example harness is built for libpng.
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use frida_gum::Gum;
|
||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
net::SocketAddr,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
os::parse_core_bind_arg,
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -34,75 +41,126 @@ use libafl::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
use frida_gum::Gum;
|
#[cfg(unix)]
|
||||||
|
use libafl_frida::asan_errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS};
|
||||||
use std::{
|
|
||||||
env,
|
|
||||||
net::SocketAddr,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use libafl_frida::{
|
use libafl_frida::{
|
||||||
coverage_rt::MAP_SIZE,
|
coverage_rt::MAP_SIZE,
|
||||||
executor::FridaInProcessExecutor,
|
executor::FridaInProcessExecutor,
|
||||||
helper::{FridaHelper, FridaInstrumentationHelper},
|
helper::{FridaHelper, FridaInstrumentationHelper},
|
||||||
FridaOptions,
|
FridaOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
use libafl_frida::asan_errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS};
|
|
||||||
|
|
||||||
use libafl_targets::cmplog::{CmpLogObserver, CMPLOG_MAP};
|
use libafl_targets::cmplog::{CmpLogObserver, CMPLOG_MAP};
|
||||||
|
|
||||||
|
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||||
|
Ok(Duration::from_millis(time.parse()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
#[structopt(
|
||||||
|
name = "libafl_frida",
|
||||||
|
version = "0.1.0",
|
||||||
|
about = "A frida-based binary-only libfuzzer-style fuzzer for with llmp-multithreading support",
|
||||||
|
author = "s1341 <github@shmarya.net>,
|
||||||
|
Dongjia Zhang <toka@aflplus.plus>, Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
||||||
|
)]
|
||||||
|
struct Opt {
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str = Cores::from_cmdline),
|
||||||
|
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||||
|
name = "CORES"
|
||||||
|
)]
|
||||||
|
cores: Cores,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short = "p",
|
||||||
|
long,
|
||||||
|
help = "Choose the broker TCP port, default is 1337",
|
||||||
|
name = "PORT",
|
||||||
|
default_value = "1337"
|
||||||
|
)]
|
||||||
|
broker_port: u16,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short = "a",
|
||||||
|
long,
|
||||||
|
help = "Specify a remote broker",
|
||||||
|
name = "REMOTE"
|
||||||
|
)]
|
||||||
|
remote_broker_addr: Option<SocketAddr>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set an initial corpus directory",
|
||||||
|
name = "INPUT"
|
||||||
|
)]
|
||||||
|
input: Vec<PathBuf>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str),
|
||||||
|
help = "Set the output directory, default is ./out",
|
||||||
|
name = "OUTPUT",
|
||||||
|
default_value = "./out"
|
||||||
|
)]
|
||||||
|
output: PathBuf,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str = timeout_from_millis_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set the exeucution timeout in milliseconds, default is 1000",
|
||||||
|
name = "TIMEOUT",
|
||||||
|
default_value = "1000"
|
||||||
|
)]
|
||||||
|
timeout: Duration,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(from_os_str),
|
||||||
|
short = "x",
|
||||||
|
long,
|
||||||
|
help = "Feed the fuzzer with an user-specified list of tokens (often called \"dictionary\"",
|
||||||
|
name = "TOKENS",
|
||||||
|
multiple = true
|
||||||
|
)]
|
||||||
|
tokens: Vec<PathBuf>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
long,
|
||||||
|
help = "The configuration this fuzzer runs with, for multiprocessing",
|
||||||
|
name = "CONF",
|
||||||
|
default_value = "default launcher"
|
||||||
|
)]
|
||||||
|
configuration: String,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
long,
|
||||||
|
help = "The file to redirect stdout input to (/dev/null if unset)"
|
||||||
|
)]
|
||||||
|
stdout_file: Option<String>,
|
||||||
|
|
||||||
|
#[structopt(help = "The harness")]
|
||||||
|
harness: String,
|
||||||
|
|
||||||
|
#[structopt(help = "The symbol name to look up and hook")]
|
||||||
|
symbol: String,
|
||||||
|
|
||||||
|
#[structopt(help = "The modules to instrument, separated by colons")]
|
||||||
|
modules_to_instrument: String,
|
||||||
|
}
|
||||||
|
|
||||||
/// The main fn, usually parsing parameters, and starting the fuzzer
|
/// The main fn, usually parsing parameters, and starting the fuzzer
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
// Registry the metadata types used in this fuzzer
|
// Registry the metadata types used in this fuzzer
|
||||||
// Needed only on no_std
|
// Needed only on no_std
|
||||||
//RegistryBuilder::register::<Tokens>();
|
//RegistryBuilder::register::<Tokens>();
|
||||||
|
|
||||||
let matches = App::new("libafl_frida")
|
let opt = Opt::from_args();
|
||||||
.version("0.1.0")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("cores")
|
|
||||||
.short("c")
|
|
||||||
.long("cores")
|
|
||||||
.value_name("CORES")
|
|
||||||
.required(true)
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("harness").required(true).index(1))
|
|
||||||
.arg(Arg::with_name("symbol").required(true).index(2))
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("modules_to_instrument")
|
|
||||||
.required(true)
|
|
||||||
.index(3),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("configuration")
|
|
||||||
.required(false)
|
|
||||||
.value_name("CONF")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("output")
|
|
||||||
.short("o")
|
|
||||||
.long("output")
|
|
||||||
.value_name("OUTPUT")
|
|
||||||
.required(false)
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("b2baddr")
|
|
||||||
.short("B")
|
|
||||||
.long("b2baddr")
|
|
||||||
.value_name("B2BADDR")
|
|
||||||
.required(false)
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.get_matches();
|
|
||||||
|
|
||||||
let cores = parse_core_bind_arg(&matches.value_of("cores").unwrap().to_string()).unwrap();
|
|
||||||
|
|
||||||
color_backtrace::install();
|
color_backtrace::install();
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@ -110,30 +168,19 @@ pub fn main() {
|
|||||||
env::current_dir().unwrap().to_string_lossy().to_string()
|
env::current_dir().unwrap().to_string_lossy().to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
let broker_addr = matches
|
|
||||||
.value_of("b2baddr")
|
|
||||||
.map(|addrstr| addrstr.parse().unwrap());
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match fuzz(
|
match fuzz(
|
||||||
matches.value_of("harness").unwrap(),
|
&opt.harness,
|
||||||
matches.value_of("symbol").unwrap(),
|
&opt.symbol,
|
||||||
&matches
|
&opt.modules_to_instrument.split(':').collect::<Vec<_>>(),
|
||||||
.value_of("modules_to_instrument")
|
|
||||||
.unwrap()
|
|
||||||
.split(':')
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
//modules_to_instrument,
|
//modules_to_instrument,
|
||||||
&[PathBuf::from("./corpus")],
|
&opt.input,
|
||||||
&PathBuf::from("./crashes"),
|
&opt.output,
|
||||||
1337,
|
opt.broker_port,
|
||||||
&cores,
|
&opt.cores,
|
||||||
matches.value_of("output"),
|
opt.stdout_file.as_deref(),
|
||||||
broker_addr,
|
opt.remote_broker_addr,
|
||||||
matches
|
opt.configuration,
|
||||||
.value_of("configuration")
|
|
||||||
.unwrap_or("default launcher")
|
|
||||||
.to_string(),
|
|
||||||
) {
|
) {
|
||||||
Ok(()) | Err(Error::ShuttingDown) => println!("\nFinished fuzzing. Good bye."),
|
Ok(()) | Err(Error::ShuttingDown) => println!("\nFinished fuzzing. Good bye."),
|
||||||
Err(e) => panic!("Error during fuzzing: {:?}", e),
|
Err(e) => panic!("Error during fuzzing: {:?}", e),
|
||||||
@ -150,7 +197,7 @@ unsafe fn fuzz(
|
|||||||
corpus_dirs: &[PathBuf],
|
corpus_dirs: &[PathBuf],
|
||||||
objective_dir: &Path,
|
objective_dir: &Path,
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
cores: &[usize],
|
cores: &Cores,
|
||||||
stdout_file: Option<&str>,
|
stdout_file: Option<&str>,
|
||||||
broker_addr: Option<SocketAddr>,
|
broker_addr: Option<SocketAddr>,
|
||||||
configuration: String,
|
configuration: String,
|
||||||
|
@ -24,7 +24,7 @@ libafl = { path = "../../libafl/" }
|
|||||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["default"] }
|
clap = { version = "3.0.0-rc.4", features = ["default"] }
|
||||||
nix = "0.23.0"
|
nix = "0.23.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@ -24,7 +24,7 @@ libafl = { path = "../../libafl/" }
|
|||||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["default"] }
|
clap = { version = "3.0.0-rc.4", features = ["default"] }
|
||||||
nix = "0.23.0"
|
nix = "0.23.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@ -14,5 +14,5 @@ debug = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../libafl/" }
|
libafl = { path = "../../libafl/" }
|
||||||
libafl_qemu = { path = "../../libafl_qemu/" }
|
libafl_qemu = { path = "../../libafl_qemu/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["default"] }
|
clap = { version = "3.0.0-rc.4", features = ["default"] }
|
||||||
nix = "0.23.0"
|
nix = "0.23.0"
|
||||||
|
@ -24,7 +24,7 @@ libafl = { path = "../../libafl/" }
|
|||||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["default", "yaml"] }
|
structopt = "0.3.25"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "generic_inmemory"
|
name = "generic_inmemory"
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
name: generic_inmemory
|
|
||||||
author: "Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
|
||||||
args:
|
|
||||||
- cores:
|
|
||||||
long: cores
|
|
||||||
about: "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6."
|
|
||||||
value_name: CORES
|
|
||||||
required: true
|
|
||||||
takes_value: true
|
|
||||||
- broker_port:
|
|
||||||
long: broker_port
|
|
||||||
about: "Choose the broker TCP port, default is 1337"
|
|
||||||
value_name: PORT
|
|
||||||
takes_value: true
|
|
||||||
- remote_broker_addr:
|
|
||||||
long: remote_broker_addr
|
|
||||||
about: "Specify a remote broker"
|
|
||||||
value_name: REMOTE
|
|
||||||
takes_value: true
|
|
||||||
- input:
|
|
||||||
long: input
|
|
||||||
about: "Set an initial corpus directory"
|
|
||||||
value_name: INPUT
|
|
||||||
multiple: true
|
|
||||||
takes_value: true
|
|
||||||
- output:
|
|
||||||
long: output
|
|
||||||
about: "Set the output directory, default is CWD"
|
|
||||||
value_name: OUTPUT
|
|
||||||
takes_value: true
|
|
||||||
- timeout:
|
|
||||||
long: timeout
|
|
||||||
about: "Set the execution timeout in milliseconds, default 10000"
|
|
||||||
value_name: TIMEOUT
|
|
||||||
takes_value: true
|
|
||||||
- tokens:
|
|
||||||
long: tokens
|
|
||||||
short: x
|
|
||||||
about: "Feed the fuzzer with an user-specified list of tokens (often called \"dictionary\")"
|
|
||||||
value_name: DICT
|
|
||||||
multiple: true
|
|
||||||
takes_value: true
|
|
@ -1,15 +1,15 @@
|
|||||||
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||||
//! The `launcher` will spawn new processes for each cpu core.
|
//! The `launcher` will spawn new processes for each cpu core.
|
||||||
|
|
||||||
use clap::{load_yaml, App};
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use std::{env, path::PathBuf};
|
use std::{env, net::SocketAddr, path::PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
os::parse_core_bind_arg,
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -26,8 +26,10 @@ use libafl::{
|
|||||||
generators::RandBytesGenerator,
|
generators::RandBytesGenerator,
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
monitors::MultiMonitor,
|
monitors::MultiMonitor,
|
||||||
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
mutators::{
|
||||||
mutators::token_mutations::{I2SRandReplace, Tokens},
|
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
|
token_mutations::{I2SRandReplace, Tokens},
|
||||||
|
},
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
stages::{StdMutationalStage, TracingStage},
|
stages::{StdMutationalStage, TracingStage},
|
||||||
state::{HasCorpus, HasMetadata, StdState},
|
state::{HasCorpus, HasMetadata, StdState},
|
||||||
@ -39,6 +41,84 @@ use libafl_targets::{
|
|||||||
MAX_EDGES_NUM,
|
MAX_EDGES_NUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Parses a millseconds int into a [`Duration`], used for commandline arg parsing
|
||||||
|
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||||
|
Ok(Duration::from_millis(time.parse()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
#[structopt(
|
||||||
|
name = "generic_inmemory",
|
||||||
|
about = "A generic libfuzzer-like fuzzer with llmp-multithreading support",
|
||||||
|
author = "Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
||||||
|
)]
|
||||||
|
struct Opt {
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str = Cores::from_cmdline),
|
||||||
|
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||||
|
name = "CORES"
|
||||||
|
)]
|
||||||
|
cores: Cores,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short = "p",
|
||||||
|
long,
|
||||||
|
help = "Choose the broker TCP port, default is 1337",
|
||||||
|
name = "PORT"
|
||||||
|
)]
|
||||||
|
broker_port: u16,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short = "a",
|
||||||
|
long,
|
||||||
|
help = "Specify a remote broker",
|
||||||
|
name = "REMOTE"
|
||||||
|
)]
|
||||||
|
remote_broker_addr: Option<SocketAddr>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set an initial corpus directory",
|
||||||
|
name = "INPUT"
|
||||||
|
)]
|
||||||
|
input: Vec<PathBuf>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str),
|
||||||
|
help = "Set the output directory, default is ./out",
|
||||||
|
name = "OUTPUT",
|
||||||
|
default_value = "./out"
|
||||||
|
)]
|
||||||
|
output: PathBuf,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str = timeout_from_millis_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set the exeucution timeout in milliseconds, default is 1000",
|
||||||
|
name = "TIMEOUT",
|
||||||
|
default_value = "1000"
|
||||||
|
)]
|
||||||
|
timeout: Duration,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(from_os_str),
|
||||||
|
short = "x",
|
||||||
|
long,
|
||||||
|
help = "Feed the fuzzer with an user-specified list of tokens (often called \"dictionary\"",
|
||||||
|
name = "TOKENS",
|
||||||
|
multiple = true
|
||||||
|
)]
|
||||||
|
tokens: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The main fn, `no_mangle` as it is a C symbol
|
/// The main fn, `no_mangle` as it is a C symbol
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn libafl_main() {
|
pub fn libafl_main() {
|
||||||
@ -48,34 +128,15 @@ pub fn libafl_main() {
|
|||||||
|
|
||||||
let workdir = env::current_dir().unwrap();
|
let workdir = env::current_dir().unwrap();
|
||||||
|
|
||||||
let yaml = load_yaml!("clap-config.yaml");
|
let opt = Opt::from_args();
|
||||||
let matches = App::from(yaml).get_matches();
|
|
||||||
|
|
||||||
let cores = parse_core_bind_arg(matches.value_of("cores").unwrap())
|
let cores = opt.cores;
|
||||||
.expect("No valid core count given!");
|
let broker_port = opt.broker_port;
|
||||||
let broker_port = matches
|
let remote_broker_addr = opt.remote_broker_addr;
|
||||||
.value_of("broker_port")
|
let input_dirs = opt.input;
|
||||||
.map(|s| s.parse().expect("Invalid broker port"))
|
let output_dir = opt.output;
|
||||||
.unwrap_or(1337);
|
let token_files = opt.tokens;
|
||||||
let remote_broker_addr = matches
|
let timeout_ms = opt.timeout;
|
||||||
.value_of("remote_broker_addr")
|
|
||||||
.map(|s| s.parse().expect("Invalid broker address"));
|
|
||||||
let input_dirs: Vec<PathBuf> = matches
|
|
||||||
.values_of("input")
|
|
||||||
.map(|v| v.map(PathBuf::from).collect())
|
|
||||||
.unwrap_or_default();
|
|
||||||
let output_dir = matches
|
|
||||||
.value_of("output")
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|| workdir.clone());
|
|
||||||
let token_files: Vec<&str> = matches
|
|
||||||
.values_of("tokens")
|
|
||||||
.map(|v| v.collect())
|
|
||||||
.unwrap_or_default();
|
|
||||||
let timeout_ms = matches
|
|
||||||
.value_of("timeout")
|
|
||||||
.map(|s| s.parse().expect("Invalid timeout"))
|
|
||||||
.unwrap_or(10000);
|
|
||||||
// let cmplog_enabled = matches.is_present("cmplog");
|
// let cmplog_enabled = matches.is_present("cmplog");
|
||||||
|
|
||||||
println!("Workdir: {:?}", workdir.to_string_lossy().to_string());
|
println!("Workdir: {:?}", workdir.to_string_lossy().to_string());
|
||||||
@ -157,7 +218,7 @@ pub fn libafl_main() {
|
|||||||
&mut state,
|
&mut state,
|
||||||
&mut mgr,
|
&mut mgr,
|
||||||
)?,
|
)?,
|
||||||
Duration::from_millis(timeout_ms),
|
timeout_ms,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Secondary harness due to mut ownership
|
// Secondary harness due to mut ownership
|
||||||
|
@ -15,7 +15,7 @@ use libafl::{
|
|||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
os::parse_core_bind_arg,
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -179,7 +179,7 @@ pub fn LLVMFuzzerRunDriver(
|
|||||||
env::current_dir().unwrap().to_string_lossy().to_string()
|
env::current_dir().unwrap().to_string_lossy().to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
let cores = parse_core_bind_arg(matches.value_of("cores").unwrap())
|
let cores = Cores::from_cmdline(matches.value_of("cores").unwrap())
|
||||||
.expect("No valid core count given!");
|
.expect("No valid core count given!");
|
||||||
let broker_port = matches
|
let broker_port = matches
|
||||||
.value_of("broker_port")
|
.value_of("broker_port")
|
||||||
|
@ -24,7 +24,7 @@ libafl = { path = "../../libafl/", features = ["std", "anymap_debug", "derive",
|
|||||||
libafl_targets = { path = "../../libafl_targets/", features = ["libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["yaml"] }
|
structopt = "0.3.25"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "libfuzzer_libpng"
|
name = "libfuzzer_libpng"
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
name: libfuzzer libpng
|
|
||||||
version: "0.1.0"
|
|
||||||
author: "Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
|
||||||
about: A clone of libfuzzer using libafl for a libpng harness.
|
|
||||||
args:
|
|
||||||
- cores:
|
|
||||||
short: c
|
|
||||||
long: cores
|
|
||||||
about: "spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6."
|
|
||||||
value_name: CORES
|
|
||||||
required: true
|
|
||||||
takes_value: true
|
|
@ -3,15 +3,15 @@
|
|||||||
//! In this example, you will see the use of the `launcher` feature.
|
//! In this example, you will see the use of the `launcher` feature.
|
||||||
//! The `launcher` will spawn new processes for each cpu core.
|
//! The `launcher` will spawn new processes for each cpu core.
|
||||||
|
|
||||||
use clap::{load_yaml, App};
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use std::{env, path::PathBuf};
|
use std::{env, net::SocketAddr, path::PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
os::parse_core_bind_arg,
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -27,8 +27,10 @@ use libafl::{
|
|||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
monitors::MultiMonitor,
|
monitors::MultiMonitor,
|
||||||
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
mutators::{
|
||||||
mutators::token_mutations::Tokens,
|
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
|
token_mutations::Tokens,
|
||||||
|
},
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
stages::mutational::StdMutationalStage,
|
stages::mutational::StdMutationalStage,
|
||||||
state::{HasCorpus, HasMetadata, StdState},
|
state::{HasCorpus, HasMetadata, StdState},
|
||||||
@ -37,19 +39,96 @@ use libafl::{
|
|||||||
|
|
||||||
use libafl_targets::{edges_map_from_ptr, libfuzzer_initialize, libfuzzer_test_one_input};
|
use libafl_targets::{edges_map_from_ptr, libfuzzer_initialize, libfuzzer_test_one_input};
|
||||||
|
|
||||||
|
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||||
|
Ok(Duration::from_millis(time.parse()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
#[structopt(
|
||||||
|
name = "libfuzzer_libpng_ctx",
|
||||||
|
about = "A clone of libfuzzer using LibAFL for a libpng harness",
|
||||||
|
author = "Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
||||||
|
)]
|
||||||
|
struct Opt {
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str = Cores::from_cmdline),
|
||||||
|
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||||
|
name = "CORES"
|
||||||
|
)]
|
||||||
|
cores: Cores,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short = "p",
|
||||||
|
long,
|
||||||
|
help = "Choose the broker TCP port, default is 1337",
|
||||||
|
name = "PORT",
|
||||||
|
default_value = "1337"
|
||||||
|
)]
|
||||||
|
broker_port: u16,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short = "a",
|
||||||
|
long,
|
||||||
|
help = "Specify a remote broker",
|
||||||
|
name = "REMOTE"
|
||||||
|
)]
|
||||||
|
remote_broker_addr: Option<SocketAddr>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set an initial corpus directory",
|
||||||
|
name = "INPUT"
|
||||||
|
)]
|
||||||
|
input: Vec<PathBuf>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str),
|
||||||
|
help = "Set the output directory, default is ./out",
|
||||||
|
name = "OUTPUT",
|
||||||
|
default_value = "./out"
|
||||||
|
)]
|
||||||
|
output: PathBuf,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str = timeout_from_millis_str),
|
||||||
|
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||||
|
name = "TIMEOUT",
|
||||||
|
default_value = "10000",
|
||||||
|
)]
|
||||||
|
timeout: Duration,
|
||||||
|
/*
|
||||||
|
// The tokens are hardcoded in this example.
|
||||||
|
#[structopt(
|
||||||
|
parse(from_os_str),
|
||||||
|
short = "x",
|
||||||
|
long,
|
||||||
|
help = "Feed the fuzzer with an user-specified list of tokens (often called \"dictionary\"",
|
||||||
|
name = "TOKENS",
|
||||||
|
multiple = true
|
||||||
|
)]
|
||||||
|
tokens: Vec<PathBuf>,*/
|
||||||
|
}
|
||||||
|
|
||||||
/// The main fn, `no_mangle` as it is a C symbol
|
/// The main fn, `no_mangle` as it is a C symbol
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn libafl_main() {
|
pub fn libafl_main() {
|
||||||
// Registry the metadata types used in this fuzzer
|
// Registry the metadata types used in this fuzzer
|
||||||
// Needed only on no_std
|
// Needed only on no_std
|
||||||
//RegistryBuilder::register::<Tokens>();
|
//RegistryBuilder::register::<Tokens>();
|
||||||
let yaml = load_yaml!("clap-config.yaml");
|
let opt = Opt::from_args();
|
||||||
let matches = App::from(yaml).get_matches();
|
|
||||||
|
|
||||||
let broker_port = 1337;
|
let broker_port = opt.broker_port;
|
||||||
|
|
||||||
let cores = parse_core_bind_arg(matches.value_of("cores").unwrap())
|
let cores = opt.cores;
|
||||||
.expect("No valid core count given!");
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Workdir: {:?}",
|
"Workdir: {:?}",
|
||||||
@ -61,9 +140,6 @@ pub fn libafl_main() {
|
|||||||
let monitor = MultiMonitor::new(|s| println!("{}", s));
|
let monitor = MultiMonitor::new(|s| println!("{}", s));
|
||||||
|
|
||||||
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut restarting_mgr, _core_id| {
|
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut restarting_mgr, _core_id| {
|
||||||
let corpus_dirs = &[PathBuf::from("./corpus")];
|
|
||||||
let objective_dir = PathBuf::from("./crashes");
|
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges = edges_map_from_ptr();
|
let edges = edges_map_from_ptr();
|
||||||
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
|
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
|
||||||
@ -95,7 +171,7 @@ pub fn libafl_main() {
|
|||||||
InMemoryCorpus::new(),
|
InMemoryCorpus::new(),
|
||||||
// Corpus in which we store solutions (crashes in this example),
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
// on disk so the user can get them after stopping the fuzzer
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
OnDiskCorpus::new(opt.output.clone()).unwrap(),
|
||||||
// States of the feedbacks.
|
// States of the feedbacks.
|
||||||
// They are the data related to the feedbacks that you want to persist in the State.
|
// They are the data related to the feedbacks that you want to persist in the State.
|
||||||
tuple_list!(feedback_state),
|
tuple_list!(feedback_state),
|
||||||
@ -143,7 +219,7 @@ pub fn libafl_main() {
|
|||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
)?,
|
)?,
|
||||||
// 10 seconds timeout
|
// 10 seconds timeout
|
||||||
Duration::new(10, 0),
|
opt.timeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
@ -156,8 +232,8 @@ pub fn libafl_main() {
|
|||||||
// In case the corpus is empty (on first run), reset
|
// In case the corpus is empty (on first run), reset
|
||||||
if state.corpus().count() < 1 {
|
if state.corpus().count() < 1 {
|
||||||
state
|
state
|
||||||
.load_initial_inputs(&mut fuzzer, &mut executor, &mut restarting_mgr, corpus_dirs)
|
.load_initial_inputs(&mut fuzzer, &mut executor, &mut restarting_mgr, &opt.input)
|
||||||
.unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", corpus_dirs));
|
.unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", &opt.input));
|
||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +248,7 @@ pub fn libafl_main() {
|
|||||||
.run_client(&mut run_client)
|
.run_client(&mut run_client)
|
||||||
.cores(&cores)
|
.cores(&cores)
|
||||||
.broker_port(broker_port)
|
.broker_port(broker_port)
|
||||||
|
.remote_broker_addr(opt.remote_broker_addr)
|
||||||
.stdout_file(Some("/dev/null"))
|
.stdout_file(Some("/dev/null"))
|
||||||
.build()
|
.build()
|
||||||
.launch()
|
.launch()
|
||||||
|
@ -24,7 +24,7 @@ libafl = { path = "../../libafl/", features = ["std", "anymap_debug", "derive",
|
|||||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
||||||
# TODO Include it only when building cc
|
# TODO Include it only when building cc
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["yaml"] }
|
structopt = "0.3.25"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "libfuzzer_libpng"
|
name = "libfuzzer_libpng"
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
name: libfuzzer libpng
|
|
||||||
version: "0.1.0"
|
|
||||||
author: "Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
|
||||||
about: A clone of libfuzzer using libafl for a libpng harness.
|
|
||||||
args:
|
|
||||||
- cores:
|
|
||||||
short: c
|
|
||||||
long: cores
|
|
||||||
about: "spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6."
|
|
||||||
value_name: CORES
|
|
||||||
required: true
|
|
||||||
takes_value: true
|
|
@ -3,15 +3,15 @@
|
|||||||
//! In this example, you will see the use of the `launcher` feature.
|
//! In this example, you will see the use of the `launcher` feature.
|
||||||
//! The `launcher` will spawn new processes for each cpu core.
|
//! The `launcher` will spawn new processes for each cpu core.
|
||||||
|
|
||||||
use clap::{load_yaml, App};
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
use std::{env, path::PathBuf};
|
use std::{env, net::SocketAddr, path::PathBuf};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
os::parse_core_bind_arg,
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -37,19 +37,98 @@ use libafl::{
|
|||||||
|
|
||||||
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
|
||||||
|
|
||||||
|
/// Parse a millis string to a [`Duration`]. Used for arg parsing.
|
||||||
|
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||||
|
Ok(Duration::from_millis(time.parse()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The commandline args this fuzzer accepts
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
#[structopt(
|
||||||
|
name = "libfuzzer_libpng_launcher",
|
||||||
|
about = "A libfuzzer-like fuzzer for libpng with llmp-multithreading support and a launcher",
|
||||||
|
author = "Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
||||||
|
)]
|
||||||
|
struct Opt {
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str = Cores::from_cmdline),
|
||||||
|
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||||
|
name = "CORES"
|
||||||
|
)]
|
||||||
|
cores: Cores,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short = "p",
|
||||||
|
long,
|
||||||
|
help = "Choose the broker TCP port, default is 1337",
|
||||||
|
name = "PORT",
|
||||||
|
default_value = "1337"
|
||||||
|
)]
|
||||||
|
broker_port: u16,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short = "a",
|
||||||
|
long,
|
||||||
|
help = "Specify a remote broker",
|
||||||
|
name = "REMOTE"
|
||||||
|
)]
|
||||||
|
remote_broker_addr: Option<SocketAddr>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set an initial corpus directory",
|
||||||
|
name = "INPUT"
|
||||||
|
)]
|
||||||
|
input: Vec<PathBuf>,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str),
|
||||||
|
help = "Set the output directory, default is ./out",
|
||||||
|
name = "OUTPUT",
|
||||||
|
default_value = "./out"
|
||||||
|
)]
|
||||||
|
output: PathBuf,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str = timeout_from_millis_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||||
|
name = "TIMEOUT",
|
||||||
|
default_value = "10000"
|
||||||
|
)]
|
||||||
|
timeout: Duration,
|
||||||
|
/*
|
||||||
|
/// This fuzzer has hard-coded tokens
|
||||||
|
#[structopt(
|
||||||
|
parse(from_os_str),
|
||||||
|
short = "x",
|
||||||
|
long,
|
||||||
|
help = "Feed the fuzzer with an user-specified list of tokens (often called \"dictionary\"",
|
||||||
|
name = "TOKENS",
|
||||||
|
multiple = true
|
||||||
|
)]
|
||||||
|
tokens: Vec<PathBuf>,
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
/// The main fn, `no_mangle` as it is a C symbol
|
/// The main fn, `no_mangle` as it is a C symbol
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn libafl_main() {
|
pub fn libafl_main() {
|
||||||
// Registry the metadata types used in this fuzzer
|
// Registry the metadata types used in this fuzzer
|
||||||
// Needed only on no_std
|
// Needed only on no_std
|
||||||
//RegistryBuilder::register::<Tokens>();
|
//RegistryBuilder::register::<Tokens>();
|
||||||
let yaml = load_yaml!("clap-config.yaml");
|
let opt = Opt::from_args();
|
||||||
let matches = App::from(yaml).get_matches();
|
|
||||||
|
|
||||||
let broker_port = 1337;
|
let broker_port = opt.broker_port;
|
||||||
|
let cores = opt.cores;
|
||||||
let cores = parse_core_bind_arg(matches.value_of("cores").unwrap())
|
|
||||||
.expect("No valid core count given!");
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Workdir: {:?}",
|
"Workdir: {:?}",
|
||||||
@ -61,9 +140,6 @@ pub fn libafl_main() {
|
|||||||
let monitor = MultiMonitor::new(|s| println!("{}", s));
|
let monitor = MultiMonitor::new(|s| println!("{}", s));
|
||||||
|
|
||||||
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut restarting_mgr, _core_id| {
|
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut restarting_mgr, _core_id| {
|
||||||
let corpus_dirs = &[PathBuf::from("./corpus")];
|
|
||||||
let objective_dir = PathBuf::from("./crashes");
|
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
||||||
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
|
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
|
||||||
@ -95,7 +171,7 @@ pub fn libafl_main() {
|
|||||||
InMemoryCorpus::new(),
|
InMemoryCorpus::new(),
|
||||||
// Corpus in which we store solutions (crashes in this example),
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
// on disk so the user can get them after stopping the fuzzer
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
OnDiskCorpus::new(&opt.output).unwrap(),
|
||||||
// States of the feedbacks.
|
// States of the feedbacks.
|
||||||
// They are the data related to the feedbacks that you want to persist in the State.
|
// They are the data related to the feedbacks that you want to persist in the State.
|
||||||
tuple_list!(feedback_state),
|
tuple_list!(feedback_state),
|
||||||
@ -143,7 +219,7 @@ pub fn libafl_main() {
|
|||||||
&mut restarting_mgr,
|
&mut restarting_mgr,
|
||||||
)?,
|
)?,
|
||||||
// 10 seconds timeout
|
// 10 seconds timeout
|
||||||
Duration::new(10, 0),
|
opt.timeout,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The actual target run starts here.
|
// The actual target run starts here.
|
||||||
@ -156,8 +232,8 @@ pub fn libafl_main() {
|
|||||||
// In case the corpus is empty (on first run), reset
|
// In case the corpus is empty (on first run), reset
|
||||||
if state.corpus().count() < 1 {
|
if state.corpus().count() < 1 {
|
||||||
state
|
state
|
||||||
.load_initial_inputs(&mut fuzzer, &mut executor, &mut restarting_mgr, corpus_dirs)
|
.load_initial_inputs(&mut fuzzer, &mut executor, &mut restarting_mgr, &opt.input)
|
||||||
.unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", corpus_dirs));
|
.unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", &opt.input));
|
||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,6 +248,7 @@ pub fn libafl_main() {
|
|||||||
.run_client(&mut run_client)
|
.run_client(&mut run_client)
|
||||||
.cores(&cores)
|
.cores(&cores)
|
||||||
.broker_port(broker_port)
|
.broker_port(broker_port)
|
||||||
|
.remote_broker_addr(opt.remote_broker_addr)
|
||||||
.stdout_file(Some("/dev/null"))
|
.stdout_file(Some("/dev/null"))
|
||||||
.build()
|
.build()
|
||||||
.launch()
|
.launch()
|
||||||
|
@ -16,7 +16,7 @@ use crate::bolts::os::startable_self;
|
|||||||
use crate::bolts::os::{dup2, fork, ForkResult};
|
use crate::bolts::os::{dup2, fork, ForkResult};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::shmem::ShMemProvider,
|
bolts::{os::Cores, shmem::ShMemProvider},
|
||||||
events::{EventConfig, LlmpRestartingEventManager, ManagerKind, RestartingMgr},
|
events::{EventConfig, LlmpRestartingEventManager, ManagerKind, RestartingMgr},
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
monitors::Monitor,
|
monitors::Monitor,
|
||||||
@ -67,7 +67,7 @@ where
|
|||||||
#[builder(default = 1337_u16)]
|
#[builder(default = 1337_u16)]
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
/// The list of cores to run on
|
/// The list of cores to run on
|
||||||
cores: &'a [usize],
|
cores: &'a Cores,
|
||||||
/// A file name to write all client output to
|
/// A file name to write all client output to
|
||||||
#[builder(default = None)]
|
#[builder(default = None)]
|
||||||
stdout_file: Option<&'a str>,
|
stdout_file: Option<&'a str>,
|
||||||
@ -114,7 +114,7 @@ where
|
|||||||
// Spawn clients
|
// Spawn clients
|
||||||
let mut index = 0_u64;
|
let mut index = 0_u64;
|
||||||
for (id, bind_to) in core_ids.iter().enumerate().take(num_cores) {
|
for (id, bind_to) in core_ids.iter().enumerate().take(num_cores) {
|
||||||
if self.cores.iter().any(|&x| x == id) {
|
if self.cores.ids.iter().any(|&x| x == id.into()) {
|
||||||
index += 1;
|
index += 1;
|
||||||
self.shmem_provider.pre_fork()?;
|
self.shmem_provider.pre_fork()?;
|
||||||
match unsafe { fork() }? {
|
match unsafe { fork() }? {
|
||||||
@ -237,7 +237,7 @@ where
|
|||||||
|
|
||||||
//spawn clients
|
//spawn clients
|
||||||
for (id, _) in core_ids.iter().enumerate().take(num_cores) {
|
for (id, _) in core_ids.iter().enumerate().take(num_cores) {
|
||||||
if self.cores.iter().any(|&x| x == id) {
|
if self.cores.ids.iter().any(|&x| x == id.into()) {
|
||||||
let stdio = if self.stdout_file.is_some() {
|
let stdio = if self.stdout_file.is_some() {
|
||||||
Stdio::inherit()
|
Stdio::inherit()
|
||||||
} else {
|
} else {
|
||||||
|
@ -1435,7 +1435,7 @@ where
|
|||||||
let last_msg = self.last_msg_recvd;
|
let last_msg = self.last_msg_recvd;
|
||||||
if !last_msg.is_null() {
|
if !last_msg.is_null() {
|
||||||
assert!(
|
assert!(
|
||||||
!((*last_msg).tag == LLMP_TAG_END_OF_PAGE && !llmp_msg_in_page(page, last_msg)),
|
(*last_msg).tag != LLMP_TAG_END_OF_PAGE || llmp_msg_in_page(page, last_msg),
|
||||||
"BUG: full page passed to await_message_blocking or reset failed"
|
"BUG: full page passed to await_message_blocking or reset failed"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
//! Operating System specific abstractions
|
//! Operating System specific abstractions
|
||||||
|
//!
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
string::{String, ToString},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(any(unix, all(windows, feature = "std")))]
|
#[cfg(any(unix, all(windows, feature = "std")))]
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
@ -94,37 +100,147 @@ pub fn dup2(fd: i32, device: i32) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Core ID
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct CoreId {
|
||||||
|
pub id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl From<&CoreId> for core_affinity::CoreId {
|
||||||
|
fn from(core_id: &CoreId) -> Self {
|
||||||
|
core_affinity::CoreId { id: core_id.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl From<CoreId> for core_affinity::CoreId {
|
||||||
|
fn from(core_id: CoreId) -> Self {
|
||||||
|
core_affinity::CoreId { id: core_id.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl CoreId {
|
||||||
|
/// Set the affinity of the current process to this [`CoreId`]
|
||||||
|
pub fn set_affinity(&self) {
|
||||||
|
core_affinity::set_for_current(self.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for CoreId {
|
||||||
|
fn from(id: usize) -> Self {
|
||||||
|
CoreId { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl From<&core_affinity::CoreId> for CoreId {
|
||||||
|
fn from(core_id: &core_affinity::CoreId) -> Self {
|
||||||
|
CoreId { id: core_id.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl From<core_affinity::CoreId> for CoreId {
|
||||||
|
fn from(core_id: core_affinity::CoreId) -> Self {
|
||||||
|
CoreId { id: core_id.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A list of [`CoreId`] to use for fuzzing
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Cores {
|
||||||
|
/// The original commandline used during parsing
|
||||||
|
pub cmdline: String,
|
||||||
|
|
||||||
|
/// Vec of core ids
|
||||||
|
pub ids: Vec<CoreId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl Cores {
|
||||||
|
/// Pick all cores
|
||||||
|
pub fn all() -> Result<Self, Error> {
|
||||||
|
Self::from_cmdline("all")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses core binding args from user input
|
||||||
|
/// Returns a Vec of CPU IDs.
|
||||||
|
/// `./fuzzer --cores 1,2-4,6` -> clients run in cores 1,2,3,4,6
|
||||||
|
/// ` ./fuzzer --cores all` -> one client runs on each available core
|
||||||
|
pub fn from_cmdline(args: &str) -> Result<Self, Error> {
|
||||||
|
let mut cores: Vec<CoreId> = vec![];
|
||||||
|
|
||||||
|
// ./fuzzer --cores all -> one client runs in each available core
|
||||||
|
if args == "all" {
|
||||||
|
let num_cores = if let Some(cores) = core_affinity::get_core_ids() {
|
||||||
|
cores.len()
|
||||||
|
} else {
|
||||||
|
return Err(Error::IllegalState(
|
||||||
|
"Could not read core count from core_affinity".to_string(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
for x in 0..num_cores {
|
||||||
|
cores.push(x.into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let core_args: Vec<&str> = args.split(',').collect();
|
||||||
|
|
||||||
|
// ./fuzzer --cores 1,2-4,6 -> clients run in cores 1,2,3,4,6
|
||||||
|
for csv in core_args {
|
||||||
|
let core_range: Vec<&str> = csv.split('-').collect();
|
||||||
|
if core_range.len() == 1 {
|
||||||
|
cores.push(core_range[0].parse::<usize>()?.into());
|
||||||
|
} else if core_range.len() == 2 {
|
||||||
|
for x in core_range[0].parse::<usize>()?..=(core_range[1].parse::<usize>()?) {
|
||||||
|
cores.push(x.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cores.is_empty() {
|
||||||
|
return Err(Error::IllegalArgument(format!(
|
||||||
|
"No cores specified! parsed: {}",
|
||||||
|
args
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
cmdline: args.to_string(),
|
||||||
|
ids: cores,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&[usize]> for Cores {
|
||||||
|
fn from(cores: &[usize]) -> Self {
|
||||||
|
let cmdline = cores
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(",");
|
||||||
|
let ids = cores.iter().map(|x| (*x).into()).collect();
|
||||||
|
Self { cmdline, ids }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<usize>> for Cores {
|
||||||
|
fn from(cores: Vec<usize>) -> Self {
|
||||||
|
Self::from(cores.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses core binding args from user input
|
/// Parses core binding args from user input
|
||||||
/// Returns a Vec of CPU IDs.
|
/// Returns a Vec of CPU IDs.
|
||||||
/// `./fuzzer --cores 1,2-4,6` -> clients run in cores 1,2,3,4,6
|
/// `./fuzzer --cores 1,2-4,6` -> clients run in cores 1,2,3,4,6
|
||||||
/// ` ./fuzzer --cores all` -> one client runs on each available core
|
/// ` ./fuzzer --cores all` -> one client runs on each available core
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
#[deprecated(since = "0.7.1", note = "Use Cores::from_cmdline instead")]
|
||||||
pub fn parse_core_bind_arg(args: &str) -> Option<Vec<usize>> {
|
pub fn parse_core_bind_arg(args: &str) -> Option<Vec<usize>> {
|
||||||
let mut cores: Vec<usize> = vec![];
|
Cores::from_cmdline(args)
|
||||||
if args == "all" {
|
.ok()
|
||||||
let num_cores = core_affinity::get_core_ids().unwrap().len();
|
.map(|cores| cores.ids.iter().map(|x| x.id).collect())
|
||||||
for x in 0..num_cores {
|
|
||||||
cores.push(x);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let core_args: Vec<&str> = args.split(',').collect();
|
|
||||||
|
|
||||||
// ./fuzzer --cores 1,2-4,6 -> clients run in cores 1,2,3,4,6
|
|
||||||
// ./fuzzer --cores all -> one client runs in each available core
|
|
||||||
for csv in core_args {
|
|
||||||
let core_range: Vec<&str> = csv.split('-').collect();
|
|
||||||
if core_range.len() == 1 {
|
|
||||||
cores.push(core_range[0].parse::<usize>().unwrap());
|
|
||||||
} else if core_range.len() == 2 {
|
|
||||||
for x in core_range[0].parse::<usize>().unwrap()
|
|
||||||
..=(core_range[1].parse::<usize>().unwrap())
|
|
||||||
{
|
|
||||||
cores.push(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(cores)
|
|
||||||
}
|
}
|
||||||
|
@ -640,7 +640,7 @@ where
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let copied_poll_fds: Vec<PollFd> = poll_fds.iter().copied().collect();
|
let copied_poll_fds: Vec<PollFd> = poll_fds.clone();
|
||||||
for poll_fd in copied_poll_fds {
|
for poll_fd in copied_poll_fds {
|
||||||
let revents = poll_fd.revents().expect("revents should not be None");
|
let revents = poll_fd.revents().expect("revents should not be None");
|
||||||
let raw_polled_fd =
|
let raw_polled_fd =
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::{cell::RefCell, time::Duration};
|
use core::{cell::RefCell, time::Duration};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fs::OpenOptions, path::PathBuf};
|
use std::{
|
||||||
|
fs::OpenOptions,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::{fs, fs::File, io::Write};
|
use std::{fs, fs::File, io::Write};
|
||||||
@ -171,14 +174,20 @@ where
|
|||||||
{
|
{
|
||||||
/// Creates the [`OnDiskCorpus`].
|
/// Creates the [`OnDiskCorpus`].
|
||||||
/// Will error, if [`std::fs::create_dir_all()`] failed for `dir_path`.
|
/// Will error, if [`std::fs::create_dir_all()`] failed for `dir_path`.
|
||||||
pub fn new(dir_path: PathBuf) -> Result<Self, Error> {
|
pub fn new<P>(dir_path: P) -> Result<Self, Error>
|
||||||
fs::create_dir_all(&dir_path)?;
|
where
|
||||||
Ok(Self {
|
P: AsRef<Path>,
|
||||||
entries: vec![],
|
{
|
||||||
current: None,
|
fn new<I: Input>(dir_path: PathBuf) -> Result<OnDiskCorpus<I>, Error> {
|
||||||
dir_path,
|
fs::create_dir_all(&dir_path)?;
|
||||||
meta_format: None,
|
Ok(OnDiskCorpus {
|
||||||
})
|
entries: vec![],
|
||||||
|
current: None,
|
||||||
|
dir_path,
|
||||||
|
meta_format: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
new(dir_path.as_ref().to_path_buf())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the [`OnDiskCorpus`] specifying the type of `Metadata` to be saved to disk.
|
/// Creates the [`OnDiskCorpus`] specifying the type of `Metadata` to be saved to disk.
|
||||||
|
@ -61,13 +61,18 @@ const ITIMER_REAL: c_int = 0;
|
|||||||
|
|
||||||
/// Reset and remove the timeout
|
/// Reset and remove the timeout
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub unsafe fn unix_remove_timeout() {
|
pub(crate) fn unix_remove_timeout() {
|
||||||
let mut itimerval_zero: Itimerval = zeroed();
|
unsafe {
|
||||||
setitimer(ITIMER_REAL, &mut itimerval_zero, null_mut());
|
let mut itimerval_zero: Itimerval = zeroed();
|
||||||
|
setitimer(ITIMER_REAL, &mut itimerval_zero, null_mut());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes this timer queue
|
||||||
|
/// # Safety
|
||||||
|
/// Will dereference the given `tp_timer` pointer, unchecked.
|
||||||
#[cfg(all(windows, feature = "std"))]
|
#[cfg(all(windows, feature = "std"))]
|
||||||
pub unsafe fn windows_delete_timer_queue(tp_timer: *mut TP_TIMER) {
|
pub(crate) unsafe fn windows_delete_timer_queue(tp_timer: *mut TP_TIMER) {
|
||||||
CloseThreadpoolTimer(tp_timer);
|
CloseThreadpoolTimer(tp_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = { version = "1.0", features = ["parallel"] }
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
which = "4.2.2"
|
||||||
|
|
||||||
[target.'cfg(target_vendor = "apple")'.build-dependencies]
|
[target.'cfg(target_vendor = "apple")'.build-dependencies]
|
||||||
glob = "0.3"
|
glob = "0.3"
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
use std::{env, fs::File, io::Write, path::Path, process::Command, str};
|
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
use glob::glob;
|
use glob::glob;
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::{env, fs::File, io::Write, path::Path, process::Command, str};
|
||||||
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
|
use which::which;
|
||||||
|
|
||||||
|
/// The max version of `LLVM` we're looking for
|
||||||
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
|
const LLVM_VERSION_MAX: u32 = 33;
|
||||||
|
|
||||||
|
/// The min version of `LLVM` we're looking for
|
||||||
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
|
const LLVM_VERSION_MIN: u32 = 6;
|
||||||
|
|
||||||
|
/// Get the extension for a shared object
|
||||||
fn dll_extension<'a>() -> &'a str {
|
fn dll_extension<'a>() -> &'a str {
|
||||||
match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
|
match env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() {
|
||||||
"windwos" => "dll",
|
"windwos" => "dll",
|
||||||
@ -53,6 +62,13 @@ fn find_llvm_config() -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(target_vendor = "apple"))]
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
|
for version in (LLVM_VERSION_MIN..=LLVM_VERSION_MAX).rev() {
|
||||||
|
let llvm_config_name = format!("llvm-config-{}", version);
|
||||||
|
if which(&llvm_config_name).is_ok() {
|
||||||
|
return llvm_config_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_vendor = "apple"))]
|
||||||
"llvm-config".to_string()
|
"llvm-config".to_string()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -62,6 +78,9 @@ fn main() {
|
|||||||
let out_dir = Path::new(&out_dir);
|
let out_dir = Path::new(&out_dir);
|
||||||
let src_dir = Path::new("src");
|
let src_dir = Path::new("src");
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE");
|
||||||
|
|
||||||
let mut custom_flags = vec![];
|
let mut custom_flags = vec![];
|
||||||
|
|
||||||
let dest_path = Path::new(&out_dir).join("clang_constants.rs");
|
let dest_path = Path::new(&out_dir).join("clang_constants.rs");
|
||||||
@ -70,7 +89,6 @@ fn main() {
|
|||||||
let edges_map_size: usize = option_env!("LIBAFL_EDGES_MAP_SIZE")
|
let edges_map_size: usize = option_env!("LIBAFL_EDGES_MAP_SIZE")
|
||||||
.map_or(Ok(65536), str::parse)
|
.map_or(Ok(65536), str::parse)
|
||||||
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE");
|
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE");
|
|
||||||
custom_flags.push(format!("-DLIBAFL_EDGES_MAP_SIZE={}", edges_map_size));
|
custom_flags.push(format!("-DLIBAFL_EDGES_MAP_SIZE={}", edges_map_size));
|
||||||
|
|
||||||
let llvm_config = find_llvm_config();
|
let llvm_config = find_llvm_config();
|
||||||
@ -154,8 +172,9 @@ pub const CLANGXX_PATH: &str = \"clang++\";
|
|||||||
.expect("Could not write file");
|
.expect("Could not write file");
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"cargo:warning=Failed to locate the LLVM path using {}, we will not build LLVM passes",
|
"cargo:warning=Failed to locate the LLVM path using {}, we will not build LLVM passes
|
||||||
llvm_config
|
(if you need them, set point the LLVM_CONFIG env to a recent llvm-config, or make sure {} is available)",
|
||||||
|
llvm_config, llvm_config
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,12 @@ use std::{ffi::c_void, marker::PhantomData};
|
|||||||
|
|
||||||
use frida_gum::{
|
use frida_gum::{
|
||||||
stalker::{NoneEventSink, Stalker},
|
stalker::{NoneEventSink, Stalker},
|
||||||
Gum, MemoryRange, NativePointer,
|
Gum, NativePointer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(all(not(debug_assertions), target_arch = "x86_64"))]
|
||||||
|
use frida_gum::MemoryRange;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
|
executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
|
||||||
inputs::{HasTargetBytes, Input},
|
inputs::{HasTargetBytes, Input},
|
||||||
@ -108,6 +111,9 @@ where
|
|||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
{
|
{
|
||||||
pub fn new(gum: &'a Gum, base: InProcessExecutor<'a, H, I, OT, S>, helper: &'c mut FH) -> Self {
|
pub fn new(gum: &'a Gum, base: InProcessExecutor<'a, H, I, OT, S>, helper: &'c mut FH) -> Self {
|
||||||
|
#[cfg(not(all(not(debug_assertions), target_arch = "x86_64")))]
|
||||||
|
let stalker = Stalker::new(gum);
|
||||||
|
#[cfg(all(not(debug_assertions), target_arch = "x86_64"))]
|
||||||
let mut stalker = Stalker::new(gum);
|
let mut stalker = Stalker::new(gum);
|
||||||
|
|
||||||
#[cfg(all(not(debug_assertions), target_arch = "x86_64"))]
|
#[cfg(all(not(debug_assertions), target_arch = "x86_64"))]
|
||||||
|
@ -64,6 +64,7 @@ enum CmplogOperandType {
|
|||||||
Mem(capstone::RegId, capstone::RegId, i32, u32),
|
Mem(capstone::RegId, capstone::RegId, i32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "cmplog", target_arch = "aarch64"))]
|
||||||
enum SpecialCmpLogCase {
|
enum SpecialCmpLogCase {
|
||||||
Tbz,
|
Tbz,
|
||||||
Tbnz,
|
Tbnz,
|
||||||
|
@ -26,7 +26,8 @@ pub mod helper;
|
|||||||
pub mod executor;
|
pub mod executor;
|
||||||
|
|
||||||
// for parsing asan and cmplog cores
|
// for parsing asan and cmplog cores
|
||||||
use libafl::bolts::os::parse_core_bind_arg;
|
use libafl::bolts::os::{CoreId, Cores};
|
||||||
|
|
||||||
// for getting current core_id
|
// for getting current core_id
|
||||||
use core_affinity::get_core_ids;
|
use core_affinity::get_core_ids;
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ impl FridaOptions {
|
|||||||
options.asan_max_allocation_panics = value.parse().unwrap();
|
options.asan_max_allocation_panics = value.parse().unwrap();
|
||||||
}
|
}
|
||||||
"asan-cores" => {
|
"asan-cores" => {
|
||||||
asan_cores = parse_core_bind_arg(value);
|
asan_cores = Cores::from_cmdline(value).ok();
|
||||||
}
|
}
|
||||||
"instrument-suppress-locations" => {
|
"instrument-suppress-locations" => {
|
||||||
options.instrument_suppress_locations = Some(
|
options.instrument_suppress_locations = Some(
|
||||||
@ -132,7 +133,7 @@ impl FridaOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"cmplog-cores" => {
|
"cmplog-cores" => {
|
||||||
cmplog_cores = parse_core_bind_arg(value);
|
cmplog_cores = Cores::from_cmdline(value).ok();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("unknown FRIDA option: '{}'", option);
|
panic!("unknown FRIDA option: '{}'", option);
|
||||||
@ -148,8 +149,8 @@ impl FridaOptions {
|
|||||||
1,
|
1,
|
||||||
"Client should only be bound to a single core"
|
"Client should only be bound to a single core"
|
||||||
);
|
);
|
||||||
let core_id = core_ids[0].id;
|
let core_id: CoreId = core_ids[0].into();
|
||||||
options.enable_asan = asan_cores.contains(&core_id);
|
options.enable_asan = asan_cores.ids.contains(&core_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if options.enable_cmplog {
|
if options.enable_cmplog {
|
||||||
@ -160,8 +161,8 @@ impl FridaOptions {
|
|||||||
1,
|
1,
|
||||||
"Client should only be bound to a single core"
|
"Client should only be bound to a single core"
|
||||||
);
|
);
|
||||||
let core_id = core_ids[0].id;
|
let core_id = core_ids[0].into();
|
||||||
options.enable_cmplog = cmplog_cores.contains(&core_id);
|
options.enable_cmplog = cmplog_cores.ids.contains(&core_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ use libafl::{
|
|||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMem, ShMemProvider, StdShMemProvider},
|
shmem::{ShMem, ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -54,7 +55,7 @@ pub struct ForkserverBytesCoverageSugar<'a, const MAP_SIZE: usize> {
|
|||||||
#[builder(default = 1337_u16)]
|
#[builder(default = 1337_u16)]
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
/// The list of cores to run on
|
/// The list of cores to run on
|
||||||
cores: &'a [usize],
|
cores: &'a Cores,
|
||||||
/// The `ip:port` address of another broker to connect our new broker to for multi-machine
|
/// The `ip:port` address of another broker to connect our new broker to for multi-machine
|
||||||
/// clusters.
|
/// clusters.
|
||||||
#[builder(default = None, setter(strip_option))]
|
#[builder(default = None, setter(strip_option))]
|
||||||
@ -252,6 +253,7 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> {
|
|||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
pub mod pybind {
|
pub mod pybind {
|
||||||
use crate::forkserver;
|
use crate::forkserver;
|
||||||
|
use libafl::bolts::os::Cores;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -260,7 +262,7 @@ pub mod pybind {
|
|||||||
input_dirs: Vec<PathBuf>,
|
input_dirs: Vec<PathBuf>,
|
||||||
output_dir: PathBuf,
|
output_dir: PathBuf,
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
cores: Vec<usize>,
|
cores: Cores,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
@ -276,7 +278,7 @@ pub mod pybind {
|
|||||||
input_dirs,
|
input_dirs,
|
||||||
output_dir,
|
output_dir,
|
||||||
broker_port,
|
broker_port,
|
||||||
cores,
|
cores: cores.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use libafl::{
|
|||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -58,7 +59,7 @@ where
|
|||||||
#[builder(default = 1337_u16)]
|
#[builder(default = 1337_u16)]
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
/// The list of cores to run on
|
/// The list of cores to run on
|
||||||
cores: &'a [usize],
|
cores: &'a Cores,
|
||||||
/// The `ip:port` address of another broker to connect our new broker to for multi-machine
|
/// The `ip:port` address of another broker to connect our new broker to for multi-machine
|
||||||
/// clusters.
|
/// clusters.
|
||||||
#[builder(default = None, setter(strip_option))]
|
#[builder(default = None, setter(strip_option))]
|
||||||
@ -272,6 +273,7 @@ where
|
|||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
pub mod pybind {
|
pub mod pybind {
|
||||||
use crate::inmemory;
|
use crate::inmemory;
|
||||||
|
use libafl::bolts::os::Cores;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyBytes;
|
use pyo3::types::PyBytes;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -281,7 +283,7 @@ pub mod pybind {
|
|||||||
input_dirs: Vec<PathBuf>,
|
input_dirs: Vec<PathBuf>,
|
||||||
output_dir: PathBuf,
|
output_dir: PathBuf,
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
cores: Vec<usize>,
|
cores: Cores,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
@ -297,7 +299,7 @@ pub mod pybind {
|
|||||||
input_dirs,
|
input_dirs,
|
||||||
output_dir,
|
output_dir,
|
||||||
broker_port,
|
broker_port,
|
||||||
cores,
|
cores: cores.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use libafl::{
|
|||||||
bolts::{
|
bolts::{
|
||||||
current_nanos,
|
current_nanos,
|
||||||
launcher::Launcher,
|
launcher::Launcher,
|
||||||
|
os::Cores,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -59,7 +60,7 @@ where
|
|||||||
#[builder(default = 1337_u16)]
|
#[builder(default = 1337_u16)]
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
/// The list of cores to run on
|
/// The list of cores to run on
|
||||||
cores: &'a [usize],
|
cores: &'a Cores,
|
||||||
/// The `ip:port` address of another broker to connect our new broker to for multi-machine
|
/// The `ip:port` address of another broker to connect our new broker to for multi-machine
|
||||||
/// clusters.
|
/// clusters.
|
||||||
#[builder(default = None, setter(strip_option))]
|
#[builder(default = None, setter(strip_option))]
|
||||||
@ -330,6 +331,7 @@ where
|
|||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
pub mod pybind {
|
pub mod pybind {
|
||||||
use crate::qemu;
|
use crate::qemu;
|
||||||
|
use libafl::bolts::os::Cores;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyBytes;
|
use pyo3::types::PyBytes;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -339,7 +341,7 @@ pub mod pybind {
|
|||||||
input_dirs: Vec<PathBuf>,
|
input_dirs: Vec<PathBuf>,
|
||||||
output_dir: PathBuf,
|
output_dir: PathBuf,
|
||||||
broker_port: u16,
|
broker_port: u16,
|
||||||
cores: Vec<usize>,
|
cores: Cores,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
@ -355,7 +357,7 @@ pub mod pybind {
|
|||||||
input_dirs,
|
input_dirs,
|
||||||
output_dir,
|
output_dir,
|
||||||
broker_port,
|
broker_port,
|
||||||
cores,
|
cores: cores.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ extern "C" {
|
|||||||
|
|
||||||
/// Hooked `exit` function
|
/// Hooked `exit` function
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn exit(status: i32) {
|
pub extern "C" fn exit(status: i32) {
|
||||||
println!("DeExit: The target called exit with status code {}", status);
|
println!("DeExit: The target called exit with status code {}", status);
|
||||||
unsafe {
|
unsafe {
|
||||||
abort();
|
abort();
|
||||||
|
@ -11,4 +11,4 @@ regex = "1"
|
|||||||
postcard = "0.7"
|
postcard = "0.7"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
libafl = { path = "../../../libafl" }
|
libafl = { path = "../../../libafl" }
|
||||||
clap = { version = "3.0.0-beta.2", features = ["yaml"] }
|
structopt = "0.3.25"
|
||||||
|
@ -1,17 +1,54 @@
|
|||||||
use clap::{load_yaml, App};
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
fs,
|
fs,
|
||||||
io::{BufReader, Write},
|
io::{BufReader, Write},
|
||||||
path::Path,
|
path::Path,
|
||||||
|
path::PathBuf,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use libafl::generators::gramatron::{Automaton, Trigger};
|
use libafl::generators::gramatron::{Automaton, Trigger};
|
||||||
|
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
#[structopt(
|
||||||
|
name = "construct_automata",
|
||||||
|
about = "Generate a serialized Automaton using a json GNF grammar",
|
||||||
|
author = "Andrea Fioraldi <andreafioraldi@gmail.com>"
|
||||||
|
)]
|
||||||
|
struct Opt {
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long = "grammar-file",
|
||||||
|
name = "GRAMMAR",
|
||||||
|
help = "The grammar to use during fuzzing"
|
||||||
|
)]
|
||||||
|
grammar: PathBuf,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
name = "LIMIT",
|
||||||
|
help = "The max stack size after which a generated input is abandoned",
|
||||||
|
default_value = "0"
|
||||||
|
)]
|
||||||
|
limit: usize,
|
||||||
|
|
||||||
|
#[structopt(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set the output file",
|
||||||
|
name = "OUTPUT"
|
||||||
|
)]
|
||||||
|
output: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
fn read_grammar_from_file<P: AsRef<Path>>(path: P) -> Value {
|
fn read_grammar_from_file<P: AsRef<Path>>(path: P) -> Value {
|
||||||
let file = fs::File::open(path).unwrap();
|
let file = fs::File::open(path).unwrap();
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
@ -268,12 +305,11 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let yaml = load_yaml!("clap-config.yaml");
|
let opt = Opt::from_args();
|
||||||
let matches = App::from(yaml).get_matches();
|
|
||||||
|
|
||||||
let grammar_file = matches.value_of("grammar").unwrap();
|
let grammar_file = opt.grammar;
|
||||||
let output_file = matches.value_of("output").unwrap();
|
let output_file = opt.output;
|
||||||
let stack_limit = matches.value_of_t::<usize>("limit").unwrap_or(0);
|
let stack_limit = opt.limit;
|
||||||
|
|
||||||
let mut worklist = VecDeque::new();
|
let mut worklist = VecDeque::new();
|
||||||
let mut state_count = 1;
|
let mut state_count = 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user