Add filter to ASAN module in qemu_launcher (#3089)

also add filters to rasan runner.

Co-authored-by: Your Name <you@example.com>
This commit is contained in:
WorksButNotTested 2025-03-19 15:13:45 +00:00 committed by GitHub
parent 1b85a92577
commit 30946641cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 98 additions and 24 deletions

View File

@ -10,8 +10,8 @@ use libafl::{
};
use libafl_bolts::{rands::StdRand, tuples::tuple_list};
use libafl_qemu::modules::{
asan::AsanModule, asan_guest::AsanGuestModule, cmplog::CmpLogModule, DrCovModule,
InjectionModule,
asan::AsanModule, asan_guest::AsanGuestModule, cmplog::CmpLogModule,
utils::filters::StdAddressFilter, DrCovModule, InjectionModule,
};
use crate::{
@ -111,6 +111,17 @@ impl Client<'_> {
.client_description(client_description)
.extra_tokens(extra_tokens);
let asan_filter = if let Some(include_asan) = &self.options.include_asan {
log::info!("ASAN includes: {include_asan:#x?}");
StdAddressFilter::allow_list(include_asan.to_vec())
} else if let Some(exclude_asan) = &self.options.exclude_asan {
log::info!("ASAN excludes: {exclude_asan:#x?}");
StdAddressFilter::deny_list(exclude_asan.to_vec())
} else {
log::info!("ASAN no additional filter");
StdAddressFilter::default()
};
if self.options.rerun_input.is_some() {
if is_drcov {
// Special code path for re-running inputs with DrCov and Asan.
@ -123,7 +134,13 @@ impl Client<'_> {
.filename(drcov.clone())
.full_trace(true)
.build(),
unsafe { AsanModule::builder().env(&env).asan_report().build() }
unsafe {
AsanModule::builder()
.env(&env)
.filter(asan_filter)
.asan_report()
.build()
}
);
instance_builder.build().run(args, modules, state)
@ -133,7 +150,7 @@ impl Client<'_> {
.filename(drcov.clone())
.full_trace(true)
.build(),
AsanGuestModule::default(&env),
AsanGuestModule::new(&env, asan_filter),
);
instance_builder.build().run(args, modules, state)
@ -146,12 +163,17 @@ impl Client<'_> {
instance_builder.build().run(args, modules, state)
}
} else if is_asan {
let modules =
tuple_list!(unsafe { AsanModule::builder().env(&env).asan_report().build() });
let modules = tuple_list!(unsafe {
AsanModule::builder()
.env(&env)
.filter(asan_filter)
.asan_report()
.build()
});
instance_builder.build().run(args, modules, state)
} else if is_asan_guest {
let modules = tuple_list!(AsanGuestModule::default(&env));
let modules = tuple_list!(AsanGuestModule::new(&env, asan_filter));
instance_builder.build().run(args, modules, state)
} else {
@ -165,7 +187,7 @@ impl Client<'_> {
args,
tuple_list!(
CmpLogModule::default(),
AsanModule::builder().env(&env).build(),
AsanModule::builder().env(&env).filter(asan_filter).build(),
injection_module,
),
state,
@ -175,7 +197,7 @@ impl Client<'_> {
args,
tuple_list!(
CmpLogModule::default(),
AsanModule::builder().env(&env).build()
AsanModule::builder().env(&env).filter(asan_filter).build()
),
state,
)
@ -186,7 +208,7 @@ impl Client<'_> {
args,
tuple_list!(
CmpLogModule::default(),
AsanGuestModule::default(&env),
AsanGuestModule::new(&env, asan_filter),
injection_module
),
state,
@ -194,7 +216,10 @@ impl Client<'_> {
} else {
instance_builder.build().run(
args,
tuple_list!(CmpLogModule::default(), AsanGuestModule::default(&env),),
tuple_list!(
CmpLogModule::default(),
AsanGuestModule::new(&env, asan_filter),
),
state,
)
}
@ -202,20 +227,25 @@ impl Client<'_> {
if let Some(injection_module) = injection_module {
instance_builder.build().run(
args,
tuple_list!(AsanModule::builder().env(&env).build(), injection_module),
tuple_list!(
AsanModule::builder().env(&env).filter(asan_filter).build(),
injection_module
),
state,
)
} else {
instance_builder.build().run(
args,
tuple_list!(AsanModule::builder().env(&env).build()),
tuple_list!(AsanModule::builder().env(&env).filter(asan_filter).build()),
state,
)
}
} else if is_asan_guest {
instance_builder
.build()
.run(args, tuple_list!(AsanGuestModule::default(&env)), state)
instance_builder.build().run(
args,
tuple_list!(AsanGuestModule::new(&env, asan_filter)),
state,
)
} else if is_cmplog {
if let Some(injection_module) = injection_module {
instance_builder.build().run(

View File

@ -68,12 +68,18 @@ pub struct FuzzerOptions {
#[arg(long = "iterations", help = "Maximum number of iterations")]
pub iterations: Option<u64>,
#[arg(long = "include", help="Include address ranges", value_parser = FuzzerOptions::parse_ranges)]
#[arg(long = "include", help="Include coverage address ranges", value_parser = FuzzerOptions::parse_ranges)]
pub include: Option<Vec<Range<GuestAddr>>>,
#[arg(long = "exclude", help="Exclude address ranges", value_parser = FuzzerOptions::parse_ranges, conflicts_with="include")]
#[arg(long = "exclude", help="Exclude coverage address ranges", value_parser = FuzzerOptions::parse_ranges, conflicts_with="include")]
pub exclude: Option<Vec<Range<GuestAddr>>>,
#[arg(long = "include-asan", help="Include asan address ranges", value_parser = FuzzerOptions::parse_ranges)]
pub include_asan: Option<Vec<Range<GuestAddr>>>,
#[arg(long = "exclude-asan", help="Exclude asan address ranges", value_parser = FuzzerOptions::parse_ranges, conflicts_with="include_asan")]
pub exclude_asan: Option<Vec<Range<GuestAddr>>>,
#[arg(
short = 'd',
help = "Write a DrCov Trace for the current input. Requires -r."

View File

@ -14,7 +14,7 @@ test: test_asan
pretty_rust:
#!/bin/sh
MAIN_LLVM_VERSION=$LLVM_VERSION cargo run --manifest-path ../../utils/libafl_fmt/Cargo.toml --release -- -v
MAIN_LLVM_VERSION=$LLVM_VERSION cargo run --manifest-path ../../utils/libafl_repo_tools/Cargo.toml --release -- -v
pretty_toml:
#!/bin/sh

View File

@ -1,12 +1,12 @@
use std::{env, fmt::Write};
use std::{env, fmt::Write, ops::Range};
use clap::{Parser, builder::Str};
use libafl_bolts::{Error, tuples::tuple_list};
use libafl_qemu::{
Emulator, NopEmulatorDriver, NopSnapshotManager, QemuExitError, QemuInitError,
Emulator, GuestAddr, NopEmulatorDriver, NopSnapshotManager, QemuExitError, QemuInitError,
command::NopCommandManager,
elf::EasyElf,
modules::{AsanGuestModule, AsanModule, EmulatorModuleTuple},
modules::{AsanGuestModule, AsanModule, EmulatorModuleTuple, utils::filters::StdAddressFilter},
};
use log::{error, info};
use thiserror::Error;
@ -60,10 +60,37 @@ pub struct FuzzerOptions {
#[clap(short, long, help = "Enable output from the fuzzer clients")]
pub verbose: bool,
#[arg(long = "include-asan", help="Include asan address ranges", value_parser = FuzzerOptions::parse_ranges)]
pub include_asan: Option<Vec<Range<GuestAddr>>>,
#[arg(long = "exclude-asan", help="Exclude asan address ranges", value_parser = FuzzerOptions::parse_ranges, conflicts_with="include_asan")]
pub exclude_asan: Option<Vec<Range<GuestAddr>>>,
#[arg(last = true, help = "Arguments passed to the target")]
pub args: Vec<String>,
}
impl FuzzerOptions {
fn parse_ranges(src: &str) -> Result<Range<GuestAddr>, Error> {
let parts = src.split('-').collect::<Vec<&str>>();
if parts.len() == 2 {
let start =
GuestAddr::from_str_radix(parts[0].trim_start_matches("0x"), 16).map_err(|e| {
Error::illegal_argument(format!("Invalid start address: {} ({e:})", parts[0]))
})?;
let end =
GuestAddr::from_str_radix(parts[1].trim_start_matches("0x"), 16).map_err(|e| {
Error::illegal_argument(format!("Invalid end address: {} ({e:})", parts[1]))
})?;
Ok(Range { start, end })
} else {
Err(Error::illegal_argument(format!(
"Invalid range provided: {src:}"
)))
}
}
}
pub fn fuzz() {
env_logger::init();
let mut options = FuzzerOptions::parse();
@ -78,14 +105,25 @@ pub fn fuzz() {
.filter(|(k, _v)| k != "LD_LIBRARY_PATH")
.collect::<Vec<(String, String)>>();
let asan_filter = if let Some(include_asan) = &options.include_asan {
info!("ASAN includes: {include_asan:#x?}");
StdAddressFilter::allow_list(include_asan.to_vec())
} else if let Some(exclude_asan) = &options.exclude_asan {
info!("ASAN excludes: {exclude_asan:#x?}");
StdAddressFilter::deny_list(exclude_asan.to_vec())
} else {
info!("ASAN no additional filter");
StdAddressFilter::default()
};
let ret = if options.asan {
info!("Enabling ASAN");
let modules = tuple_list!(AsanModule::builder().env(&env).build());
let modules = tuple_list!(AsanModule::builder().env(&env).filter(asan_filter).build());
info!("Modules: {:#?}", modules);
run(options, modules)
} else if options.gasan {
info!("Enabling Guest ASAN");
let modules = tuple_list!(AsanGuestModule::default(&env));
let modules = tuple_list!(AsanGuestModule::new(&env, asan_filter));
info!("Modules: {:#?}", modules);
run(options, modules)
} else {