You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You have verified that the issue to be present in the current main branch
Have done.
Thank you for making LibAFL better!
Describe the bug CommandExecutor crashes after some time on Linux when using InputLocation::StdIn to provide input. I have tested this on two machines with different hardware and Linux setups and found that they both fail eventually with this error message:
thread 'main' panicked at 'Error in the fuzzing loop: File(Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }, ErrorBacktrace)', src/main.rs:137:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
To Reproduce
Steps to reproduce the behavior:
Replace the contents of /fuzzers/baby_fuzzer/src/main.rs with the following and cargo run (it crashes after around 10 seconds on my local machine but may take longer):
#[cfg(windows)]
use std::ptr::write_volatile;
use std::{path::PathBuf, ptr::write};
#[cfg(feature = "tui")]
use libafl::monitors::tui::TuiMonitor;
#[cfg(not(feature = "tui"))]
use libafl::monitors::SimpleMonitor;
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer},
generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes},
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
observers::StdMapObserver,
schedulers::QueueScheduler,
stages::mutational::StdMutationalStage,
state::StdState,
prelude::{CommandExecutor, TimeFeedback, TimeObserver}
};
/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() };
/// Assign a signal to the signals map
fn signals_set(idx: usize) {
unsafe { write(SIGNALS_PTR.add(idx), 1) };
}
#[allow(clippy::similar_names, clippy::manual_assert)]
pub fn main() {
// The closure that we want to fuzz
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
signals_set(0);
if !buf.is_empty() && buf[0] == b'a' {
signals_set(1);
if buf.len() > 1 && buf[1] == b'b' {
signals_set(2);
if buf.len() > 2 && buf[2] == b'c' {
#[cfg(unix)]
panic!("Artificial bug triggered =)");
// panic!() raises a STATUS_STACK_BUFFER_OVERRUN exception which cannot be caught by the exception handler.
// Here we make it raise STATUS_ACCESS_VIOLATION instead.
// Extending the windows exception handler is a TODO. Maybe we can refer to what winafl code does.
// https://github.com/googleprojectzero/winafl/blob/ea5f6b85572980bb2cf636910f622f36906940aa/winafl.c#L728
#[cfg(windows)]
unsafe {
write_volatile(0 as *mut u32, 0);
}
}
}
}
ExitKind::Ok
};
// Create an observation channel using the signals map
// let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };
let observer = TimeObserver::new("time");
// Feedback to rate the interestingness of an input
// let mut feedback = MaxMapFeedback::new(&observer);
let mut feedback = TimeFeedback::with_observer(&observer);
// A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new();
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
// States of the feedbacks.
// The feedbacks can report the data that should persist in the State.
&mut feedback,
// Same for objective feedbacks
&mut objective,
)
.unwrap();
// The Monitor trait define how the fuzzer stats are displayed to the user
#[cfg(not(feature = "tui"))]
let mon = SimpleMonitor::new(|s| println!("{s}"));
#[cfg(feature = "tui")]
let mon = TuiMonitor::new(String::from("Baby Fuzzer"), false);
// The event manager handle the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(mon);
// A queue policy to get testcasess from the corpus
let scheduler = QueueScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// Create the executor for an in-process function with just one observer
let mut builder = CommandExecutor::builder();
builder.program("echo");
let mut executor = builder.build(tuple_list!(observer)).unwrap();
// Generator of printable bytearrays of max size 32
let mut generator = RandPrintablesGenerator::new(32);
// Generate 8 initial inputs
state
.generate_initial_inputs_forced(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8)
.expect("Failed to generate the initial corpus");
// Setup a mutational stage with a basic bytes mutator
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.expect("Error in the fuzzing loop");
}
Expected behavior
The fuzzer should continue as normal.
Screen output/Screenshots
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 1, objectives: 0, executions: 1, exec/sec: 0.000
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 2, objectives: 0, executions: 2, exec/sec: 0.000
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 3, objectives: 0, executions: 3, exec/sec: 0.000
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 4, objectives: 0, executions: 4, exec/sec: 0.000
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 5, objectives: 0, executions: 5, exec/sec: 0.000
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 6, objectives: 0, executions: 6, exec/sec: 0.000
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 7, objectives: 0, executions: 7, exec/sec: 0.000
[Testcase #0] run time: 0h-0m-0s, clients: 1, corpus: 8, objectives: 0, executions: 8, exec/sec: 0.000
thread 'main' panicked at 'Error in the fuzzing loop: File(Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }, ErrorBacktrace)', src/main.rs:137:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
[1] 15497 abort (core dumped) cargo run
Additional context
The following patch fixes the issue for me:
diff --git a/libafl/src/executors/command.rs b/libafl/src/executors/command.rs
index a92022f6..43e161dd 100644
--- a/libafl/src/executors/command.rs
+++ b/libafl/src/executors/command.rs
@@ -132,8 +132,7 @@ impl CommandConfigurator for StdCommandConfigurator {
Ok(cmd.spawn()?)
}
InputLocation::StdIn => {
- self.command.stdin(Stdio::piped()).spawn()?;
- let mut handle = self.command.spawn()?;
+ let mut handle = self.command.stdin(Stdio::piped()).spawn()?;
let mut stdin = handle.stdin.take().unwrap();
The text was updated successfully, but these errors were encountered:
IMPORTANT
main
branchHave done.
Thank you for making LibAFL better!
Describe the bug
CommandExecutor
crashes after some time on Linux when usingInputLocation::StdIn
to provide input. I have tested this on two machines with different hardware and Linux setups and found that they both fail eventually with this error message:To Reproduce
Steps to reproduce the behavior:
/fuzzers/baby_fuzzer/src/main.rs
with the following andcargo run
(it crashes after around 10 seconds on my local machine but may take longer):Expected behavior
The fuzzer should continue as normal.
Screen output/Screenshots
Additional context
The following patch fixes the issue for me:
The text was updated successfully, but these errors were encountered: