Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libafl_nyx: Allow custom input buffer size to be passed to NyxHelper #1960

Merged
merged 9 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions fuzzers/nyx_libxml2_parallel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use libafl_bolts::{
shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list,
};
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper};
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};

fn main() {
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
Expand All @@ -32,21 +32,17 @@ fn main() {

// region: fuzzer start function
let mut run_client = |state: Option<_>, mut restarting_mgr, core_id: CoreId| {
// nyx shared dir, created by nyx-fuzz/packer/packer/nyx_packer.py
let share_dir = Path::new("/tmp/nyx_libxml2/");
let cpu_id = core_id.0.try_into().unwrap();
let parallel_mode = true;
// nyx stuff
let mut helper = NyxHelper::new(
share_dir,
cpu_id,
true,
parallel_mode,
Some(parent_cpu_id.0.try_into().unwrap()),
)
.unwrap();
let observer =
unsafe { StdMapObserver::from_mut_ptr("trace", helper.trace_bits, helper.map_size) };
let settings = NyxSettings::builder()
.cpu_id(0)
.snap_mode(true)
.parallel_mode(true)
.parent_cpu_id(Some(parent_cpu_id.0 as u32))
.build();
let helper = NyxHelper::new("/tmp/nyx_libxml2/", settings).unwrap();
let observer = unsafe {
StdMapObserver::from_mut_ptr("trace", helper.bitmap_buffer, helper.bitmap_size)
};

let input = BytesInput::new(b"22".to_vec());
let rand = StdRand::new();
Expand All @@ -60,7 +56,7 @@ fn main() {
let mut feedback = MaxMapFeedback::new(&observer);
let mut objective = CrashFeedback::new();
let scheduler = RandScheduler::new();
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
let mut executor = NyxExecutor::new(helper, tuple_list!(observer));

// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {
Expand Down
20 changes: 11 additions & 9 deletions fuzzers/nyx_libxml2_standalone/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::{Path, PathBuf};
use std::path::PathBuf;

use libafl::{
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus, Testcase},
Expand All @@ -17,17 +17,19 @@ use libafl_bolts::{
rands::{RandomSeed, StdRand},
tuples::tuple_list,
};
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper};
use libafl_nyx::{executor::NyxExecutor, helper::NyxHelper, settings::NyxSettings};

fn main() {
let share_dir = Path::new("/tmp/nyx_libxml2/");
let cpu_id = 0;
let parallel_mode = false;

// nyx stuff
let mut helper = NyxHelper::new(share_dir, cpu_id, true, parallel_mode, None).unwrap();
let settings = NyxSettings::builder()
.cpu_id(0)
.snap_mode(true)
.parallel_mode(false)
.parent_cpu_id(None)
.build();
let helper = NyxHelper::new("/tmp/nyx_libxml2/", settings).unwrap();
let observer =
unsafe { StdMapObserver::from_mut_ptr("trace", helper.trace_bits, helper.map_size) };
unsafe { StdMapObserver::from_mut_ptr("trace", helper.bitmap_buffer, helper.bitmap_size) };

let input = BytesInput::new(b"22".to_vec());
let rand = StdRand::new();
Expand All @@ -50,7 +52,7 @@ fn main() {
let monitor = TuiMonitor::new(ui);

let mut mgr = SimpleEventManager::new(monitor);
let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap();
let mut executor = NyxExecutor::new(helper, tuple_list!(observer));
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator));

Expand Down
4 changes: 3 additions & 1 deletion libafl_nyx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ categories = ["development-tools::testing", "emulators", "embedded", "os", "no-s
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[target.'cfg(target_os = "linux")'.dependencies]
libnyx = {git = "https://github.com/nyx-fuzz/libnyx.git",rev = "acaf7f6"}
libnyx = { git = "https://github.com/nyx-fuzz/libnyx.git", rev = "acaf7f6" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we upgrade this to the latest rev?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started working on using the latest libnyx revision here: https://github.com/l4yton/LibAFL/tree/libnyx_latest, but will have to do some more testing. Documentation and example fuzzers would also have to be updated since NyxProcess gets the config directly from the config.ron file in the share_dir.

libafl = { path = "../libafl", version = "0.11.2", features = ["std", "libafl_derive", "frida_cli" ]}
libafl_bolts = { path = "../libafl_bolts", version = "0.11.2", features = ["std", "libafl_derive", "frida_cli" ]}
libafl_targets = { path = "../libafl_targets", version = "0.11.2", features = ["std", "sancov_cmplog"] }

typed-builder = "0.18.1"
75 changes: 35 additions & 40 deletions libafl_nyx/src/executor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fmt::Debug, marker::PhantomData};
use std::marker::PhantomData;

use libafl::{
executors::{Executor, ExitKind, HasObservers},
Expand All @@ -13,39 +13,31 @@ use libnyx::NyxReturnValue;
use crate::helper::NyxHelper;

/// executor for nyx standalone mode
pub struct NyxExecutor<'a, S, OT> {
pub struct NyxExecutor<S, OT> {
/// implement nyx function
pub helper: &'a mut NyxHelper,
pub helper: NyxHelper,
/// observers
observers: OT,
/// phantom data to keep generic type <I,S>
phantom: PhantomData<S>,
}

impl<'a, S, OT> Debug for NyxExecutor<'a, S, OT> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NyxInprocessExecutor")
.field("helper", &self.helper)
.finish()
}
}

impl<'a, S, OT> UsesState for NyxExecutor<'a, S, OT>
impl<S, OT> UsesState for NyxExecutor<S, OT>
where
S: State,
{
type State = S;
}

impl<'a, S, OT> UsesObservers for NyxExecutor<'a, S, OT>
impl<S, OT> UsesObservers for NyxExecutor<S, OT>
where
OT: ObserversTuple<S>,
S: State,
{
type Observers = OT;
}

impl<'a, EM, S, Z, OT> Executor<EM, Z> for NyxExecutor<'a, S, OT>
impl<EM, S, Z, OT> Executor<EM, Z> for NyxExecutor<S, OT>
where
EM: UsesState<State = S>,
S: State + HasExecutions,
Expand All @@ -60,56 +52,59 @@ where
input: &Self::Input,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
let input_owned = input.target_bytes();
let input = input_owned.as_slice();
self.helper.nyx_process.set_input(
input,
input
.len()
.try_into()
.expect("Inputs larger than 4GB not supported"),
);

let bytes = input.target_bytes();
let buffer = bytes.as_slice();
let size = u32::try_from(buffer.len())
.map_err(|_| Error::unsupported("Inputs larger than 4GB are not supported"))?;

self.helper.nyx_process.set_input(buffer, size);

// exec will take care of trace_bits, so no need to reset
let ret_val = self.helper.nyx_process.exec();
match ret_val {
match self.helper.nyx_process.exec() {
NyxReturnValue::Normal => Ok(ExitKind::Ok),
NyxReturnValue::Crash | NyxReturnValue::Asan => Ok(ExitKind::Crash),
NyxReturnValue::Timeout => Ok(ExitKind::Timeout),
NyxReturnValue::InvalidWriteToPayload => Err(libafl::Error::illegal_state(
"FixMe: Nyx InvalidWriteToPayload handler is missing",
)),
NyxReturnValue::Error => Err(libafl::Error::illegal_state(
"Error: Nyx runtime error has occurred...",
)),
NyxReturnValue::InvalidWriteToPayload => {
self.helper.nyx_process.shutdown();
Err(Error::illegal_state(
"FixMe: Nyx InvalidWriteToPayload handler is missing",
))
}
NyxReturnValue::Error => {
self.helper.nyx_process.shutdown();
Err(Error::illegal_state("Nyx runtime error has occurred"))
}
NyxReturnValue::IoError => {
// todo! *stop_soon_p = 0
Err(libafl::Error::unknown("Error: QEMU-nyx died..."))
self.helper.nyx_process.shutdown();
Err(Error::unknown("QEMU-nyx died"))
}
NyxReturnValue::Abort => {
self.helper.nyx_process.shutdown();
Err(libafl::Error::shutting_down())
Err(Error::shutting_down())
}
}
}
}

impl<'a, S, OT> NyxExecutor<'a, S, OT> {
pub fn new(helper: &'a mut NyxHelper, observers: OT) -> Result<Self, Error> {
Ok(Self {
impl<S, OT> NyxExecutor<S, OT> {
pub fn new(helper: NyxHelper, observers: OT) -> Self {
Self {
helper,
observers,
phantom: PhantomData,
})
}
}

/// convert `trace_bits` ptr into real trace map
pub fn trace_bits(self) -> &'static mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.helper.trace_bits, self.helper.real_map_size) }
unsafe {
std::slice::from_raw_parts_mut(self.helper.bitmap_buffer, self.helper.bitmap_size)
}
}
}

impl<'a, S, OT> HasObservers for NyxExecutor<'a, S, OT>
impl<S, OT> HasObservers for NyxExecutor<S, OT>
where
S: State,
OT: ObserversTuple<S>,
Expand Down
Loading
Loading