Document LIBAFL_DEBUG_OUTPUT in Launcher (#1485)

* Document LIBAFL_DEBUG_OUTPUT in Launcher

* fmt

* more doc

* fork

* unix
This commit is contained in:
Dominik Maier 2023-08-30 00:00:12 +02:00 committed by GitHub
parent 51e4d814fb
commit 5710c8b28a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 8 deletions

View File

@ -29,6 +29,6 @@ feel free to use and mutate an Abstract Syntax Tree instead, for structured fuzz
- `scalable`: As part of LibAFL, we developed `Low Level Message Passing`, `LLMP` for short, which allows LibAFL to scale almost linearly over cores. That is, if you chose to use this feature - it is your fuzzer, after all. - `scalable`: As part of LibAFL, we developed `Low Level Message Passing`, `LLMP` for short, which allows LibAFL to scale almost linearly over cores. That is, if you chose to use this feature - it is your fuzzer, after all.
Scaling to multiple machines over TCP is also possible, using LLMP's `broker2broker` feature. Scaling to multiple machines over TCP is also possible, using LLMP's `broker2broker` feature.
- `fast`: We do everything we can at compile time so that the runtime overhead is as minimal as it can get. - `fast`: We do everything we can at compile time so that the runtime overhead is as minimal as it can get.
- `bring your own target`: We support binary-only modes, like QEMU-Mode and Frida-Mode with ASAN and CmpLog, as well as multiple compilation passes for sourced-based instrumentation. - `bring your own target`: We support binary-only modes, like (full-system) QEMU-Mode and Frida-Mode with ASan and CmpLog, as well as multiple compilation passes for sourced-based instrumentation.
Of course, we also support custom instrumentation, as you can see in the Python example based on Google's Atheris. Of course, we also support custom instrumentation, as you can see in the Python example based on Google's Atheris.
- `usable`: This one is on you to decide. Dig right in! - `usable`: This one is on you to decide. Dig right in!

View File

@ -3,7 +3,7 @@
Configurations for individual fuzzer nodes are relevant for multi node fuzzing. Configurations for individual fuzzer nodes are relevant for multi node fuzzing.
The chapter describes how to run nodes with different configurations The chapter describes how to run nodes with different configurations
in one fuzzing cluster. in one fuzzing cluster.
This allows, for example, a node compiled with ASAN, to know that it needs to rerun new testcases for a node without ASAN, while the same binary/configuration does not. This allows, for example, a node compiled with ASan, to know that it needs to rerun new testcases for a node without ASan, while the same binary/configuration does not.
Fuzzers with the same configuration can exchange Observers for new testcases and reuse them without rerunning the input. Fuzzers with the same configuration can exchange Observers for new testcases and reuse them without rerunning the input.
A different configuration indicates, that only the raw input can be exchanged, it must be rerun on the other node to capture relevant observations. A different configuration indicates, that only the raw input can be exchanged, it must be rerun on the other node to capture relevant observations.

View File

@ -4,7 +4,7 @@ Multiple fuzzer instances can be spawned using different ways.
## Manually, via a TCP port ## Manually, via a TCP port
The straightforward way to do Multi-Threading is to use the `LlmpRestartingEventManager`, specifically to use `setup_restarting_mgr_std`. The straightforward way to do Multi-Threading is to use the [`LlmpRestartingEventManager`](https://docs.rs/libafl/latest/libafl/events/llmp/struct.LlmpRestartingEventManager.html), specifically to use [`setup_restarting_mgr_std`](https://docs.rs/libafl/latest/libafl/events/llmp/fn.setup_restarting_mgr_std.html).
It abstracts away all the pesky details about restarts on crash handling (for in-memory fuzzers) and multi-threading. It abstracts away all the pesky details about restarts on crash handling (for in-memory fuzzers) and multi-threading.
With it, every instance you launch manually tries to connect to a TCP port on the local machine. With it, every instance you launch manually tries to connect to a TCP port on the local machine.
@ -13,7 +13,7 @@ If the port is not yet bound, this instance becomes the broker, binding itself t
If the port is already bound, the EventManager will try to connect to it. If the port is already bound, the EventManager will try to connect to it.
The instance becomes a client and can now communicate with all other nodes. The instance becomes a client and can now communicate with all other nodes.
Launching nodes manually has the benefit that you can have multiple nodes with different configurations, such as clients fuzzing with and without ASAN. Launching nodes manually has the benefit that you can have multiple nodes with different configurations, such as clients fuzzing with and without `ASan``.
While it's called "restarting" manager, it uses `fork` on Unix-like operating systems as optimization and only actually restarts from scratch on Windows. While it's called "restarting" manager, it uses `fork` on Unix-like operating systems as optimization and only actually restarts from scratch on Windows.
@ -42,6 +42,7 @@ To use launcher, first you need to write an anonymous function `let mut run_clie
This first starts a broker, then spawns `n` clients, according to the value passed to `cores`. This first starts a broker, then spawns `n` clients, according to the value passed to `cores`.
The value is a string indicating the cores to bind to, for example, `0,2,5` or `0-3`. The value is a string indicating the cores to bind to, for example, `0,2,5` or `0-3`.
For each client, `run_client` will be called. For each client, `run_client` will be called.
If the launcher uses `fork`, it will hide child output, unless the settings indicate otherwise, or the `LIBAFL_DEBUG_OUTPUT` env variable is set.
On Windows, the Launcher will restart each client, while on Unix-alikes, it will use `fork`. On Windows, the Launcher will restart each client, while on Unix-alikes, it will use `fork`.
Advanced use-cases: Advanced use-cases:
@ -49,6 +50,9 @@ Advanced use-cases:
1. To connect multiple nodes together via TCP, you can use the `remote_broker_addr`. this requires the `llmp_bind_public` compile-time feature for `LibAFL`. 1. To connect multiple nodes together via TCP, you can use the `remote_broker_addr`. this requires the `llmp_bind_public` compile-time feature for `LibAFL`.
2. To use multiple launchers for individual configurations, you can set `spawn_broker` to `false` on all instances but one. 2. To use multiple launchers for individual configurations, you can set `spawn_broker` to `false` on all instances but one.
3. Launcher will not select the cores automatically, so you need to specify the `cores` that you want. 3. Launcher will not select the cores automatically, so you need to specify the `cores` that you want.
4. On `Unix`, you can chose between a forking and non-forking version of Launcher by setting the `fork` feature in LibAFL. Some targets may not like forking, but it is faster than restarting processes from scratch. Windows will never fork.
5. For simple debugging, first set the `LIBAFL_DEBUG_OUTPUT` env variable to see if a child process printed anything.
6. For further debugging of fuzzer failures, it may make sense to replace `Launcher` temporarily with a [`SimpleEventManager`](https://docs.rs/libafl/latest/libafl/events/simple/struct.SimpleEventManager.html#method.new) and call your harness fn (`run_client(None, mgr, 0);`) directly, so that fuzzing runs in the same thread and is easier to debug, before moving back to `Launcher` after the bugfix.
For more examples, you can check out `qemu_launcher` and `libfuzzer_libpng_launcher` in [`./fuzzers/`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers). For more examples, you can check out `qemu_launcher` and `libfuzzer_libpng_launcher` in [`./fuzzers/`](https://github.com/AFLplusplus/LibAFL/tree/main/fuzzers).

View File

@ -1,6 +1,8 @@
//! The [`Launcher`] launches multiple fuzzer instances in parallel. //! The [`Launcher`] launches multiple fuzzer instances in parallel.
//! Thanks to it, we won't need a `for` loop in a shell script... //! Thanks to it, we won't need a `for` loop in a shell script...
//! //!
//! It will hide child output, unless the settings indicate otherwise, or the `LIBAFL_DEBUG_OUTPUT` env variable is set.
//!
//! To use multiple [`Launcher`]`s` for individual configurations, //! To use multiple [`Launcher`]`s` for individual configurations,
//! we can set `spawn_broker` to `false` on all but one. //! we can set `spawn_broker` to `false` on all but one.
//! //!
@ -54,7 +56,13 @@ use crate::{
/// The (internal) `env` that indicates we're running as client. /// The (internal) `env` that indicates we're running as client.
const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT"; const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT";
/// Provides a Launcher, which can be used to launch a fuzzing run on a specified list of cores /// The env variable to set in order to enable child output
#[cfg(all(feature = "fork", unix))]
const LIBAFL_DEBUG_OUTPUT: &str = "LIBAFL_DEBUG_OUTPUT";
/// Provides a [`Launcher`], which can be used to launch a fuzzing run on a specified list of cores
///
/// Will hide child output, unless the settings indicate otherwise, or the `LIBAFL_DEBUG_OUTPUT` env variable is set.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[allow( #[allow(
clippy::type_complexity, clippy::type_complexity,
@ -168,7 +176,7 @@ where
.map(|filename| File::create(filename).unwrap()); .map(|filename| File::create(filename).unwrap());
#[cfg(feature = "std")] #[cfg(feature = "std")]
let debug_output = std::env::var("LIBAFL_DEBUG_OUTPUT").is_ok(); let debug_output = std::env::var(LIBAFL_DEBUG_OUTPUT).is_ok();
// Spawn clients // Spawn clients
let mut index = 0_u64; let mut index = 0_u64;
@ -277,7 +285,8 @@ where
Ok(core_conf) => { Ok(core_conf) => {
let core_id = core_conf.parse()?; let core_id = core_conf.parse()?;
//todo: silence stdout and stderr for clients // TODO: silence stdout and stderr for clients
// let debug_output = std::env::var(LIBAFL_DEBUG_OUTPUT).is_ok();
// the actual client. do the fuzzing // the actual client. do the fuzzing
let (state, mgr) = RestartingMgr::<MT, S, SP>::builder() let (state, mgr) = RestartingMgr::<MT, S, SP>::builder()
@ -493,7 +502,7 @@ where
.stderr_file .stderr_file
.map(|filename| File::create(filename).unwrap()); .map(|filename| File::create(filename).unwrap());
let debug_output = std::env::var("LIBAFL_DEBUG_OUTPUT").is_ok(); let debug_output = std::env::var(LIBAFL_DEBUG_OUTPUT).is_ok();
// Spawn centralized broker // Spawn centralized broker
self.shmem_provider.pre_fork()?; self.shmem_provider.pre_fork()?;