Skip to content

Commit

Permalink
introducing alternative coverage measurements using gcov
Browse files Browse the repository at this point in the history
  • Loading branch information
riesentoaster committed Jun 1, 2024
1 parent 8811c5f commit 8409b83
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 42 deletions.
3 changes: 2 additions & 1 deletion fuzzers/coreutils_differential/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
crashes*
crashes*
*.gcov
80 changes: 45 additions & 35 deletions fuzzers/coreutils_differential/Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,18 @@ script = '''
clang -c -o "./${CARGO_TARGET_DIR}/coverage.o" coverage.c
'''


[tasks.gnu_coreutils_src]
[tasks.gnu_coreutils]
condition = { files_not_exist = [
"./${CARGO_TARGET_DIR}/GNU_coreutils/Makefile",
] }
dependencies = ["coverage_collector", "create_target_dir"]
script_runner = "@shell"
condition = { files_not_exist = ["./${CARGO_TARGET_DIR}/GNU_coreutils"] }
dependencies = ["create_target_dir"]
script = '''
cd "./${CARGO_TARGET_DIR}"
wget "http://ftp.gnu.org/gnu/coreutils/coreutils-${COREUTILS_VERSION}.tar.gz"
tar -xzf "coreutils-${COREUTILS_VERSION}.tar.gz"
rm "coreutils-${COREUTILS_VERSION}.tar.gz"
mv -f "coreutils-${COREUTILS_VERSION}" GNU_coreutils
'''

[tasks.gnu_coreutils_bin]
condition = { files_not_exist = [
"./${CARGO_TARGET_DIR}/GNU_coreutils/Makefile",
] }
dependencies = ["gnu_coreutils_src", "coverage_collector", "create_target_dir"]
script_runner = "@shell"
script = '''
cd "./${CARGO_TARGET_DIR}"
# absolute path because build system traverses into subdirectories
COVERAGE_FILE=$(realpath "./coverage.o")
Expand All @@ -58,28 +49,37 @@ export LDFLAGS="-rdynamic ${COVERAGE_FILE}"
make
'''

[tasks.uutils_coreutils_src]
script_runner = "@shell"
condition = { files_not_exist = ["./${CARGO_TARGET_DIR}/uutils_coreutils"] }
[tasks.gnu_coreutils_coverage]
condition = { files_not_exist = [
"./${CARGO_TARGET_DIR}/GNU_coreutils_coverage/Makefile",
] }
dependencies = ["create_target_dir"]
script_runner = "@shell"
script = '''
cd "./${CARGO_TARGET_DIR}"
git clone https://github.com/uutils/coreutils
mv coreutils uutils_coreutils
wget "http://ftp.gnu.org/gnu/coreutils/coreutils-${COREUTILS_VERSION}.tar.gz"
tar -xzf "coreutils-${COREUTILS_VERSION}.tar.gz"
rm "coreutils-${COREUTILS_VERSION}.tar.gz"
mv -f "coreutils-${COREUTILS_VERSION}" GNU_coreutils_coverage
# absolute path because build system traverses into subdirectories
COVERAGE_FILE=$(realpath "./coverage.o")
cd ./GNU_coreutils_coverage
CFLAGS="--coverage" ./configure
make
'''

[tasks.uutils_coreutils_bin]
[tasks.uutils_coreutils]
script_runner = "@shell"
condition = { files_not_exist = [
"./${CARGO_TARGET_DIR}/uutils_coreutils/target/release/coreutils",
] }
dependencies = [
"uutils_coreutils_src",
"coverage_collector",
"create_target_dir",
]
dependencies = ["coverage_collector", "create_target_dir"]
script = '''
cd "./${CARGO_TARGET_DIR}"
git clone https://github.com/uutils/coreutils
mv coreutils uutils_coreutils
# absolute path because build system traverses into subdirectories
COVERAGE_FILE=$(realpath "./coverage.o")
Expand All @@ -99,8 +99,8 @@ export PROFILE="release"
make
'''

[tasks.coreutils_bin]
dependencies = ["gnu_coreutils_bin", "uutils_coreutils_bin"]
[tasks.coreutils]
dependencies = ["gnu_coreutils", "uutils_coreutils"]

[tasks.get_guard_num]
script_runner = "@shell"
Expand All @@ -118,43 +118,53 @@ cargo build --profile ${PROFILE} --package setup_guard_redirection
dependencies = ["get_guard_num", "setup_guard_redirection"]

[tasks.fuzzer]
dependencies = ["coreutils_bin", "preloads"]
dependencies = ["coreutils", "preloads"]
script_runner = "@shell"
script = '''
cargo build --profile ${PROFILE}
'''

[tasks.fuzzer_gnu]
dependencies = ["coreutils_bin", "preloads"]
dependencies = ["GNU_coreutils", "preloads"]
script_runner = "@shell"
script = '''
cargo build --profile ${PROFILE} --no-default-features --features gnu
'''

[tasks.fuzzer_uutils]
dependencies = ["coreutils_bin", "preloads"]
dependencies = ["uutils_coreutils", "preloads"]
script_runner = "@shell"
script = '''
cargo build --profile ${PROFILE} --no-default-features --features uutils
'''

[tasks.clear_gcov_coverage]
dependencies = ["gnu_coreutils_coverage"]
script_runner = "@shell"
script = '''
rm -f ./*.gcov
rm -f ./**/*.gcov
rm -f ./${CARGO_TARGET_DIR}/GNU_coreutils_coverage/*.gcda
rm -f ./${CARGO_TARGET_DIR}/GNU_coreutils_coverage/**/*.gcda
'''

[tasks.run]
dependencies = ["fuzzer"]
dependencies = ["fuzzer", "clear_gcov_coverage"]
script_runner = "@shell"
script = '''
./target/release/coreutils_differential --output crashes --stdout out.log ${@}
./${CARGO_TARGET_DIR}/${PROFILE_DIR}/coreutils_differential --output crashes --stdout out.log ${@}
'''

[tasks.run_gnu]
dependencies = ["fuzzer_gnu"]
dependencies = ["fuzzer_gnu", "clear_gcov_coverage"]
script_runner = "@shell"
script = '''
./target/release/coreutils_differential --output crashes --stdout out.log ${@}
./${CARGO_TARGET_DIR}/${PROFILE_DIR}/coreutils_differential --output crashes --stdout out.log ${@}
'''

[tasks.run_uutils]
dependencies = ["fuzzer_uutils"]
script_runner = "@shell"
script = '''
./target/release/coreutils_differential --output crashes --stdout out.log ${@}
./${CARGO_TARGET_DIR}/${PROFILE_DIR}/coreutils_differential --output crashes --stdout out.log ${@}
'''
80 changes: 80 additions & 0 deletions fuzzers/coreutils_differential/src/generic/cov_feedback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use std::{
borrow::Cow,
process::{Command, Stdio},
};

use libafl::{
corpus::Testcase, events::EventFirer, executors::ExitKind, feedbacks::Feedback,
observers::ObserversTuple, state::State, Error,
};
use libafl_bolts::Named;

use super::executor::{pseudo_pipe, ExtractsToCommand};

pub struct CovFeedback {
is_interesting: bool,
gcov_path: String,
temp_file_stdin_path: String,
}

impl CovFeedback {
pub fn new(is_interesting: bool, gcov_path: String, temp_file_stdin_path: String) -> Self {
Self {
is_interesting,
gcov_path,
temp_file_stdin_path: format!("/dev/shm/temp{}", temp_file_stdin_path),
}
}
}

impl<S> Feedback<S> for CovFeedback
where
S: State,
S::Input: ExtractsToCommand,
{
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &<S>::Input,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
Ok(self.is_interesting)
}

fn append_metadata<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_observers: &OT,
testcase: &mut Testcase<<S>::Input>,
) -> Result<(), Error>
where
OT: ObserversTuple<S>,
EM: EventFirer<State = S>,
{
let input = testcase
.input()
.as_ref()
.ok_or(Error::illegal_state("Should have an input at this point"))?;
Command::new(&self.gcov_path)
.args(input.get_args())
.stdin(pseudo_pipe(input.get_stdin(), &self.temp_file_stdin_path)?)
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()?
.wait()?;
Ok(())
}
}

impl Named for CovFeedback {
fn name(&self) -> &Cow<'static, str> {
&Cow::Borrowed("CovFeedback")
}
}
2 changes: 1 addition & 1 deletion fuzzers/coreutils_differential/src/generic/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ where
/// # Errors on
///
/// This function will return an error if the underlying os functions error.
fn pseudo_pipe(data: &[u8], path: &str) -> Result<File, Error> {
pub fn pseudo_pipe(data: &[u8], path: &str) -> Result<File, Error> {
File::create(path)
.map_err(|e| Error::os_error(e, "Could not create temp file"))?
.write_all(data)
Expand Down
1 change: 1 addition & 0 deletions fuzzers/coreutils_differential/src/generic/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod cov_feedback;
pub mod executor;
pub mod shmem;
pub mod stdio;
30 changes: 25 additions & 5 deletions fuzzers/coreutils_differential/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ use std::path::PathBuf;
use base64::{base64_mutators, Base64Generator};

use generic::{
cov_feedback::CovFeedback,
executor::CoverageCommandExecutor,
shmem::{get_coverage_shmem_size, get_shmem},
};

use libafl::{
corpus::{InMemoryCorpus, OnDiskCorpus},
events::{EventConfig, Launcher, LlmpRestartingEventManager},
feedback_or_fast,
feedbacks::{CrashFeedback, DiffExitKindFeedback, MaxMapFeedback, TimeoutFeedback},
monitors::MultiMonitor,
mutators::StdScheduledMutator,
observers::{StdErrObserver, StdMapObserver, StdOutObserver, TimeObserver},
schedulers::{powersched::PowerSchedule, StdScheduler, StdWeightedScheduler},
Expand Down Expand Up @@ -53,6 +56,8 @@ use libafl::monitors::MultiMonitor;
pub static UUTILS_PREFIX: &str = "./target/uutils_coreutils/target/release/";
#[cfg(feature = "gnu")]
pub static GNU_PREFIX: &str = "./target/GNU_coreutils/src/";
#[cfg(feature = "gnu")]
pub static GNU_GCOV_PREFIX: &str = "./target/GNU_coreutils_coverage/src/";

pub fn main() {
let util = "base64";
Expand All @@ -72,8 +77,9 @@ fn fuzz(util: &str) -> Result<(), Error> {

#[cfg(feature = "introspection")]
let monitor = MultiMonitor::new(|s| println!("{}", s));
#[cfg(not(feature = "introspection"))]
let monitor = TuiMonitor::new(TuiUI::new("coreutils fuzzer".to_string(), true));
let monitor = MultiMonitor::new(|s| println!("{}", s));
// #[cfg(not(feature = "introspection"))]
// let monitor = TuiMonitor::new(TuiUI::new("coreutils fuzzer".to_string(), true));

#[cfg(feature = "uutils")]
let (uutils_coverage_shmem_size, uutils_path) =
Expand Down Expand Up @@ -175,7 +181,16 @@ fn fuzz(util: &str) -> Result<(), Error> {
},
)?;

let feedback = MaxMapFeedback::new(&combined_coverage_observer);
let gcov_feedback = CovFeedback::new(
true,
format!("{GNU_GCOV_PREFIX}{util}"),
format!("cov-{:?}", core_id.0),
);

let feedback = feedback_and_fast!(
MaxMapFeedback::new(&combined_coverage_observer),
gcov_feedback
);

// only add logger feedbacks if something was found
let objective = feedback_and!(
Expand Down Expand Up @@ -207,7 +222,13 @@ fn fuzz(util: &str) -> Result<(), Error> {

#[cfg(all(not(feature = "differential"), feature = "gnu"))]
let (mut feedback, mut objective) = {
let feedback = MaxMapFeedback::new(&gnu_coverage_observer);
let gcov_feedback = CovFeedback::new(
true,
format!("{GNU_GCOV_PREFIX}{util}"),
format!("cov-{:?}", core_id.0),
);
let feedback =
feedback_and_fast!(MaxMapFeedback::new(&gnu_coverage_observer), gcov_feedback);
let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
(feedback, objective)
};
Expand Down Expand Up @@ -238,7 +259,6 @@ fn fuzz(util: &str) -> Result<(), Error> {
&gnu_coverage_observer,
Some(PowerSchedule::FAST),
);
// let scheduler = StdScheduler::new();

let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
#[cfg(feature = "uutils")]
Expand Down

0 comments on commit 8409b83

Please sign in to comment.