Skip to content

Commit

Permalink
Add additional logging and debug logging consumer for libafl code (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
novafacing authored Mar 20, 2024
1 parent b4e02ee commit ac494cf
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 39 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ env:
PUBLIC_SIMICS_ISPM_URL: "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/ead79ef5-28b5-48c7-8d1f-3cde7760798f/intel-simics-package-manager-1.8.3-linux64.tar.gz"
PUBLIC_SIMICS_PACKAGE_VERSION_1000: "6.0.185"
PUBLIC_SIMICS_ISPM_VERSION: "1.8.3"
BUILDER_CFE_VERSION: "5.0.2"
BUILDER_LLVM_VERSION: "5.0.2"
BUILDER_MAKE_VERSION: "4.4.1"
BUILDER_CMAKE_VERSION: "3.28.0-rc5"
BUILDER_PATCHELF_VERSION: "0.18.0"
MINGW_URL: "https://github.com/brechtsanders/winlibs_mingw/releases/download/13.2.0-16.0.6-11.0.0-ucrt-r1/winlibs-x86_64-posix-seh-gcc-13.2.0-llvm-16.0.6-mingw-w64ucrt-11.0.0-r1.7z"
MINGW_VERSION: "13.2.0-16.0.6-11.0.0-ucrt-r1"

Expand Down Expand Up @@ -588,7 +593,7 @@ jobs:
uses: actions/cache@v4
with:
path: .github/builder/rsrc
key: "cache-builder-dependencies-${{ env.PUBLIC_SIMICS_ISPM_URL}}-${{env.PUBLIC_SIMICS_PKGS_URL }}-${{ env.CFE_URL }}-${{ env.LLVM_SRC_URL }}-${{ env.MAKE_SRC_URL }}-${{ env.RUSTUP_INIT_URL }}-${{ env.CMAKE_URL }}"
key: "cache-builder-dependencies-${{ env.PUBLIC_SIMICS_ISPM_VERSION }}-${{ env.BUILDER_CFE_VERSION }}-${{ env.BUILDER_LLVM_VERSION }}-${{ env.BUILDER_MAKE_VERSION }}-${{ env.BUILDER_CMAKE_VERSION }}"

- name: Download Builder Dependencies
if: ${{ steps.cache-builder-dependencies.outputs.cache-hit != 'true' }}
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
versions = { version = "6.1.0", features = ["serde"] }
ffi = "0.1.1"
tracing-subscriber = "0.3.18"
tracing = { version = "0.1.40", features = ["log"] }

[dev-dependencies]
simics-test = { path = "simics-rs/simics-test" }
Expand Down
168 changes: 130 additions & 38 deletions src/fuzzer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ use libafl_bolts::{
use libafl_targets::{AFLppCmpLogObserver, AFLppCmplogTracingStage};
use simics::{api::AsConfObject, debug, warn};
use std::{
cell::RefCell, fmt::Debug, slice::from_raw_parts_mut, sync::mpsc::channel, thread::spawn,
time::Duration,
cell::RefCell, fmt::Debug, io::stderr, slice::from_raw_parts_mut, sync::mpsc::channel,
thread::spawn, time::Duration,
};
use tokenize::{tokenize_executable_file, tokenize_src_file};
use tracing::{level_filters::LevelFilter, Level};
use tracing_subscriber::{
filter::filter_fn, fmt, layer::SubscriberExt, registry, util::SubscriberInitExt, Layer,
};

pub mod feedbacks;
pub mod messages;
Expand Down Expand Up @@ -176,14 +180,37 @@ impl Tsffs {
let generate_random_corpus = self.generate_random_corpus;
let initial_random_corpus_size = self.initial_random_corpus_size;
let executor_timeout = self.executor_timeout;
let debug_log_libafl = self.debug_log_libafl;

// NOTE: We do *not* use `run_in_thread` because it causes the fuzzer to block when HAPs arrive
// which prevents forward progress.
self.fuzz_thread
.set(spawn(move || -> Result<()> {
if debug_log_libafl {
let reg = registry().with({
fmt::layer()
.compact()
.with_thread_ids(true)
.with_thread_names(true)
.with_writer(stderr)
.with_filter(LevelFilter::TRACE)
.with_filter(filter_fn(|metadata| {
// LLMP absolutely spams the log when tracing
!(metadata.target() == "libafl_bolts::llmp"
&& matches!(metadata.level(), &Level::TRACE))
}))
});

reg.try_init()
.map_err(|e| {
eprintln!("Could not install tracing subscriber: {}", e);
e
})
.ok();
}

let mut harness = |input: &BytesInput| {
let testcase = BytesInput::new(input.target_bytes().as_slice().to_vec());
// println!("Sending testcase {:?}", testcase);
client
.borrow_mut()
.0
Expand All @@ -192,19 +219,17 @@ impl Tsffs {
cmplog: false,
})
.expect("Failed to send testcase message");
// println!("Sent testcase, waiting for status");

let status = match client.borrow_mut().1.recv() {
Err(e) => panic!("Error receiving status: {e}"),
Ok(m) => m,
};
// println!("Got status: {:?}", status);

status
};

let mut aflpp_cmp_harness = |input: &BytesInput| {
let testcase = BytesInput::new(input.target_bytes().as_slice().to_vec());
// println!("Sending testcase {:?}", testcase);
client
.borrow_mut()
.0
Expand All @@ -213,13 +238,11 @@ impl Tsffs {
cmplog: true,
})
.expect("Failed to send testcase message");
// println!("Sent testcase, waiting for status");

let status = match client.borrow_mut().1.recv() {
Err(e) => panic!("Error receiving status: {e}"),
Ok(m) => m,
};
// println!("Got status: {:?}", status);

status
};
Expand Down Expand Up @@ -256,13 +279,21 @@ impl Tsffs {
let solutions = OnDiskCorpus::with_meta_format(
solutions_directory.clone(),
OnDiskMetadataFormat::JsonPretty,
)?;
)
.map_err(|e| {
eprintln!("Failed to initialize solutions corpus: {e}");
anyhow!("Failed to initialize solutions corpus: {e}")
})?;

let corpus = CachedOnDiskCorpus::with_meta_format(
corpus_directory.clone(),
Self::CORPUS_CACHE_SIZE,
Some(OnDiskMetadataFormat::Json),
)?;
)
.map_err(|e| {
eprintln!("Failed to initialize corpus: {e}");
anyhow!("Failed to initialize corpus: {e}")
})?;

// NOTE: Initialize these here before we move the feedbacks
let calibration_stage = CalibrationStage::new(&map_feedback);
Expand All @@ -279,7 +310,10 @@ impl Tsffs {
&mut feedback,
&mut objective,
)
.map_err(|e| anyhow!("Couldn't initialize state: {e}"))?;
.map_err(|e| {
eprintln!("Couldn't initialize fuzzer state: {e}");
anyhow!("Couldn't initialize state: {e}")
})?;

let mut tokens = Tokens::default().add_from_files(token_files)?;

Expand Down Expand Up @@ -315,7 +349,11 @@ impl Tsffs {
&mut state,
&mut manager,
Duration::from_secs(executor_timeout),
)?;
)
.map_err(|e| {
eprintln!("Couldn't initialize fuzzer executor: {e}");
anyhow!("Couldn't initialize fuzzer executor: {e}")
})?;

let aflpp_cmp_executor = InProcessExecutor::with_timeout(
&mut aflpp_cmp_harness,
Expand All @@ -324,7 +362,11 @@ impl Tsffs {
&mut state,
&mut manager,
Duration::from_secs(executor_timeout),
)?;
)
.map_err(|e| {
eprintln!("Couldn't initialize fuzzer AFL++ cmplog executor: {e}");
anyhow!("Couldn't initialize fuzzer AFL++ cmplog executor: {e}")
})?;

let tracing_executor = InProcessExecutor::with_timeout(
&mut tracing_harness,
Expand All @@ -333,20 +375,30 @@ impl Tsffs {
&mut state,
&mut manager,
Duration::from_secs(executor_timeout),
)?;
)
.map_err(|e| {
eprintln!("Couldn't initialize fuzzer AFL++ cmplog executor: {e}");
anyhow!("Couldn't initialize fuzzer AFL++ cmplog executor: {e}")
})?;

let input_to_state_stage = StdMutationalStage::new(StdScheduledMutator::new(
tuple_list!(I2SRandReplace::new()),
));
let havoc_mutational_stage = StdPowerMutationalStage::new(
StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())),
);
let mopt_mutational_stage = StdPowerMutationalStage::new(StdMOptMutator::new(
&mut state,
havoc_mutations().merge(tokens_mutations()),
7,
5,
)?);
let mopt_mutational_stage = StdPowerMutationalStage::new(
StdMOptMutator::new(
&mut state,
havoc_mutations().merge(tokens_mutations()),
7,
5,
)
.map_err(|e| {
eprintln!("Couldn't initialize fuzzer MOpt mutator: {e}");
anyhow!("Couldn't initialize fuzzer MOpt mutator: {e}")
})?,
);
let redqueen_mutational_stage =
MultiMutationalStage::new(AFLppRedQueen::with_cmplog_options(true, true));
let aflpp_tracing_stage = AFLppCmplogTracingStage::with_cmplog_observer_name(
Expand All @@ -360,25 +412,41 @@ impl Tsffs {
|input: &BytesInput, _state: &_| input.target_bytes().as_slice().to_vec(),
corpus_directory.clone(),
solutions_directory.clone(),
)?;
)
.map_err(|e| {
eprintln!("Couldn't initialize fuzzer dump to disk stage: {e}");
anyhow!("Couldn't initialize fuzzer dump to disk stage: {e}")
})?;

if state.must_load_initial_inputs() {
state.load_initial_inputs(
&mut fuzzer,
&mut executor,
&mut manager,
&[corpus_directory.clone()],
)?;

if state.corpus().count() < 1 && generate_random_corpus {
let mut generator = RandBytesGenerator::new(64);
state.generate_initial_inputs(
state
.load_initial_inputs(
&mut fuzzer,
&mut executor,
&mut generator,
&mut manager,
initial_random_corpus_size,
)?;
&[corpus_directory.clone()],
)
.map_err(|e| {
eprintln!(
"Error loading initial inputs from {corpus_directory:?}: {e}"
);
anyhow!("Error loading initial inputs from {corpus_directory:?}: {e}")
})?;

if state.corpus().count() < 1 && generate_random_corpus {
let mut generator = RandBytesGenerator::new(64);
state
.generate_initial_inputs(
&mut fuzzer,
&mut executor,
&mut generator,
&mut manager,
initial_random_corpus_size,
)
.map_err(|e| {
eprintln!("Error generating random inputs: {e}");
anyhow!("Error generating random inputs: {e}")
})?;
}
}

Expand All @@ -403,9 +471,28 @@ impl Tsffs {
Ok(cmplog_enabled
&& state
.corpus()
.get(state.current_corpus_idx()?.ok_or_else(|| {
libafl::Error::unknown("No current corpus index")
})?)?
.get(
state
.current_corpus_idx()
.map_err(|e| {
eprintln!(
"Error getting current corpus index: {e}"
);
// libafl::Error::unkown(format!(
// "Error getting current corpus index: {e}"
// ))
e
})?
.ok_or_else(|| {
eprintln!("No current corpus index");

libafl::Error::unknown("No current corpus index")
})?,
)
.map_err(|e| {
eprintln!("Error getting current corpus entry: {e}");
e
})?
.borrow()
.scheduled_count()
== 1)
Expand Down Expand Up @@ -438,7 +525,12 @@ impl Tsffs {
break;
}

fuzzer.fuzz_one(&mut stages, &mut executor, &mut state, &mut manager)?;
fuzzer
.fuzz_one(&mut stages, &mut executor, &mut state, &mut manager)
.map_err(|e| {
eprintln!("Error running iteration of fuzzing loop: {e}");
anyhow!("Error running iteration of fuzzing loop: {e}")
})?;
}

println!("Fuzzing loop exited.");
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ pub(crate) struct Tsffs {
pub log_to_file: bool,
#[class(attribute(optional, default = false))]
pub keep_all_corpus: bool,
#[class(attribute(optional, default = false))]
pub debug_log_libafl: bool,

#[attr_value(skip)]
/// Handle for the core simulation stopped hap
Expand Down

0 comments on commit ac494cf

Please sign in to comment.