Skip to content

Commit

Permalink
Add nyx_launcher example fuzzer
Browse files Browse the repository at this point in the history
  • Loading branch information
d0ntrash committed Jan 10, 2025
1 parent 1f9f1f8 commit bce3474
Show file tree
Hide file tree
Showing 7 changed files with 632 additions and 0 deletions.
36 changes: 36 additions & 0 deletions fuzzers/full_system/nyx_launcher/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "nyx_launcher"
version = "0.14.1"
authors = ["Konstantin Bücheler <[email protected]>"]
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["std"]
std = []

## Build with a simple event manager instead of Launcher - don't fork, and crash after the first bug.
simplemgr = []

[profile.release]
lto = true
codegen-units = 1
opt-level = 3
debug = true

[build-dependencies]
vergen = { version = "8.2.1", features = ["build", "cargo", "git", "gitcl", "rustc", "si"] }

[dependencies]
clap = { version = "4.5.18", features = ["derive", "string"] }
libafl = { path = "../../../libafl", features = ["tui_monitor"] }
libafl_bolts = { path = "../../../libafl_bolts", features = [
"errors_backtrace",
] }
libafl_nyx = { path = "../../../libafl_nyx/"}
log = {version = "0.4.20" }
nix = { version = "0.29.0", features = ["fs"] }
rangemap = { version = "1.5.1" }
readonly = { version = "0.2.12" }
typed-builder = { version = "0.20.0" }
11 changes: 11 additions & 0 deletions fuzzers/full_system/nyx_launcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# nyx_launcher

Example fuzzer based on `qemu_launcher` but for Nyx.

## Run the fuzzer

Run with an existing nyx shared dir:

```
cargo run -- --input input/ --output output/ --share /tmp/shareddir/ --buffer-size 4096 --cores 0-1 -v --cmplog-cores 1
```
42 changes: 42 additions & 0 deletions fuzzers/full_system/nyx_launcher/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use libafl::{
corpus::{InMemoryOnDiskCorpus, OnDiskCorpus},
events::ClientDescription,
inputs::BytesInput,
monitors::Monitor,
state::StdState,
Error,
};
use libafl_bolts::rands::StdRand;

use crate::{
instance::{ClientMgr, Instance},
options::FuzzerOptions,
};

#[allow(clippy::module_name_repetitions)]
pub type ClientState =
StdState<BytesInput, InMemoryOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>;

pub struct Client<'a> {
options: &'a FuzzerOptions,
}

impl<'a> Client<'a> {
pub fn new(options: &FuzzerOptions) -> Client {
Client { options }
}

pub fn run<M: Monitor>(
&self,
state: Option<ClientState>,
mgr: ClientMgr<M>,
client_description: ClientDescription,
) -> Result<(), Error> {
let instance = Instance::builder()
.options(self.options)
.mgr(mgr)
.client_description(client_description);

instance.build().run(state)
}
}
152 changes: 152 additions & 0 deletions fuzzers/full_system/nyx_launcher/src/fuzzer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use std::{
cell::RefCell,
fs::{File, OpenOptions},
io::{self, Write},
};

use clap::Parser;

use libafl::events::{
ClientDescription, EventConfig, Launcher, LlmpEventManager, LlmpRestartingEventManager,
MonitorTypedEventManager,
};
use libafl::{
monitors::{tui::TuiMonitor, Monitor, MultiMonitor},
Error,
};

use libafl_bolts::shmem::{ShMemProvider, StdShMemProvider};
use libafl_bolts::{
core_affinity::CoreId, current_time, llmp::LlmpBroker, staterestore::StateRestorer,
tuples::tuple_list,
};
#[cfg(unix)]
use {
nix::unistd::dup,
std::os::unix::io::{AsRawFd, FromRawFd},
};

use crate::{client::Client, options::FuzzerOptions};

pub struct Fuzzer {
options: FuzzerOptions,
}

impl Fuzzer {
pub fn new() -> Fuzzer {
let options = FuzzerOptions::parse();
options.validate();
Fuzzer { options }
}

pub fn fuzz(&self) -> Result<(), Error> {
if self.options.tui {
let monitor = TuiMonitor::builder()
.title("Nyx Launcher")
.version("0.14.1")
.enhanced_graphics(true)
.build();
self.launch(monitor)
} else {
let log = self.options.log.as_ref().and_then(|l| {
OpenOptions::new()
.append(true)
.create(true)
.open(l)
.ok()
.map(RefCell::new)
});

#[cfg(unix)]
let stdout_cpy = RefCell::new(unsafe {
let new_fd = dup(io::stdout().as_raw_fd()).unwrap();
File::from_raw_fd(new_fd)
});

// The stats reporter for the broker
let monitor = MultiMonitor::new(|s| {
#[cfg(unix)]
writeln!(stdout_cpy.borrow_mut(), "{s}").unwrap();
#[cfg(windows)]
println!("{s}");

if let Some(log) = &log {
writeln!(log.borrow_mut(), "{:?} {}", current_time(), s).unwrap();
}
});
self.launch(monitor)
}
}

fn launch<M>(&self, monitor: M) -> Result<(), Error>
where
M: Monitor + Clone,
{
// The shared memory allocator
let mut shmem_provider = StdShMemProvider::new()?;

/* If we are running in verbose, don't provide a replacement stdout, otherwise, use /dev/null */
let stdout = if self.options.verbose {
None
} else {
Some("/dev/null")
};

let client = Client::new(&self.options);

if self.options.rerun_input.is_some() {
// If we want to rerun a single input but we use a restarting mgr, we'll have to create a fake restarting mgr that doesn't actually restart.
// It's not pretty but better than recompiling with simplemgr.

// Just a random number, let's hope it's free :)
let broker_port = 13120;
let _fake_broker = LlmpBroker::create_attach_to_tcp(
shmem_provider.clone(),
tuple_list!(),
broker_port,
)
.unwrap();

// To rerun an input, instead of using a launcher, we create dummy parameters and run the client directly.
return client.run(
None,
MonitorTypedEventManager::<_, M>::new(LlmpRestartingEventManager::new(
LlmpEventManager::builder()
.build_on_port(
shmem_provider.clone(),
broker_port,
EventConfig::AlwaysUnique,
None,
)
.unwrap(),
StateRestorer::new(shmem_provider.new_shmem(0x1000).unwrap()),
)),
ClientDescription::new(0, 0, CoreId(0)),
);
}

#[cfg(feature = "simplemgr")]
return client.run(None, SimpleEventManager::new(monitor), CoreId(0));

// Build and run a Launcher
match Launcher::builder()
.shmem_provider(shmem_provider)
.broker_port(self.options.port)
.configuration(EventConfig::from_build_id())
.monitor(monitor)
.run_client(|s, m, c| client.run(s, MonitorTypedEventManager::<_, M>::new(m), c))
.cores(&self.options.cores)
.stdout_file(stdout)
.stderr_file(stdout)
.build()
.launch()
{
Ok(()) => Ok(()),
Err(Error::ShuttingDown) => {
println!("Fuzzing stopped by user. Good bye.");
Ok(())
}
Err(err) => Err(err),
}
}
}
Loading

0 comments on commit bce3474

Please sign in to comment.