Skip to content

Can't use InProcessExecutor inside of InProcessExecutor #3582

@langston-barrett

Description

@langston-barrett

I know this is an odd one but... I have a fuzzer that runs a QemuExecutor inside of a StatefulInProcessExecutor. This two-layered structure is essential to its functionality. The problem is that InProcessExecutor internally uses a single global variable that is shared between all instances. In particular, my fuzzer is hitting this assertion:

assert!((*data).crash_handler.is_null());

To Reproduce

Here's a minimal test-case that has the same behavior:

// mkdir tmp && cd tmp
// cargo init
// cargo add --no-default-features --features=std --git https://github.com/AFLplusplus/LibAFL libafl
// cargo add --no-default-features --features=std --git https://github.com/AFLplusplus/LibAFL libafl_bolts
// cargo run

use std::path::PathBuf;

use libafl::{
    corpus::{InMemoryCorpus, OnDiskCorpus},
    executors::{ExitKind, InProcessExecutor},
    fuzzer::{Fuzzer, StdFuzzer},
    generators::RandPrintablesGenerator,
    inputs::BytesInput,
    mutators::{havoc_mutations::havoc_mutations, scheduled::HavocScheduledMutator},
    stages::mutational::StdMutationalStage,
};
use libafl_bolts::{current_nanos, nonzero, rands::StdRand, tuples::tuple_list};

fn fuzz_with_harness(harness: impl FnMut(&BytesInput) -> ExitKind) {
    let mut feedback = libafl::feedbacks::ConstFeedback::False;
    let mut objective = libafl::feedbacks::ConstFeedback::False;
    let mut state = libafl::state::StdState::new(
        StdRand::with_seed(current_nanos()),
        InMemoryCorpus::new(),
        OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
        &mut feedback,
        &mut objective,
    )
    .unwrap();
    let mon = libafl::monitors::SimpleMonitor::new(|s| println!("{s}"));
    let mut mgr = libafl::events::SimpleEventManager::new(mon);
    let scheduler = libafl::schedulers::QueueScheduler::new();
    let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
    let mut executor =
        InProcessExecutor::new(harness, (), &mut fuzzer, &mut state, &mut mgr).unwrap();
    let mut generator = RandPrintablesGenerator::new(nonzero!(32));
    state
        .generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8)
        .unwrap();
    let mutator = HavocScheduledMutator::new(havoc_mutations());
    let mut stages = tuple_list!(StdMutationalStage::new(mutator));
    fuzzer
        .fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
        .unwrap();
}

pub fn main() {
    fuzz_with_harness(|_| {
        fuzz_with_harness(|_| ExitKind::Ok);
        ExitKind::Ok
    });
}

Expected behavior
The above fuzzer works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions