Intial support to Python bindings for the libafl crate (#429)

* Add libafl py module

* Hardcoded baby_fuzzer

* Trait abstraction: MapObserver
Send type name as a param as it's needed for extracting the rust struct from the PyObject

* Fix merge

* Impl traits for python wrappers

* Add PythonExecutor
Not buildable version

* Executor trait bindings

* Monitor trait bindings

* EventManager trait bindings

* Fix warnings

* Add corpus trait bindings

* Use corpus trait bindings

* Rand trait bindings

* Remove python feature from default

* Add cfg attribute

* Fix fmt

* No std box

* Fix clippy

* turn OwnedInProcessExecutor in a simple type alias

* remove crate-type from libafl's Cargo.toml

* Add python baby_fuzzer

* Fix doc

* Maturin doc

* multiple map observer

* fmt

* build pylibafl with nightly

* macro for map element type

* Update py baby_fuzzer & fmt

* Mutator bindings

* fmt

* merge conflicts

* StdMutationalStage bindings
Not working: Cannot pass mutator to new method because not clonable

* Stage bindings

* StagesOwnedList bindings
Not working: Stage not clonable

* Unsafe transmute copy fix

* Use Stage bindings in baby_fuzzer

* fmt

* fmt

* Fix doc

* fix merge

* Remove x86_64 feature from pylibafl

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
This commit is contained in:
Farouk Faiz 2022-02-14 11:41:39 +01:00 committed by GitHub
parent 393afa56c8
commit 2dcdaaa89f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 2762 additions and 26 deletions

View File

@ -7,6 +7,8 @@ edition = "2021"
pyo3 = { version = "0.15", features = ["extension-module"] }
libafl_qemu = { path = "../../libafl_qemu", version = "0.7", features = ["python"] }
libafl_sugar = { path = "../../libafl_sugar", version = "0.7", features = ["python"] }
libafl = { path = "../../libafl", version = "0.7", features = ["python"] }
[build-dependencies]
pyo3-build-config = { version = "0.15" }
@ -14,3 +16,6 @@ pyo3-build-config = { version = "0.15" }
[lib]
name = "pylibafl"
crate-type = ["cdylib"]
[profile.dev]
panic = "abort"

View File

@ -0,0 +1,31 @@
# How to use python bindings
## First time setup
```
# Create environment variable
python -m venv .env
# Install maturin
pip install maturin
```
## Build bindings
```
# Activate virtual environment
source .env/bin/activate
# Build python module
maturin develop
```
This is going to install `pylibafl` python module.
## Use bindings
### Example: Running baby_fuzzer in fuzzers/baby_fuzzer/baby_fuzzer.py
First, make sure the python virtual environment is activated. If not, run `source .env/bin/activate
`. Running `pip freeze` at this point should display the following (versions may differ):
```
maturin==0.12.6
pylibafl==0.7.0
toml==0.10.2
```
Then simply run
```
python PATH_TO_BABY_FUZZER/baby_fuzzer.py
```
The crashes' directory will be created in the directory from which you ran the command.

View File

@ -0,0 +1 @@
nightly

View File

@ -1,5 +1,6 @@
use libafl_qemu;
use libafl_sugar;
use libafl;
use pyo3::prelude::*;
#[pymodule]
@ -13,5 +14,9 @@ pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
libafl_qemu::python_module(py, qemu_module)?;
m.add_submodule(qemu_module)?;
let libafl_module = PyModule::new(py, "libafl")?;
libafl::python_module(py, libafl_module)?;
m.add_submodule(libafl_module)?;
Ok(())
}

View File

@ -0,0 +1,70 @@
from pylibafl import libafl
# LIBRARY WRAPPER
def map_observer_wrapper(map_observer):
if type(map_observer).__name__ == "OwnedMapObserverI32":
return libafl.MapObserverI32.new_from_owned(map_observer)
def executor_wrapper(executor):
if type(executor).__name__ == "OwnedInProcessExecutorI32":
return libafl.ExecutorI32.new_from_inprocess(executor)
def monitor_wrapper(monitor):
if type(monitor).__name__ == "SimpleMonitor":
return libafl.Monitor.new_from_simple(monitor)
def event_manager_wrapper(event_manager):
if type(event_manager).__name__ == "SimpleEventManager":
return libafl.EventManagerI32.new_from_simple(event_manager)
def corpus_wrapper(corpus):
if type(corpus).__name__ == "InMemoryCorpus":
return libafl.Corpus.new_from_in_memory(corpus)
if type(corpus).__name__ == "OnDiskCorpus":
return libafl.Corpus.new_from_on_disk(corpus)
def rand_wrapper(rand):
if type(rand).__name__ == "StdRand":
return libafl.Rand.new_from_std(rand)
def stage_wrapper(stage):
if type(stage).__name__ == "StdScheduledHavocMutationsStageI32":
return libafl.StageI32.new_from_std_scheduled(stage)
# CODE WRITTEN BY USER
def harness(inp):
if len(inp.hex()) >= 2 and inp.hex()[:2] == '61':
raise Exception("NOOOOOO =)")
map_observer = libafl.OwnedMapObserverI32("signals", [0] * 16)
feedback_state = libafl.MapFeedbackStateI32.with_observer(map_observer_wrapper(map_observer))
feedback = libafl.MaxMapFeedbackI32(feedback_state, map_observer_wrapper(map_observer))
state = libafl.StdStateI32(
rand_wrapper(libafl.StdRand.with_current_nanos()),
corpus_wrapper(libafl.InMemoryCorpus()),
corpus_wrapper(libafl.OnDiskCorpus("./crashes")),
feedback_state
)
monitor = libafl.SimpleMonitor()
mgr = libafl.SimpleEventManager(monitor_wrapper(monitor))
fuzzer = libafl.StdFuzzerI32(feedback)
executor = libafl.OwnedInProcessExecutorI32(harness, map_observer_wrapper(map_observer), fuzzer, state, event_manager_wrapper(mgr))
generator = libafl.RandPrintablesGeneratorI32(32)
state.generate_initial_inputs(fuzzer, executor_wrapper(executor), generator, event_manager_wrapper(mgr), 8)
stage = libafl.StdScheduledHavocMutationsStageI32.new_from_scheduled_havoc_mutations()
stage_tuple_list = libafl.StagesOwnedListI32(stage_wrapper(stage))
fuzzer.fuzz_loop(executor_wrapper(executor), state, event_manager_wrapper(mgr), stage_tuple_list)

View File

@ -19,6 +19,7 @@ fork = [] # uses the fork() syscall to spawn children, instead of launching a ne
rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng`
introspection = [] # Include performance statistics of the fuzzing pipeline
concolic_mutation = ["z3"] # include a simple concolic mutator based on z3
python = ["pyo3"]
tui_monitor = ["tui", "crossterm"] # enable TuiMonitor with crossterm
cli = ["clap"] # expose bolts::cli
qemu_cli = ["cli"]
@ -81,6 +82,8 @@ wait-timeout = { version = "0.2", optional = true } # used by CommandExecutor to
z3 = { version = "0.11", features = ["static-link-z3"], optional = true } # for concolic mutation
pyo3 = { version = "0.15", optional = true }
# AGPL
# !!! this create requires nightly
grammartec = { version = "0.1", optional = true }

View File

@ -224,7 +224,7 @@ unsafe fn handle_signal(sig: c_int, info: siginfo_t, void: *mut c_void) {
/// Setup signal handlers in a somewhat rusty way.
/// This will allocate a signal stack and set the signal handlers accordingly.
/// It is, for example, used in the [`struct@crate::executors::InProcessExecutor`] to restart the fuzzer in case of a crash,
/// It is, for example, used in the [`type@crate::executors::InProcessExecutor`] to restart the fuzzer in case of a crash,
/// or to handle `SIGINT` in the broker process.
/// # Safety
/// The signal handlers will be called on any signal. They should (tm) be async safe.

View File

@ -430,3 +430,81 @@ mod tests {
println!("random value: {}", mutator.rng.next_u32());
}
}
#[cfg(feature = "python")]
/// `Rand` Python bindings
pub mod pybind {
use super::Rand;
use crate::bolts::{current_nanos, rands::StdRand};
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
#[pyclass(unsendable, name = "StdRand")]
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for StdRand
pub struct PythonStdRand {
/// Rust wrapped StdRand object
pub std_rand: StdRand,
}
#[pymethods]
impl PythonStdRand {
#[staticmethod]
fn with_current_nanos() -> Self {
Self {
std_rand: StdRand::with_seed(current_nanos()),
}
}
#[staticmethod]
fn with_seed(seed: u64) -> Self {
Self {
std_rand: StdRand::with_seed(seed),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
enum PythonRandWrapper {
StdRand(PythonStdRand),
}
/// Rand Trait binding
#[pyclass(unsendable, name = "Rand")]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PythonRand {
rand: PythonRandWrapper,
}
#[pymethods]
impl PythonRand {
#[staticmethod]
fn new_from_std(py_std_rand: PythonStdRand) -> Self {
Self {
rand: PythonRandWrapper::StdRand(py_std_rand),
}
}
}
impl Rand for PythonRand {
fn set_seed(&mut self, seed: u64) {
match &mut self.rand {
PythonRandWrapper::StdRand(py_std_rand) => py_std_rand.std_rand.set_seed(seed),
}
}
#[inline]
fn next(&mut self) -> u64 {
match &mut self.rand {
PythonRandWrapper::StdRand(py_std_rand) => py_std_rand.std_rand.next(),
}
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdRand>()?;
m.add_class::<PythonRand>()?;
Ok(())
}
}

View File

@ -133,3 +133,38 @@ where
})
}
}
/// ``CachedOnDiskCorpus`` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use std::path::PathBuf;
use crate::corpus::CachedOnDiskCorpus;
use crate::inputs::BytesInput;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
#[pyclass(unsendable, name = "CachedOnDiskCorpus")]
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for CachedOnDiskCorpus
pub struct PythonCachedOnDiskCorpus {
/// Rust wrapped CachedOnDiskCorpus object
pub cached_on_disk_corpus: CachedOnDiskCorpus<BytesInput>,
}
#[pymethods]
impl PythonCachedOnDiskCorpus {
#[new]
fn new(path: String, cache_max_len: usize) -> Self {
Self {
cached_on_disk_corpus: CachedOnDiskCorpus::new(PathBuf::from(path), cache_max_len)
.unwrap(),
}
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonCachedOnDiskCorpus>()?;
Ok(())
}
}

View File

@ -87,3 +87,35 @@ where
}
}
}
/// `InMemoryCorpus` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::corpus::InMemoryCorpus;
use crate::inputs::BytesInput;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
#[pyclass(unsendable, name = "InMemoryCorpus")]
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for InMemoryCorpus
pub struct PythonInMemoryCorpus {
/// Rust wrapped InMemoryCorpus object
pub in_memory_corpus: InMemoryCorpus<BytesInput>,
}
#[pymethods]
impl PythonInMemoryCorpus {
#[new]
fn new() -> Self {
Self {
in_memory_corpus: InMemoryCorpus::new(),
}
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonInMemoryCorpus>()?;
Ok(())
}
}

View File

@ -148,3 +148,171 @@ impl Default for RandCorpusScheduler {
/// A [`StdCorpusScheduler`] uses the default scheduler in `LibAFL` to schedule [`Testcase`]s.
/// The current `Std` is a [`RandCorpusScheduler`], although this may change in the future, if another [`CorpusScheduler`] delivers better results.
pub type StdCorpusScheduler = RandCorpusScheduler;
/// `Corpus` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::corpus::inmemory::pybind::PythonInMemoryCorpus;
use crate::corpus::{Corpus, Testcase};
use crate::inputs::BytesInput;
use crate::Error;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use super::cached::pybind::PythonCachedOnDiskCorpus;
use super::ondisk::pybind::PythonOnDiskCorpus;
#[derive(Serialize, Deserialize, Debug, Clone)]
enum PythonCorpusWrapper {
InMemory(PythonInMemoryCorpus),
CachedOnDisk(PythonCachedOnDiskCorpus),
OnDisk(PythonOnDiskCorpus),
}
/// Corpus Trait binding
#[pyclass(unsendable, name = "Corpus")]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PythonCorpus {
corpus: PythonCorpusWrapper,
}
#[pymethods]
impl PythonCorpus {
#[staticmethod]
fn new_from_in_memory(py_in_memory_corpus: PythonInMemoryCorpus) -> Self {
Self {
corpus: PythonCorpusWrapper::InMemory(py_in_memory_corpus),
}
}
#[staticmethod]
fn new_from_cached_on_disk(py_cached_on_disk_corpus: PythonCachedOnDiskCorpus) -> Self {
Self {
corpus: PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus),
}
}
#[staticmethod]
fn new_from_on_disk(py_on_disk_corpus: PythonOnDiskCorpus) -> Self {
Self {
corpus: PythonCorpusWrapper::OnDisk(py_on_disk_corpus),
}
}
}
impl Corpus<BytesInput> for PythonCorpus {
#[inline]
fn count(&self) -> usize {
match &self.corpus {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
py_in_memory_corpus.in_memory_corpus.count()
}
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
py_cached_on_disk_corpus.cached_on_disk_corpus.count()
}
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
py_on_disk_corpus.on_disk_corpus.count()
}
}
}
#[inline]
fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
match &mut self.corpus {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
py_in_memory_corpus.in_memory_corpus.add(testcase)
}
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
py_cached_on_disk_corpus.cached_on_disk_corpus.add(testcase)
}
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
py_on_disk_corpus.on_disk_corpus.add(testcase)
}
}
}
#[inline]
fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
match &mut self.corpus {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
py_in_memory_corpus.in_memory_corpus.replace(idx, testcase)
}
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
py_cached_on_disk_corpus
.cached_on_disk_corpus
.replace(idx, testcase)
}
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
py_on_disk_corpus.on_disk_corpus.replace(idx, testcase)
}
}
}
#[inline]
fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
match &mut self.corpus {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
py_in_memory_corpus.in_memory_corpus.remove(idx)
}
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
py_cached_on_disk_corpus.cached_on_disk_corpus.remove(idx)
}
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
py_on_disk_corpus.on_disk_corpus.remove(idx)
}
}
}
#[inline]
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<BytesInput>>, Error> {
match &self.corpus {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
py_in_memory_corpus.in_memory_corpus.get(idx)
}
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
py_cached_on_disk_corpus.cached_on_disk_corpus.get(idx)
}
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
py_on_disk_corpus.on_disk_corpus.get(idx)
}
}
}
#[inline]
fn current(&self) -> &Option<usize> {
match &self.corpus {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
py_in_memory_corpus.in_memory_corpus.current()
}
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
py_cached_on_disk_corpus.cached_on_disk_corpus.current()
}
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
py_on_disk_corpus.on_disk_corpus.current()
}
}
}
#[inline]
fn current_mut(&mut self) -> &mut Option<usize> {
match &mut self.corpus {
PythonCorpusWrapper::InMemory(py_in_memory_corpus) => {
py_in_memory_corpus.in_memory_corpus.current_mut()
}
PythonCorpusWrapper::CachedOnDisk(py_cached_on_disk_corpus) => {
py_cached_on_disk_corpus.cached_on_disk_corpus.current_mut()
}
PythonCorpusWrapper::OnDisk(py_on_disk_corpus) => {
py_on_disk_corpus.on_disk_corpus.current_mut()
}
}
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonCorpus>()?;
Ok(())
}
}

View File

@ -205,3 +205,36 @@ where
})
}
}
#[cfg(feature = "python")]
/// `OnDiskCorpus` Python bindings
pub mod pybind {
use std::path::PathBuf;
use crate::corpus::OnDiskCorpus;
use crate::inputs::BytesInput;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
#[pyclass(unsendable, name = "OnDiskCorpus")]
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for OnDiskCorpus
pub struct PythonOnDiskCorpus {
/// Rust wrapped OnDiskCorpus object
pub on_disk_corpus: OnDiskCorpus<BytesInput>,
}
#[pymethods]
impl PythonOnDiskCorpus {
#[new]
fn new(path: String) -> Self {
Self {
on_disk_corpus: OnDiskCorpus::new(PathBuf::from(path)).unwrap(),
}
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonOnDiskCorpus>()?;
Ok(())
}
}

View File

@ -543,3 +543,208 @@ mod tests {
};
}
}
/// `EventManager` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::events::simple::pybind::PythonSimpleEventManager;
use crate::events::{
Event, EventFirer, EventManager, EventManagerId, EventProcessor, EventRestarter,
HasEventManagerId, ProgressReporter,
};
use crate::inputs::BytesInput;
use crate::Error;
use pyo3::prelude::*;
macro_rules! define_python_event_manager {
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $std_state_name: ident, $executor_name: ident, $my_std_fuzzer_type_name: ident) => {
use crate::executors::pybind::$executor_name;
use crate::pybind::$my_std_fuzzer_type_name;
use crate::state::pybind::$std_state_name;
#[derive(Debug, Clone)]
enum $wrapper_name {
Simple(*mut PythonSimpleEventManager),
}
/// EventManager Trait binding
#[pyclass(unsendable, name = $py_name_trait)]
#[derive(Debug, Clone)]
pub struct $struct_name_trait {
event_manager: $wrapper_name,
}
impl $struct_name_trait {
fn get_event_manager(
&self,
) -> &impl EventManager<
$executor_name,
BytesInput,
$std_state_name,
$my_std_fuzzer_type_name,
> {
unsafe {
match self.event_manager {
$wrapper_name::Simple(py_simple_event_manager) => {
&(*py_simple_event_manager).simple_event_manager
}
}
}
}
fn get_mut_event_manager(
&mut self,
) -> &mut impl EventManager<
$executor_name,
BytesInput,
$std_state_name,
$my_std_fuzzer_type_name,
> {
unsafe {
match self.event_manager {
$wrapper_name::Simple(py_simple_event_manager) => {
&mut (*py_simple_event_manager).simple_event_manager
}
}
}
}
}
#[pymethods]
impl $struct_name_trait {
#[staticmethod]
fn new_from_simple(py_simple_event_manager: &mut PythonSimpleEventManager) -> Self {
Self {
event_manager: $wrapper_name::Simple(py_simple_event_manager),
}
}
}
impl EventFirer<BytesInput> for $struct_name_trait {
fn fire<S>(
&mut self,
_state: &mut S,
event: Event<BytesInput>,
) -> Result<(), Error> {
self.get_mut_event_manager().fire(_state, event)
}
}
impl<S> EventRestarter<S> for $struct_name_trait {}
impl
EventProcessor<
$executor_name,
BytesInput,
$std_state_name,
$my_std_fuzzer_type_name,
> for $struct_name_trait
{
fn process(
&mut self,
_fuzzer: &mut $my_std_fuzzer_type_name,
state: &mut $std_state_name,
_executor: &mut $executor_name,
) -> Result<usize, Error> {
self.get_mut_event_manager()
.process(_fuzzer, state, _executor)
}
}
impl ProgressReporter<BytesInput> for $struct_name_trait {}
impl HasEventManagerId for $struct_name_trait {
fn mgr_id(&self) -> EventManagerId {
self.get_event_manager().mgr_id()
}
}
impl EventManager<$executor_name, BytesInput, $std_state_name, $my_std_fuzzer_type_name>
for $struct_name_trait
{
}
};
}
define_python_event_manager!(
PythonEventManagerI8,
"EventManagerI8",
PythonEventManagerWrapperI8,
MyStdStateI8,
PythonExecutorI8,
MyStdFuzzerI8
);
define_python_event_manager!(
PythonEventManagerI16,
"EventManagerI16",
PythonEventManagerWrapperI16,
MyStdStateI16,
PythonExecutorI16,
MyStdFuzzerI16
);
define_python_event_manager!(
PythonEventManagerI32,
"EventManagerI32",
PythonEventManagerWrapperI32,
MyStdStateI32,
PythonExecutorI32,
MyStdFuzzerI32
);
define_python_event_manager!(
PythonEventManagerI64,
"EventManagerI64",
PythonEventManagerWrapperI64,
MyStdStateI64,
PythonExecutorI64,
MyStdFuzzerI64
);
define_python_event_manager!(
PythonEventManagerU8,
"EventManagerU8",
PythonEventManagerWrapperU8,
MyStdStateU8,
PythonExecutorU8,
MyStdFuzzerU8
);
define_python_event_manager!(
PythonEventManagerU16,
"EventManagerU16",
PythonEventManagerWrapperU16,
MyStdStateU16,
PythonExecutorU16,
MyStdFuzzerU16
);
define_python_event_manager!(
PythonEventManagerU32,
"EventManagerU32",
PythonEventManagerWrapperU32,
MyStdStateU32,
PythonExecutorU32,
MyStdFuzzerU32
);
define_python_event_manager!(
PythonEventManagerU64,
"EventManagerU64",
PythonEventManagerWrapperU64,
MyStdStateU64,
PythonExecutorU64,
MyStdFuzzerU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonEventManagerI8>()?;
m.add_class::<PythonEventManagerI16>()?;
m.add_class::<PythonEventManagerI32>()?;
m.add_class::<PythonEventManagerI64>()?;
m.add_class::<PythonEventManagerU8>()?;
m.add_class::<PythonEventManagerU16>()?;
m.add_class::<PythonEventManagerU32>()?;
m.add_class::<PythonEventManagerU64>()?;
Ok(())
}
}

View File

@ -425,3 +425,35 @@ where
Ok((state, mgr))
}
}
/// `SimpleEventManager` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::events::SimpleEventManager;
use crate::inputs::BytesInput;
use crate::monitors::pybind::PythonMonitor;
use pyo3::prelude::*;
#[pyclass(unsendable, name = "SimpleEventManager")]
#[derive(Debug, Clone)]
/// Python class for SimpleEventManager
pub struct PythonSimpleEventManager {
/// Rust wrapped SimpleEventManager object
pub simple_event_manager: SimpleEventManager<BytesInput, PythonMonitor>,
}
#[pymethods]
impl PythonSimpleEventManager {
#[new]
fn new(py_monitor: PythonMonitor) -> Self {
Self {
simple_event_manager: SimpleEventManager::new(py_monitor),
}
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonSimpleEventManager>()?;
Ok(())
}
}

View File

@ -4,6 +4,7 @@
//! Needs the `fork` feature flag.
use core::{
borrow::BorrowMut,
ffi::c_void,
fmt::{self, Debug, Formatter},
marker::PhantomData,
@ -16,6 +17,8 @@ use core::{
sync::atomic::{compiler_fence, Ordering},
};
use alloc::boxed::Box;
#[cfg(all(feature = "std", unix))]
use std::intrinsics::transmute;
@ -52,40 +55,50 @@ use crate::{
Error,
};
/// The process executor simply calls a target function, as mutable reference to a closure
pub type InProcessExecutor<'a, H, I, OT, S> = GenericInProcessExecutor<H, &'a mut H, I, OT, S>;
/// The process executor simply calls a target function, as boxed `FnMut` trait object
pub type OwnedInProcessExecutor<I, OT, S> =
GenericInProcessExecutor<dyn FnMut(&I) -> ExitKind, Box<dyn FnMut(&I) -> ExitKind>, I, OT, S>;
/// The inmem executor simply calls a target function, then returns afterwards.
#[allow(dead_code)]
pub struct InProcessExecutor<'a, H, I, OT, S>
pub struct GenericInProcessExecutor<H, HB, I, OT, S>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
I: Input,
OT: ObserversTuple<I, S>,
{
/// The harness function, being executed for each fuzzing loop execution
harness_fn: &'a mut H,
harness_fn: HB,
/// The observers, observing each run
observers: OT,
// Crash and timeout hah
handlers: InProcessHandlers,
phantom: PhantomData<(I, S)>,
phantom: PhantomData<(I, S, *const H)>,
}
impl<'a, H, I, OT, S> Debug for InProcessExecutor<'a, H, I, OT, S>
impl<H, HB, I, OT, S> Debug for GenericInProcessExecutor<H, HB, I, OT, S>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
I: Input,
OT: ObserversTuple<I, S>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("InProcessExecutor")
f.debug_struct("GenericInProcessExecutor")
.field("harness_fn", &"<fn>")
.field("observers", &self.observers)
.finish_non_exhaustive()
}
}
impl<'a, EM, H, I, OT, S, Z> Executor<EM, I, S, Z> for InProcessExecutor<'a, H, I, OT, S>
impl<EM, H, HB, I, OT, S, Z> Executor<EM, I, S, Z> for GenericInProcessExecutor<H, HB, I, OT, S>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
I: Input,
OT: ObserversTuple<I, S>,
{
@ -99,16 +112,17 @@ where
self.handlers
.pre_run_target(self, fuzzer, state, mgr, input);
let ret = (self.harness_fn)(input);
let ret = (self.harness_fn.borrow_mut())(input);
self.handlers.post_run_target();
Ok(ret)
}
}
impl<'a, H, I, OT, S> HasObservers<I, OT, S> for InProcessExecutor<'a, H, I, OT, S>
impl<H, HB, I, OT, S> HasObservers<I, OT, S> for GenericInProcessExecutor<H, HB, I, OT, S>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
I: Input,
OT: ObserversTuple<I, S>,
{
@ -123,9 +137,10 @@ where
}
}
impl<'a, H, I, OT, S> InProcessExecutor<'a, H, I, OT, S>
impl<H, HB, I, OT, S> GenericInProcessExecutor<H, HB, I, OT, S>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
I: Input,
OT: ObserversTuple<I, S>,
{
@ -136,7 +151,7 @@ where
/// * `observers` - the observers observing the target during execution
/// This may return an error on unix, if signal handler setup fails
pub fn new<EM, OF, Z>(
harness_fn: &'a mut H,
harness_fn: HB,
observers: OT,
_fuzzer: &mut Z,
_state: &mut S,
@ -175,13 +190,13 @@ where
/// Retrieve the harness function.
#[inline]
pub fn harness(&self) -> &H {
self.harness_fn
self.harness_fn.borrow()
}
/// Retrieve the harness function for a mutable reference.
#[inline]
pub fn harness_mut(&mut self) -> &mut H {
self.harness_fn
self.harness_fn.borrow_mut()
}
/// The inprocess handlers
@ -305,7 +320,7 @@ impl InProcessHandlers {
OF: Feedback<I, S>,
S: HasSolutions<I> + HasClientPerfMonitor,
Z: HasObjective<I, OF, S>,
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
{
#[cfg(unix)]
unsafe {
@ -1376,7 +1391,7 @@ impl Handler for InProcessForkExecutorGlobalData {
#[cfg(all(feature = "std", unix))]
pub struct InProcessForkExecutor<'a, H, I, OT, S, SP>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider,
@ -1391,7 +1406,7 @@ where
#[cfg(all(feature = "std", unix))]
impl<'a, H, I, OT, S, SP> Debug for InProcessForkExecutor<'a, H, I, OT, S, SP>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider,
@ -1408,7 +1423,7 @@ where
impl<'a, EM, H, I, OT, S, SP, Z> Executor<EM, I, S, Z>
for InProcessForkExecutor<'a, H, I, OT, S, SP>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider,
@ -1466,7 +1481,7 @@ where
#[cfg(all(feature = "std", unix))]
impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider,
@ -1512,7 +1527,7 @@ where
#[cfg(all(feature = "std", unix))]
impl<'a, H, I, OT, S, SP> HasObservers<I, OT, S> for InProcessForkExecutor<'a, H, I, OT, S, SP>
where
H: FnMut(&I) -> ExitKind,
H: FnMut(&I) -> ExitKind + ?Sized,
I: Input,
OT: ObserversTuple<I, S>,
SP: ShMemProvider,
@ -1652,3 +1667,155 @@ mod tests {
.is_ok());
}
}
#[cfg(feature = "python")]
/// `InProcess` Python bindings
pub mod pybind {
use crate::bolts::tuples::tuple_list;
use crate::executors::{inprocess::OwnedInProcessExecutor, ExitKind};
use crate::inputs::{BytesInput, HasBytesVec};
use pyo3::prelude::*;
use pyo3::types::PyBytes;
macro_rules! define_python_in_process_executor {
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $std_state_name: ident, $event_manager_name: ident, $map_observer_name: ident, $std_fuzzer_name: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::fuzzer::pybind::$std_fuzzer_name;
use crate::observers::pybind::$map_observer_name;
use crate::state::pybind::{$my_std_state_type_name, $std_state_name};
#[pyclass(unsendable, name = $py_name)]
#[derive(Debug)]
/// Python class for OwnedInProcessExecutor (i.e. InProcessExecutor with owned harness)
pub struct $struct_name {
/// Rust wrapped OwnedInProcessExecutor object
pub owned_in_process_executor: OwnedInProcessExecutor<
BytesInput,
($map_observer_name, ()),
$my_std_state_type_name,
>,
}
#[pymethods]
impl $struct_name {
#[new]
fn new(
harness: PyObject,
py_observer: $map_observer_name,
py_fuzzer: &mut $std_fuzzer_name,
py_state: &mut $std_state_name,
py_event_manager: &mut $event_manager_name,
) -> Self {
Self {
owned_in_process_executor: OwnedInProcessExecutor::new(
Box::new(move |input: &BytesInput| {
Python::with_gil(|py| -> PyResult<()> {
let args = (PyBytes::new(py, input.bytes()),);
harness.call1(py, args)?;
Ok(())
})
.unwrap();
ExitKind::Ok
}),
tuple_list!(py_observer),
&mut py_fuzzer.std_fuzzer,
&mut py_state.std_state,
py_event_manager,
)
.expect("Failed to create the Executor".into()),
}
}
}
};
}
define_python_in_process_executor!(
PythonOwnedInProcessExecutorI8,
"OwnedInProcessExecutorI8",
MyStdStateI8,
PythonStdStateI8,
PythonEventManagerI8,
PythonMapObserverI8,
PythonStdFuzzerI8
);
define_python_in_process_executor!(
PythonOwnedInProcessExecutorI16,
"OwnedInProcessExecutorI16",
MyStdStateI16,
PythonStdStateI16,
PythonEventManagerI16,
PythonMapObserverI16,
PythonStdFuzzerI16
);
define_python_in_process_executor!(
PythonOwnedInProcessExecutorI32,
"OwnedInProcessExecutorI32",
MyStdStateI32,
PythonStdStateI32,
PythonEventManagerI32,
PythonMapObserverI32,
PythonStdFuzzerI32
);
define_python_in_process_executor!(
PythonOwnedInProcessExecutorI64,
"OwnedInProcessExecutorI64",
MyStdStateI64,
PythonStdStateI64,
PythonEventManagerI64,
PythonMapObserverI64,
PythonStdFuzzerI64
);
define_python_in_process_executor!(
PythonOwnedInProcessExecutorU8,
"OwnedInProcessExecutorU8",
MyStdStateU8,
PythonStdStateU8,
PythonEventManagerU8,
PythonMapObserverU8,
PythonStdFuzzerU8
);
define_python_in_process_executor!(
PythonOwnedInProcessExecutorU16,
"OwnedInProcessExecutorU16",
MyStdStateU16,
PythonStdStateU16,
PythonEventManagerU16,
PythonMapObserverU16,
PythonStdFuzzerU16
);
define_python_in_process_executor!(
PythonOwnedInProcessExecutorU32,
"OwnedInProcessExecutorU32",
MyStdStateU32,
PythonStdStateU32,
PythonEventManagerU32,
PythonMapObserverU32,
PythonStdFuzzerU32
);
define_python_in_process_executor!(
PythonOwnedInProcessExecutorU64,
"OwnedInProcessExecutorU64",
MyStdStateU64,
PythonStdStateU64,
PythonEventManagerU64,
PythonMapObserverU64,
PythonStdFuzzerU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonOwnedInProcessExecutorI8>()?;
m.add_class::<PythonOwnedInProcessExecutorI16>()?;
m.add_class::<PythonOwnedInProcessExecutorI32>()?;
m.add_class::<PythonOwnedInProcessExecutorI64>()?;
m.add_class::<PythonOwnedInProcessExecutorU8>()?;
m.add_class::<PythonOwnedInProcessExecutorU16>()?;
m.add_class::<PythonOwnedInProcessExecutorU32>()?;
m.add_class::<PythonOwnedInProcessExecutorU64>()?;
Ok(())
}
}

View File

@ -184,3 +184,223 @@ mod test {
.is_ok());
}
}
#[cfg(feature = "python")]
/// `Executor` Python bindings
pub mod pybind {
use crate::executors::{Executor, ExitKind, HasObservers};
use crate::inputs::BytesInput;
use crate::Error;
use pyo3::prelude::*;
macro_rules! define_python_executor {
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident,
$event_manager_name: ident, $in_process_executor_name: ident, $map_observer_name: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::executors::inprocess::pybind::$in_process_executor_name;
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
use crate::observers::map::pybind::$map_observer_name;
use crate::state::pybind::$my_std_state_type_name;
#[derive(Debug)]
enum $wrapper_name {
OwnedInProcess(*mut $in_process_executor_name),
}
#[pyclass(unsendable, name = $py_name_trait)]
#[derive(Debug)]
/// Executor + HasObservers Trait binding
pub struct $struct_name_trait {
executor: $wrapper_name,
}
impl $struct_name_trait {
fn get_executor(
&self,
) -> &(impl Executor<
$event_manager_name,
BytesInput,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
> + HasObservers<BytesInput, ($map_observer_name, ()), $my_std_state_type_name>)
{
unsafe {
match self.executor {
$wrapper_name::OwnedInProcess(py_owned_inprocess_executor) => {
&(*py_owned_inprocess_executor).owned_in_process_executor
}
}
}
}
fn get_mut_executor(
&mut self,
) -> &mut (impl Executor<
$event_manager_name,
BytesInput,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
> + HasObservers<
BytesInput,
($map_observer_name, ()),
$my_std_state_type_name,
>) {
unsafe {
match self.executor {
$wrapper_name::OwnedInProcess(py_owned_inprocess_executor) => {
&mut (*py_owned_inprocess_executor).owned_in_process_executor
}
}
}
}
}
#[pymethods]
impl $struct_name_trait {
#[staticmethod]
fn new_from_inprocess(
owned_inprocess_executor: &mut $in_process_executor_name,
) -> Self {
Self {
executor: $wrapper_name::OwnedInProcess(owned_inprocess_executor),
}
}
}
impl<I, S> HasObservers<I, ($map_observer_name, ()), S> for $struct_name_trait {
// #[inline]
fn observers(&self) -> &($map_observer_name, ()) {
self.get_executor().observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut ($map_observer_name, ()) {
self.get_mut_executor().observers_mut()
}
}
impl
Executor<
$event_manager_name,
BytesInput,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
> for $struct_name_trait
{
#[inline]
fn run_target(
&mut self,
fuzzer: &mut $my_std_fuzzer_type_name,
state: &mut $my_std_state_type_name,
mgr: &mut $event_manager_name,
input: &BytesInput,
) -> Result<ExitKind, Error> {
self.get_mut_executor()
.run_target(fuzzer, state, mgr, input)
}
}
};
}
define_python_executor!(
PythonExecutorI8,
"ExecutorI8",
PythonExecutorWrapperI8,
MyStdStateI8,
MyStdFuzzerI8,
PythonEventManagerI8,
PythonOwnedInProcessExecutorI8,
PythonMapObserverI8
);
define_python_executor!(
PythonExecutorI16,
"ExecutorI16",
PythonExecutorWrapperI16,
MyStdStateI16,
MyStdFuzzerI16,
PythonEventManagerI16,
PythonOwnedInProcessExecutorI16,
PythonMapObserverI16
);
define_python_executor!(
PythonExecutorI32,
"ExecutorI32",
PythonExecutorWrapperI32,
MyStdStateI32,
MyStdFuzzerI32,
PythonEventManagerI32,
PythonOwnedInProcessExecutorI32,
PythonMapObserverI32
);
define_python_executor!(
PythonExecutorI64,
"ExecutorI64",
PythonExecutorWrapperI64,
MyStdStateI64,
MyStdFuzzerI64,
PythonEventManagerI64,
PythonOwnedInProcessExecutorI64,
PythonMapObserverI64
);
define_python_executor!(
PythonExecutorU8,
"ExecutorU8",
PythonExecutorWrapperU8,
MyStdStateU8,
MyStdFuzzerU8,
PythonEventManagerU8,
PythonOwnedInProcessExecutorU8,
PythonMapObserverU8
);
define_python_executor!(
PythonExecutorU16,
"ExecutorU16",
PythonExecutorWrapperU16,
MyStdStateU16,
MyStdFuzzerU16,
PythonEventManagerU16,
PythonOwnedInProcessExecutorU16,
PythonMapObserverU16
);
define_python_executor!(
PythonExecutorU32,
"ExecutorU32",
PythonExecutorWrapperU32,
MyStdStateU32,
MyStdFuzzerU32,
PythonEventManagerU32,
PythonOwnedInProcessExecutorU32,
PythonMapObserverU32
);
define_python_executor!(
PythonExecutorU64,
"ExecutorU64",
PythonExecutorWrapperU64,
MyStdStateU64,
MyStdFuzzerU64,
PythonEventManagerU64,
PythonOwnedInProcessExecutorU64,
PythonMapObserverU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonExecutorI8>()?;
m.add_class::<PythonExecutorI16>()?;
m.add_class::<PythonExecutorI32>()?;
m.add_class::<PythonExecutorI64>()?;
m.add_class::<PythonExecutorU8>()?;
m.add_class::<PythonExecutorU16>()?;
m.add_class::<PythonExecutorU32>()?;
m.add_class::<PythonExecutorU64>()?;
Ok(())
}
}

View File

@ -654,7 +654,6 @@ where
self.name.as_str()
}
}
#[cfg(test)]
mod tests {
use crate::feedbacks::{AllIsNovel, IsNovel, NextPow2IsNovel};
@ -679,3 +678,162 @@ mod tests {
assert!(!NextPow2IsNovel::is_novel(255_u8, 255));
}
}
#[cfg(feature = "python")]
/// Map Feedback Python bindings
pub mod pybind {
use crate::feedbacks::map::{MapFeedbackState, MaxMapFeedback};
use crate::inputs::BytesInput;
use pyo3::prelude::*;
macro_rules! define_python_map_feedback {
($map_feedback_state_struct_name:ident, $map_feedback_state_py_name:tt, $max_map_feedback_struct_name:ident,
$max_map_feedback_py_name:tt, $datatype:ty, $map_observer_name: ident, $std_state_name: ident) => {
use crate::observers::map::pybind::$map_observer_name;
use crate::state::pybind::$std_state_name;
#[pyclass(unsendable, name = $map_feedback_state_py_name)]
#[derive(Clone, Debug)]
/// Python class for MapFeedbackState
pub struct $map_feedback_state_struct_name {
/// Rust wrapped MapFeedbackState object
pub map_feedback_state: MapFeedbackState<$datatype>,
}
#[pymethods]
impl $map_feedback_state_struct_name {
#[staticmethod]
fn with_observer(py_observer: &$map_observer_name) -> Self {
Self {
map_feedback_state: MapFeedbackState::with_observer(py_observer),
}
}
}
#[pyclass(unsendable, name = $max_map_feedback_py_name)]
#[derive(Clone, Debug)]
/// Python class for MaxMapFeedback
pub struct $max_map_feedback_struct_name {
/// Rust wrapped MaxMapFeedback object
pub max_map_feedback:
MaxMapFeedback<BytesInput, $map_observer_name, $std_state_name, $datatype>,
}
#[pymethods]
impl $max_map_feedback_struct_name {
#[new]
fn new(
py_feedback_state: &$map_feedback_state_struct_name,
py_observer: &$map_observer_name,
) -> Self {
Self {
max_map_feedback: MaxMapFeedback::new(
&py_feedback_state.map_feedback_state,
py_observer,
),
}
}
}
};
}
define_python_map_feedback!(
PythonMapFeedbackStateI8,
"MapFeedbackStateI8",
PythonMaxMapFeedbackI8,
"MaxMapFeedbackI8",
i8,
PythonMapObserverI8,
MyStdStateI8
);
define_python_map_feedback!(
PythonMapFeedbackStateI16,
"MapFeedbackStateI16",
PythonMaxMapFeedbackI16,
"MaxMapFeedbackI16",
i16,
PythonMapObserverI16,
MyStdStateI16
);
define_python_map_feedback!(
PythonMapFeedbackStateI32,
"MapFeedbackStateI32",
PythonMaxMapFeedbackI32,
"MaxMapFeedbackI32",
i32,
PythonMapObserverI32,
MyStdStateI32
);
define_python_map_feedback!(
PythonMapFeedbackStateI64,
"MapFeedbackStateI64",
PythonMaxMapFeedbackI64,
"MaxMapFeedbackI64",
i64,
PythonMapObserverI64,
MyStdStateI64
);
define_python_map_feedback!(
PythonMapFeedbackStateU8,
"MapFeedbackStateU8",
PythonMaxMapFeedbackU8,
"MaxMapFeedbackU8",
u8,
PythonMapObserverU8,
MyStdStateU8
);
define_python_map_feedback!(
PythonMapFeedbackStateU16,
"MapFeedbackStateU16",
PythonMaxMapFeedbackU16,
"MaxMapFeedbackU16",
u16,
PythonMapObserverU16,
MyStdStateU16
);
define_python_map_feedback!(
PythonMapFeedbackStateU32,
"MapFeedbackStateU32",
PythonMaxMapFeedbackU32,
"MaxMapFeedbackU32",
u32,
PythonMapObserverU32,
MyStdStateU32
);
define_python_map_feedback!(
PythonMapFeedbackStateU64,
"MapFeedbackStateU64",
PythonMaxMapFeedbackU64,
"MaxMapFeedbackU64",
u64,
PythonMapObserverU64,
MyStdStateU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonMapFeedbackStateI8>()?;
m.add_class::<PythonMapFeedbackStateI16>()?;
m.add_class::<PythonMapFeedbackStateI32>()?;
m.add_class::<PythonMapFeedbackStateI64>()?;
m.add_class::<PythonMapFeedbackStateU8>()?;
m.add_class::<PythonMapFeedbackStateU16>()?;
m.add_class::<PythonMapFeedbackStateU32>()?;
m.add_class::<PythonMapFeedbackStateU64>()?;
m.add_class::<PythonMaxMapFeedbackI8>()?;
m.add_class::<PythonMaxMapFeedbackI16>()?;
m.add_class::<PythonMaxMapFeedbackI32>()?;
m.add_class::<PythonMaxMapFeedbackI64>()?;
m.add_class::<PythonMaxMapFeedbackU8>()?;
m.add_class::<PythonMaxMapFeedbackU16>()?;
m.add_class::<PythonMaxMapFeedbackU32>()?;
m.add_class::<PythonMaxMapFeedbackU64>()?;
Ok(())
}
}

View File

@ -666,3 +666,199 @@ where
Ok(exit_kind)
}
}
#[cfg(feature = "python")]
/// `Fuzzer` Python bindings
pub mod pybind {
use crate::corpus::QueueCorpusScheduler;
use crate::feedbacks::{CrashFeedback, MaxMapFeedback};
use crate::fuzzer::{Fuzzer, StdFuzzer};
use crate::inputs::BytesInput;
use pyo3::prelude::*;
macro_rules! define_python_fuzzer {
($type_name:ident, $struct_name:ident, $py_name:tt, $datatype:ty, $my_std_state_type_name: ident, $std_state_name: ident,
$event_manager_name: ident, $map_observer_name: ident, $max_map_feedback_py_name: ident, $executor_name: ident, $stage_tuple_name: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::executors::pybind::$executor_name;
use crate::feedbacks::map::pybind::$max_map_feedback_py_name;
use crate::observers::map::pybind::$map_observer_name;
use crate::stages::owned::pybind::$stage_tuple_name;
use crate::state::pybind::{$my_std_state_type_name, $std_state_name};
/// `StdFuzzer` with fixed generics
pub type $type_name = StdFuzzer<
QueueCorpusScheduler,
MaxMapFeedback<BytesInput, $map_observer_name, $my_std_state_type_name, $datatype>,
BytesInput,
CrashFeedback,
($map_observer_name, ()),
$my_std_state_type_name,
>;
/// Python class for StdFuzzer
#[pyclass(unsendable, name = $py_name)]
#[derive(Debug)]
pub struct $struct_name {
/// Rust wrapped StdFuzzer object
pub std_fuzzer: $type_name,
}
#[pymethods]
impl $struct_name {
#[new]
fn new(py_max_map_feedback: $max_map_feedback_py_name) -> Self {
Self {
std_fuzzer: StdFuzzer::new(
QueueCorpusScheduler::new(),
py_max_map_feedback.max_map_feedback,
CrashFeedback::new(),
),
}
}
fn fuzz_loop(
&mut self,
py_executor: &mut $executor_name,
py_state: &mut $std_state_name,
py_mgr: &mut $event_manager_name,
stage_tuple: &mut $stage_tuple_name,
) {
self.std_fuzzer
.fuzz_loop(
&mut stage_tuple.stages_owned_list,
py_executor,
&mut py_state.std_state,
py_mgr,
)
.expect("Failed to generate the initial corpus".into());
}
}
};
}
define_python_fuzzer!(
MyStdFuzzerI8,
PythonStdFuzzerI8,
"StdFuzzerI8",
i8,
MyStdStateI8,
PythonStdStateI8,
PythonEventManagerI8,
PythonMapObserverI8,
PythonMaxMapFeedbackI8,
PythonExecutorI8,
PythonStagesOwnedListI8
);
define_python_fuzzer!(
MyStdFuzzerI16,
PythonStdFuzzerI16,
"StdFuzzerI16",
i16,
MyStdStateI16,
PythonStdStateI16,
PythonEventManagerI16,
PythonMapObserverI16,
PythonMaxMapFeedbackI16,
PythonExecutorI16,
PythonStagesOwnedListI16
);
define_python_fuzzer!(
MyStdFuzzerI32,
PythonStdFuzzerI32,
"StdFuzzerI32",
i32,
MyStdStateI32,
PythonStdStateI32,
PythonEventManagerI32,
PythonMapObserverI32,
PythonMaxMapFeedbackI32,
PythonExecutorI32,
PythonStagesOwnedListI32
);
define_python_fuzzer!(
MyStdFuzzerI64,
PythonStdFuzzerI64,
"StdFuzzerI64",
i64,
MyStdStateI64,
PythonStdStateI64,
PythonEventManagerI64,
PythonMapObserverI64,
PythonMaxMapFeedbackI64,
PythonExecutorI64,
PythonStagesOwnedListI64
);
define_python_fuzzer!(
MyStdFuzzerU8,
PythonStdFuzzerU8,
"StdFuzzerU8",
u8,
MyStdStateU8,
PythonStdStateU8,
PythonEventManagerU8,
PythonMapObserverU8,
PythonMaxMapFeedbackU8,
PythonExecutorU8,
PythonStagesOwnedListU8
);
define_python_fuzzer!(
MyStdFuzzerU16,
PythonStdFuzzerU16,
"StdFuzzerU16",
u16,
MyStdStateU16,
PythonStdStateU16,
PythonEventManagerU16,
PythonMapObserverU16,
PythonMaxMapFeedbackU16,
PythonExecutorU16,
PythonStagesOwnedListU16
);
define_python_fuzzer!(
MyStdFuzzerU32,
PythonStdFuzzerU32,
"StdFuzzerU32",
u32,
MyStdStateU32,
PythonStdStateU32,
PythonEventManagerU32,
PythonMapObserverU32,
PythonMaxMapFeedbackU32,
PythonExecutorU32,
PythonStagesOwnedListU32
);
define_python_fuzzer!(
MyStdFuzzerU64,
PythonStdFuzzerU64,
"StdFuzzerU64",
u64,
MyStdStateU64,
PythonStdStateU64,
PythonEventManagerU64,
PythonMapObserverU64,
PythonMaxMapFeedbackU64,
PythonExecutorU64,
PythonStagesOwnedListU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdFuzzerI8>()?;
m.add_class::<PythonStdFuzzerI16>()?;
m.add_class::<PythonStdFuzzerI32>()?;
m.add_class::<PythonStdFuzzerI64>()?;
m.add_class::<PythonStdFuzzerU8>()?;
m.add_class::<PythonStdFuzzerU16>()?;
m.add_class::<PythonStdFuzzerU32>()?;
m.add_class::<PythonStdFuzzerU64>()?;
Ok(())
}
}

View File

@ -125,3 +125,90 @@ where
}
}
}
/// `Generator` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::generators::RandPrintablesGenerator;
use pyo3::prelude::*;
macro_rules! define_python_event_manager {
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident) => {
use crate::state::pybind::$my_std_state_type_name;
#[pyclass(unsendable, name = $py_name)]
/// Python class for RandPrintablesGenerator
#[derive(Debug)]
pub struct $struct_name {
/// Rust wrapped SimpleEventManager object
pub rand_printable_generator: RandPrintablesGenerator<$my_std_state_type_name>,
}
#[pymethods]
impl $struct_name {
#[new]
fn new(max_size: usize) -> Self {
Self {
rand_printable_generator: RandPrintablesGenerator::new(max_size),
}
}
}
};
}
define_python_event_manager!(
PythonRandPrintablesGeneratorI8,
"RandPrintablesGeneratorI8",
MyStdStateI8
);
define_python_event_manager!(
PythonRandPrintablesGeneratorI16,
"RandPrintablesGeneratorI16",
MyStdStateI16
);
define_python_event_manager!(
PythonRandPrintablesGeneratorI32,
"RandPrintablesGeneratorI32",
MyStdStateI32
);
define_python_event_manager!(
PythonRandPrintablesGeneratorI64,
"RandPrintablesGeneratorI64",
MyStdStateI64
);
define_python_event_manager!(
PythonRandPrintablesGeneratorU8,
"RandPrintablesGeneratorU8",
MyStdStateU8
);
define_python_event_manager!(
PythonRandPrintablesGeneratorU16,
"RandPrintablesGeneratorU16",
MyStdStateU16
);
define_python_event_manager!(
PythonRandPrintablesGeneratorU32,
"RandPrintablesGeneratorU32",
MyStdStateU32
);
define_python_event_manager!(
PythonRandPrintablesGeneratorU64,
"RandPrintablesGeneratorU64",
MyStdStateU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonRandPrintablesGeneratorI8>()?;
m.add_class::<PythonRandPrintablesGeneratorI16>()?;
m.add_class::<PythonRandPrintablesGeneratorI32>()?;
m.add_class::<PythonRandPrintablesGeneratorI64>()?;
m.add_class::<PythonRandPrintablesGeneratorU8>()?;
m.add_class::<PythonRandPrintablesGeneratorU16>()?;
m.add_class::<PythonRandPrintablesGeneratorU32>()?;
m.add_class::<PythonRandPrintablesGeneratorU64>()?;
Ok(())
}
}

View File

@ -314,3 +314,32 @@ pub extern "C" fn external_current_millis() -> u64 {
// TODO: use "real" time here
1000
}
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
#[pymodule]
#[pyo3(name = "libafl")]
/// Register the classes to the python module
pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> {
observers::map::pybind::register(py, m)?;
feedbacks::map::pybind::register(py, m)?;
state::pybind::register(py, m)?;
monitors::pybind::register(py, m)?;
events::pybind::register(py, m)?;
events::simple::pybind::register(py, m)?;
fuzzer::pybind::register(py, m)?;
executors::pybind::register(py, m)?;
executors::inprocess::pybind::register(py, m)?;
generators::pybind::register(py, m)?;
corpus::pybind::register(py, m)?;
corpus::ondisk::pybind::register(py, m)?;
corpus::inmemory::pybind::register(py, m)?;
corpus::cached::pybind::register(py, m)?;
bolts::rands::pybind::register(py, m)?;
stages::pybind::register(py, m)?;
stages::owned::pybind::register(py, m)?;
stages::mutational::pybind::register(py, m)?;
Ok(())
}

View File

@ -784,3 +784,104 @@ impl Default for ClientPerfMonitor {
Self::new()
}
}
/// `Monitor` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::monitors::{Monitor, SimpleMonitor};
use pyo3::prelude::*;
use super::ClientStats;
use core::time::Duration;
#[pyclass(unsendable, name = "SimpleMonitor")]
#[derive(Clone, Debug)]
/// Python class for SimpleMonitor
pub struct PythonSimpleMonitor {
/// Rust wrapped SimpleMonitor object
pub simple_monitor: SimpleMonitor<fn(String)>,
}
#[pymethods]
impl PythonSimpleMonitor {
#[new]
fn new(/*py_print_fn: PyObject */) -> Self {
// TODO: Find a fix to: closures can only be coerced to `fn` types if they
// do not capture any variables and print_fn expected to be fn pointer.
// fn printf_fn (s: String){
// Python::with_gil(|py| -> PyResult<()> {
// print_fn.call1(py, (PyUnicode::new(py, &s),));
// Ok(())
// });
// }
Self {
simple_monitor: SimpleMonitor::new(|s| println!("{}", s)),
}
}
}
#[derive(Clone, Debug)]
enum PythonMonitorWrapper {
Simple(PythonSimpleMonitor),
}
#[pyclass(unsendable, name = "Monitor")]
#[derive(Clone, Debug)]
/// EventManager Trait binding
pub struct PythonMonitor {
monitor: PythonMonitorWrapper,
}
impl PythonMonitor {
fn get_monitor(&self) -> &impl Monitor {
match &self.monitor {
PythonMonitorWrapper::Simple(py_simple_monitor) => {
&py_simple_monitor.simple_monitor
}
}
}
fn get_mut_monitor(&mut self) -> &mut impl Monitor {
match &mut self.monitor {
PythonMonitorWrapper::Simple(py_simple_monitor) => {
&mut py_simple_monitor.simple_monitor
}
}
}
}
#[pymethods]
impl PythonMonitor {
#[staticmethod]
fn new_from_simple(simple_monitor: PythonSimpleMonitor) -> Self {
Self {
monitor: PythonMonitorWrapper::Simple(simple_monitor),
}
}
}
impl Monitor for PythonMonitor {
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> {
self.get_mut_monitor().client_stats_mut()
}
fn client_stats(&self) -> &[ClientStats] {
self.get_monitor().client_stats()
}
/// Time this fuzzing run stated
fn start_time(&mut self) -> Duration {
self.get_mut_monitor().start_time()
}
fn display(&mut self, event_msg: String, sender_id: u32) {
self.get_mut_monitor().display(event_msg, sender_id);
}
}
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonSimpleMonitor>()?;
m.add_class::<PythonMonitor>()?;
Ok(())
}
}

View File

@ -769,7 +769,6 @@ where
Self { base }
}
}
/// The Multi Map Observer merge different maps into one observer
#[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")]
@ -977,3 +976,408 @@ where
self.maps.iter().flatten()
}
}
/// Exact copy of `StdMapObserver` that owns its map
/// Used for python bindings
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(bound = "T: serde::de::DeserializeOwned")]
#[allow(clippy::unsafe_derive_deserialize)]
pub struct OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
{
map: Vec<T>,
initial: T,
name: String,
}
impl<I, S, T> Observer<I, S> for OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
self.reset_map()
}
}
impl<T> Named for OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
{
#[inline]
fn name(&self) -> &str {
self.name.as_str()
}
}
impl<T> HasLen for OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
{
#[inline]
fn len(&self) -> usize {
self.map.as_slice().len()
}
}
impl<'it, T> IntoIterator for &'it OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'it, T> IntoIterator for &'it mut OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<T> MapObserver for OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Entry = T;
#[inline]
fn get(&self, pos: usize) -> &T {
&self.as_slice()[pos]
}
#[inline]
fn get_mut(&mut self, idx: usize) -> &mut T {
&mut self.as_mut_slice()[idx]
}
#[inline]
fn usable_count(&self) -> usize {
self.as_slice().len()
}
fn hash(&self) -> u64 {
hash_slice(self.as_slice())
}
#[inline]
fn initial(&self) -> T {
self.initial
}
#[inline]
fn initial_mut(&mut self) -> &mut T {
&mut self.initial
}
#[inline]
fn set_initial(&mut self, initial: T) {
self.initial = initial;
}
fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
}
impl<T> AsSlice<T> for OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[must_use]
#[inline]
fn as_slice(&self) -> &[T] {
self.map.as_slice()
}
}
impl<T> AsMutSlice<T> for OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[must_use]
#[inline]
fn as_mut_slice(&mut self) -> &mut [T] {
self.map.as_mut_slice()
}
}
impl<T> OwnedMapObserver<T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
{
/// Creates a new [`MapObserver`] with an owned map
#[must_use]
pub fn new(name: &'static str, map: Vec<T>) -> Self {
let initial = if map.is_empty() { T::default() } else { map[0] };
Self {
map: map,
name: name.to_string(),
initial,
}
}
}
/// `MapObserver` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::bolts::{tuples::Named, HasLen};
use crate::observers::{map::OwnedMapObserver, MapObserver, Observer};
use crate::Error;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
macro_rules! define_python_map_observer {
($struct_name:ident, $py_name:tt, $struct_name_trait:ident, $py_name_trait:tt, $datatype:ty, $wrapper_name: ident) => {
#[pyclass(unsendable, name = $py_name)]
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map)
pub struct $struct_name {
/// Rust wrapped OwnedMapObserver object
pub owned_map_observer: OwnedMapObserver<$datatype>,
}
#[pymethods]
impl $struct_name {
#[new]
fn new(name: String, map: Vec<$datatype>) -> Self {
Self {
//TODO: Not leak memory
owned_map_observer: OwnedMapObserver::new(
Box::leak(name.into_boxed_str()),
map,
),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
enum $wrapper_name {
Owned($struct_name),
}
// Should not be exposed to user
#[pyclass(unsendable, name = $py_name_trait)]
#[derive(Serialize, Deserialize, Debug, Clone)]
/// MapObserver + Observer Trait binding
pub struct $struct_name_trait {
map_observer: $wrapper_name,
}
#[pymethods]
impl $struct_name_trait {
#[staticmethod]
fn new_from_owned(owned_map_observer: $struct_name) -> Self {
Self {
map_observer: $wrapper_name::Owned(owned_map_observer),
}
}
}
impl MapObserver for $struct_name_trait {
type Entry = $datatype;
#[inline]
fn get(&self, idx: usize) -> &$datatype {
match &self.map_observer {
$wrapper_name::Owned(map_observer) => {
&map_observer.owned_map_observer.get(idx)
}
}
}
#[inline]
fn get_mut(&mut self, idx: usize) -> &mut $datatype {
match &mut self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.get_mut(idx)
}
}
}
#[inline]
fn usable_count(&self) -> usize {
match &self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.usable_count()
}
}
}
fn hash(&self) -> u64 {
match &self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.hash()
}
}
}
#[inline]
fn initial(&self) -> $datatype {
match &self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.initial()
}
}
}
#[inline]
fn initial_mut(&mut self) -> &mut $datatype {
match &mut self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.initial_mut()
}
}
}
#[inline]
fn set_initial(&mut self, initial: $datatype) {
match &mut self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.set_initial(initial);
}
}
}
fn to_vec(&self) -> Vec<$datatype> {
match &self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.to_vec()
}
}
}
}
impl Named for $struct_name_trait {
#[inline]
fn name(&self) -> &str {
match &self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.name()
}
}
}
}
impl HasLen for $struct_name_trait {
#[inline]
fn len(&self) -> usize {
match &self.map_observer {
$wrapper_name::Owned(map_observer) => map_observer.owned_map_observer.len(),
}
}
}
impl<I, S> Observer<I, S> for $struct_name_trait
where
Self: MapObserver,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
match &mut self.map_observer {
$wrapper_name::Owned(map_observer) => {
map_observer.owned_map_observer.pre_exec(_state, _input)
}
}
}
}
};
}
define_python_map_observer!(
PythonOwnedMapObserverI8,
"OwnedMapObserverI8",
PythonMapObserverI8,
"MapObserverI8",
i8,
PythonMapObserverWrapperI8
);
define_python_map_observer!(
PythonOwnedMapObserverI16,
"OwnedMapObserverI16",
PythonMapObserverI16,
"MapObserverI16",
i16,
PythonMapObserverWrapperI16
);
define_python_map_observer!(
PythonOwnedMapObserverI32,
"OwnedMapObserverI32",
PythonMapObserverI32,
"MapObserverI32",
i32,
PythonMapObserverWrapperI32
);
define_python_map_observer!(
PythonOwnedMapObserverI64,
"OwnedMapObserverI64",
PythonMapObserverI64,
"MapObserverI64",
i64,
PythonMapObserverWrapperI64
);
define_python_map_observer!(
PythonOwnedMapObserverU8,
"OwnedMapObserverU8",
PythonMapObserverU8,
"MapObserverU8",
u8,
PythonMapObserverWrapperU8
);
define_python_map_observer!(
PythonOwnedMapObserverU16,
"OwnedMapObserverU16",
PythonMapObserverU16,
"MapObserverU16",
u16,
PythonMapObserverWrapperU16
);
define_python_map_observer!(
PythonOwnedMapObserverU32,
"OwnedMapObserverU32",
PythonMapObserverU32,
"MapObserverU32",
u32,
PythonMapObserverWrapperU32
);
define_python_map_observer!(
PythonOwnedMapObserverU64,
"OwnedMapObserverU64",
PythonMapObserverU64,
"MapObserverU64",
u64,
PythonMapObserverWrapperU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonOwnedMapObserverI8>()?;
m.add_class::<PythonMapObserverI8>()?;
m.add_class::<PythonOwnedMapObserverI16>()?;
m.add_class::<PythonMapObserverI16>()?;
m.add_class::<PythonOwnedMapObserverI32>()?;
m.add_class::<PythonMapObserverI32>()?;
m.add_class::<PythonOwnedMapObserverI64>()?;
m.add_class::<PythonMapObserverI64>()?;
m.add_class::<PythonOwnedMapObserverU8>()?;
m.add_class::<PythonMapObserverU8>()?;
m.add_class::<PythonOwnedMapObserverU16>()?;
m.add_class::<PythonMapObserverU16>()?;
m.add_class::<PythonOwnedMapObserverU32>()?;
m.add_class::<PythonMapObserverU32>()?;
m.add_class::<PythonOwnedMapObserverU64>()?;
m.add_class::<PythonMapObserverU64>()?;
Ok(())
}
}

View File

@ -256,3 +256,190 @@ where
.deinit(fuzzer, state, event_mgr, executor.observers_mut())
}
}
/// `Stage` Python bindings
#[cfg(feature = "python")]
pub mod pybind {
use crate::impl_asany;
use crate::stages::Stage;
use crate::Error;
use pyo3::prelude::*;
use super::owned::AnyStage;
macro_rules! define_python_stage {
($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $std_havoc_mutations_stage_name: ident, $my_std_state_type_name: ident,
$my_std_fuzzer_type_name: ident, $executor_name: ident, $event_manager_name: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::executors::pybind::$executor_name;
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
use crate::stages::mutational::pybind::$std_havoc_mutations_stage_name;
use crate::state::pybind::$my_std_state_type_name;
#[derive(Debug)]
enum $wrapper_name {
StdHavocMutations(*mut $std_havoc_mutations_stage_name),
}
/// Stage Trait binding
#[pyclass(unsendable, name = $py_name_trait)]
#[derive(Debug)]
pub struct $struct_name_trait {
stage: $wrapper_name,
}
#[pymethods]
impl $struct_name_trait {
#[staticmethod]
fn new_from_std_scheduled(
py_std_havoc_mutations_stage: &mut $std_havoc_mutations_stage_name,
) -> Self {
Self {
stage: $wrapper_name::StdHavocMutations(py_std_havoc_mutations_stage),
}
}
}
impl
Stage<
$executor_name,
$event_manager_name,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
> for $struct_name_trait
{
#[inline]
#[allow(clippy::let_and_return)]
fn perform(
&mut self,
fuzzer: &mut $my_std_fuzzer_type_name,
executor: &mut $executor_name,
state: &mut $my_std_state_type_name,
manager: &mut $event_manager_name,
corpus_idx: usize,
) -> Result<(), Error> {
unsafe {
match self.stage {
$wrapper_name::StdHavocMutations(py_std_havoc_mutations_stage) => {
(*py_std_havoc_mutations_stage)
.std_mutational_stage
.perform(fuzzer, executor, state, manager, corpus_idx)
}
}
}
}
}
impl_asany!($struct_name_trait);
impl
AnyStage<
$executor_name,
$event_manager_name,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
> for $struct_name_trait
{
}
};
}
define_python_stage!(
PythonStageI8,
"StageI8",
PythonStageWrapperI8,
PythonStdScheduledHavocMutationsStageI8,
MyStdStateI8,
MyStdFuzzerI8,
PythonExecutorI8,
PythonEventManagerI8
);
define_python_stage!(
PythonStageI16,
"StageI16",
PythonStageWrapperI16,
PythonStdScheduledHavocMutationsStageI16,
MyStdStateI16,
MyStdFuzzerI16,
PythonExecutorI16,
PythonEventManagerI16
);
define_python_stage!(
PythonStageI32,
"StageI32",
PythonStageWrapperI32,
PythonStdScheduledHavocMutationsStageI32,
MyStdStateI32,
MyStdFuzzerI32,
PythonExecutorI32,
PythonEventManagerI32
);
define_python_stage!(
PythonStageI64,
"StageI64",
PythonStageWrapperI64,
PythonStdScheduledHavocMutationsStageI64,
MyStdStateI64,
MyStdFuzzerI64,
PythonExecutorI64,
PythonEventManagerI64
);
define_python_stage!(
PythonStageU8,
"StageU8",
PythonStageWrapperU8,
PythonStdScheduledHavocMutationsStageU8,
MyStdStateU8,
MyStdFuzzerU8,
PythonExecutorU8,
PythonEventManagerU8
);
define_python_stage!(
PythonStageU16,
"StageU16",
PythonStageWrapperU16,
PythonStdScheduledHavocMutationsStageU16,
MyStdStateU16,
MyStdFuzzerU16,
PythonExecutorU16,
PythonEventManagerU16
);
define_python_stage!(
PythonStageU32,
"StageU32",
PythonStageWrapperU32,
PythonStdScheduledHavocMutationsStageU32,
MyStdStateU32,
MyStdFuzzerU32,
PythonExecutorU32,
PythonEventManagerU32
);
define_python_stage!(
PythonStageU64,
"StageU64",
PythonStageWrapperU64,
PythonStdScheduledHavocMutationsStageU64,
MyStdStateU64,
MyStdFuzzerU64,
PythonExecutorU64,
PythonEventManagerU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStageI8>()?;
m.add_class::<PythonStageI16>()?;
m.add_class::<PythonStageI32>()?;
m.add_class::<PythonStageI64>()?;
m.add_class::<PythonStageU8>()?;
m.add_class::<PythonStageU16>()?;
m.add_class::<PythonStageU32>()?;
m.add_class::<PythonStageU64>()?;
Ok(())
}
}

View File

@ -161,3 +161,163 @@ where
}
}
}
#[cfg(feature = "python")]
/// `StdMutationalStage` Python bindings
pub mod pybind {
use crate::bolts::tuples::tuple_list_type;
use crate::inputs::BytesInput;
pub use crate::mutators::mutations::*;
pub use crate::mutators::mutations::*;
use crate::mutators::{havoc_mutations, StdScheduledMutator};
use crate::stages::StdMutationalStage;
use pyo3::prelude::*;
type HavocMutationsType = tuple_list_type!(
BitFlipMutator,
ByteFlipMutator,
ByteIncMutator,
ByteDecMutator,
ByteNegMutator,
ByteRandMutator,
ByteAddMutator,
WordAddMutator,
DwordAddMutator,
QwordAddMutator,
ByteInterestingMutator,
WordInterestingMutator,
DwordInterestingMutator,
BytesDeleteMutator,
BytesDeleteMutator,
BytesDeleteMutator,
BytesDeleteMutator,
BytesExpandMutator,
BytesInsertMutator,
BytesRandInsertMutator,
BytesSetMutator,
BytesRandSetMutator,
BytesCopyMutator,
BytesInsertCopyMutator,
BytesSwapMutator,
CrossoverInsertMutator,
CrossoverReplaceMutator,
);
macro_rules! define_python_std_mutational_stage {
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, $executor_name: ident, $event_manager_name: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::executors::pybind::$executor_name;
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
use crate::state::pybind::$my_std_state_type_name;
#[pyclass(unsendable, name = $py_name)]
#[derive(Debug)]
/// Python class for StdMutationalStage
pub struct $struct_name {
/// Rust wrapped StdMutationalStage object
pub std_mutational_stage: StdMutationalStage<
$executor_name,
$event_manager_name,
BytesInput,
StdScheduledMutator<BytesInput, HavocMutationsType, $my_std_state_type_name>,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
>,
}
#[pymethods]
impl $struct_name {
#[staticmethod]
fn new_from_scheduled_havoc_mutations() -> Self {
Self {
std_mutational_stage: StdMutationalStage::new(StdScheduledMutator::new(
havoc_mutations(),
)),
}
}
}
};
}
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageI8,
"StdScheduledHavocMutationsStageI8",
MyStdStateI8,
MyStdFuzzerI8,
PythonExecutorI8,
PythonEventManagerI8
);
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageI16,
"StdScheduledHavocMutationsStageI16",
MyStdStateI16,
MyStdFuzzerI16,
PythonExecutorI16,
PythonEventManagerI16
);
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageI32,
"StdScheduledHavocMutationsStageI32",
MyStdStateI32,
MyStdFuzzerI32,
PythonExecutorI32,
PythonEventManagerI32
);
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageI64,
"StdScheduledHavocMutationsStageI64",
MyStdStateI64,
MyStdFuzzerI64,
PythonExecutorI64,
PythonEventManagerI64
);
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageU8,
"StdScheduledHavocMutationsStageU8",
MyStdStateU8,
MyStdFuzzerU8,
PythonExecutorU8,
PythonEventManagerU8
);
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageU16,
"StdScheduledHavocMutationsStageU16",
MyStdStateU16,
MyStdFuzzerU16,
PythonExecutorU16,
PythonEventManagerU16
);
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageU32,
"StdScheduledHavocMutationsStageU32",
MyStdStateU32,
MyStdFuzzerU32,
PythonExecutorU32,
PythonEventManagerU32
);
define_python_std_mutational_stage!(
PythonStdScheduledHavocMutationsStageU64,
"StdScheduledHavocMutationsStageU64",
MyStdStateU64,
MyStdFuzzerU64,
PythonExecutorU64,
PythonEventManagerU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdScheduledHavocMutationsStageI8>()?;
m.add_class::<PythonStdScheduledHavocMutationsStageI16>()?;
m.add_class::<PythonStdScheduledHavocMutationsStageI32>()?;
m.add_class::<PythonStdScheduledHavocMutationsStageI64>()?;
m.add_class::<PythonStdScheduledHavocMutationsStageU8>()?;
m.add_class::<PythonStdScheduledHavocMutationsStageU16>()?;
m.add_class::<PythonStdScheduledHavocMutationsStageU32>()?;
m.add_class::<PythonStdScheduledHavocMutationsStageU64>()?;
Ok(())
}
}

View File

@ -42,3 +42,147 @@ impl<E, EM, S, Z> StagesOwnedList<E, EM, S, Z> {
Self { list }
}
}
#[cfg(feature = "python")]
/// `StagesOwnedList` Python bindings
pub mod pybind {
use crate::stages::owned::StagesOwnedList;
use pyo3::prelude::*;
macro_rules! define_python_stage_owned_list {
($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, $event_manager_name: ident,
$executor_name: ident, $stage_name: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::executors::pybind::$executor_name;
use crate::fuzzer::pybind::$my_std_fuzzer_type_name;
use crate::stages::pybind::$stage_name;
use crate::state::pybind::$my_std_state_type_name;
#[pyclass(unsendable, name = $py_name)]
/// Python class for StagesOwnedList
#[allow(missing_debug_implementations)]
pub struct $struct_name {
/// Rust wrapped StagesOwnedList object
pub stages_owned_list: StagesOwnedList<
$executor_name,
$event_manager_name,
$my_std_state_type_name,
$my_std_fuzzer_type_name,
>,
}
#[pymethods]
impl $struct_name {
//TODO: Add new from list
#[new]
fn new(stage: &$stage_name) -> Self {
// TODO: Be safe
unsafe {
Self {
stages_owned_list: StagesOwnedList {
list: vec![Box::new(std::mem::transmute_copy::<
$stage_name,
$stage_name,
>(stage))],
},
}
}
}
}
};
}
define_python_stage_owned_list!(
PythonStagesOwnedListI8,
"StagesOwnedListI8",
MyStdStateI8,
MyStdFuzzerI8,
PythonEventManagerI8,
PythonExecutorI8,
PythonStageI8
);
define_python_stage_owned_list!(
PythonStagesOwnedListI16,
"StagesOwnedListI16",
MyStdStateI16,
MyStdFuzzerI16,
PythonEventManagerI16,
PythonExecutorI16,
PythonStageI16
);
define_python_stage_owned_list!(
PythonStagesOwnedListI32,
"StagesOwnedListI32",
MyStdStateI32,
MyStdFuzzerI32,
PythonEventManagerI32,
PythonExecutorI32,
PythonStageI32
);
define_python_stage_owned_list!(
PythonStagesOwnedListI64,
"StagesOwnedListI64",
MyStdStateI64,
MyStdFuzzerI64,
PythonEventManagerI64,
PythonExecutorI64,
PythonStageI64
);
define_python_stage_owned_list!(
PythonStagesOwnedListU8,
"StagesOwnedListU8",
MyStdStateU8,
MyStdFuzzerU8,
PythonEventManagerU8,
PythonExecutorU8,
PythonStageU8
);
define_python_stage_owned_list!(
PythonStagesOwnedListU16,
"StagesOwnedListU16",
MyStdStateU16,
MyStdFuzzerU16,
PythonEventManagerU16,
PythonExecutorU16,
PythonStageU16
);
define_python_stage_owned_list!(
PythonStagesOwnedListU32,
"StagesOwnedListU32",
MyStdStateU32,
MyStdFuzzerU32,
PythonEventManagerU32,
PythonExecutorU32,
PythonStageU32
);
define_python_stage_owned_list!(
PythonStagesOwnedListU64,
"StagesOwnedListU64",
MyStdStateU64,
MyStdFuzzerU64,
PythonEventManagerU64,
PythonExecutorU64,
PythonStageU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStagesOwnedListI8>()?;
m.add_class::<PythonStagesOwnedListI16>()?;
m.add_class::<PythonStagesOwnedListI32>()?;
m.add_class::<PythonStagesOwnedListI64>()?;
m.add_class::<PythonStagesOwnedListU8>()?;
m.add_class::<PythonStagesOwnedListU16>()?;
m.add_class::<PythonStagesOwnedListU32>()?;
m.add_class::<PythonStagesOwnedListU64>()?;
Ok(())
}
}

View File

@ -638,3 +638,188 @@ where
&mut self.stability
}
}
#[cfg(feature = "python")]
/// `State` Python bindings
pub mod pybind {
use crate::bolts::rands::pybind::PythonRand;
use crate::bolts::tuples::tuple_list;
use crate::corpus::pybind::PythonCorpus;
use crate::feedbacks::map::MapFeedbackState;
use crate::inputs::BytesInput;
use crate::state::StdState;
use pyo3::prelude::*;
macro_rules! define_python_state {
($type_name:ident, $struct_name:ident, $py_name:tt, $datatype:ty, $py_map_feedback_state_name:ident, $event_manager_name: ident,
$fuzzer_name: ident, $executor_name: ident, $rand_printable_generator: ident) => {
use crate::events::pybind::$event_manager_name;
use crate::executors::pybind::$executor_name;
use crate::feedbacks::map::pybind::$py_map_feedback_state_name;
use crate::fuzzer::pybind::$fuzzer_name;
use crate::generators::pybind::$rand_printable_generator;
/// `StdState` with fixed generics
pub type $type_name = StdState<
PythonCorpus,
(MapFeedbackState<$datatype>, ()),
BytesInput,
PythonRand,
PythonCorpus,
>;
#[pyclass(unsendable, name = $py_name)]
#[derive(Debug)]
/// Python class for StdState
pub struct $struct_name {
/// Rust wrapped StdState object
pub std_state: $type_name,
}
#[pymethods]
impl $struct_name {
#[new]
fn new(
py_rand: PythonRand,
corpus: PythonCorpus,
solutions: PythonCorpus,
py_map_feedback_state: $py_map_feedback_state_name,
) -> Self {
Self {
std_state: StdState::new(
py_rand,
corpus,
solutions,
tuple_list!(py_map_feedback_state.map_feedback_state),
),
}
}
fn generate_initial_inputs(
&mut self,
py_fuzzer: &mut $fuzzer_name,
py_executor: &mut $executor_name,
py_generator: &mut $rand_printable_generator,
py_mgr: &mut $event_manager_name,
num: usize,
) {
self.std_state
.generate_initial_inputs(
&mut py_fuzzer.std_fuzzer,
py_executor,
&mut py_generator.rand_printable_generator,
py_mgr,
num,
)
.expect("Failed to generate the initial corpus".into());
}
}
};
}
define_python_state!(
MyStdStateI8,
PythonStdStateI8,
"StdStateI8",
i8,
PythonMapFeedbackStateI8,
PythonEventManagerI8,
PythonStdFuzzerI8,
PythonExecutorI8,
PythonRandPrintablesGeneratorI8
);
define_python_state!(
MyStdStateI16,
PythonStdStateI16,
"StdStateI16",
i16,
PythonMapFeedbackStateI16,
PythonEventManagerI16,
PythonStdFuzzerI16,
PythonExecutorI16,
PythonRandPrintablesGeneratorI16
);
define_python_state!(
MyStdStateI32,
PythonStdStateI32,
"StdStateI32",
i32,
PythonMapFeedbackStateI32,
PythonEventManagerI32,
PythonStdFuzzerI32,
PythonExecutorI32,
PythonRandPrintablesGeneratorI32
);
define_python_state!(
MyStdStateI64,
PythonStdStateI64,
"StdStateI64",
i64,
PythonMapFeedbackStateI64,
PythonEventManagerI64,
PythonStdFuzzerI64,
PythonExecutorI64,
PythonRandPrintablesGeneratorI64
);
define_python_state!(
MyStdStateU8,
PythonStdStateU8,
"StdStateU8",
u8,
PythonMapFeedbackStateU8,
PythonEventManagerU8,
PythonStdFuzzerU8,
PythonExecutorU8,
PythonRandPrintablesGeneratorU8
);
define_python_state!(
MyStdStateU16,
PythonStdStateU16,
"StdStateU16",
u16,
PythonMapFeedbackStateU16,
PythonEventManagerU16,
PythonStdFuzzerU16,
PythonExecutorU16,
PythonRandPrintablesGeneratorU16
);
define_python_state!(
MyStdStateU32,
PythonStdStateU32,
"StdStateU32",
u32,
PythonMapFeedbackStateU32,
PythonEventManagerU32,
PythonStdFuzzerU32,
PythonExecutorU32,
PythonRandPrintablesGeneratorU32
);
define_python_state!(
MyStdStateU64,
PythonStdStateU64,
"StdStateU64",
u64,
PythonMapFeedbackStateU64,
PythonEventManagerU64,
PythonStdFuzzerU64,
PythonExecutorU64,
PythonRandPrintablesGeneratorU64
);
/// Register the classes to the python module
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PythonStdStateI8>()?;
m.add_class::<PythonStdStateI16>()?;
m.add_class::<PythonStdStateI32>()?;
m.add_class::<PythonStdStateI64>()?;
m.add_class::<PythonStdStateU8>()?;
m.add_class::<PythonStdStateU16>()?;
m.add_class::<PythonStdStateU32>()?;
m.add_class::<PythonStdStateU64>()?;
Ok(())
}
}