Add Features for C Targets (#1663)

* Allow disabling C targets for platforms that dont support them when using cmp observers

* Make sancov depend on coverage
This commit is contained in:
Rowan Hart 2023-11-27 13:34:41 -08:00 committed by GitHub
parent c84629a2f8
commit 5d5ee40329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 126 additions and 134 deletions

View File

@ -9,31 +9,49 @@ readme = "../README.md"
license = "MIT OR Apache-2.0"
keywords = ["fuzzing", "testing"]
edition = "2021"
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
categories = [
"development-tools::testing",
"emulators",
"embedded",
"os",
"no-std",
]
[package.metadata.docs.rs]
all-features = true
[features]
default = ["std", "sanitizers_flags"]
default = [
"std",
"sanitizers_flags",
"windows_asan",
"forkserver",
"cmplog",
"coverage",
"common",
]
std = ["libafl/std"]
libfuzzer = ["std", "sanitizer_interfaces"]
libfuzzer = ["std", "common", "sanitizer_interfaces"]
libfuzzer_no_link_main = ["libfuzzer"]
libfuzzer_define_run_driver = ["libfuzzer"]
libfuzzer_interceptors = ["libfuzzer", "sancov_cmplog"]
libfuzzer_oom = ["libfuzzer"]
sanitizers_flags = []
pointer_maps = []
sancov_pcguard_edges = []
sancov_pcguard_hitcounts = []
sancov_value_profile = []
sancov_pcguard_edges = ["coverage"]
sancov_pcguard_hitcounts = ["coverage"]
sancov_value_profile = ["common"]
sancov_8bit = []
sancov_cmplog = [] # Defines cmp and __sanitizer_weak_hook functions. Use libfuzzer_interceptors to define interceptors (only compatible with Linux)
sancov_cmplog = ["common"] # Defines cmp and __sanitizer_weak_hook functions. Use libfuzzer_interceptors to define interceptors (only compatible with Linux)
sancov_pcguard = ["sancov_pcguard_hitcounts"]
sanitizer_interfaces = []
clippy = [] # Ignore compiler warnings during clippy
observers = ["meminterval", "ahash"]
common = [] # Compile common C code defining sanitizer options and cross-platform intrinsics
coverage = ["common"] # Compile C code definining coverage maps
cmplog = ["common"] # Compile C code defining cmp log maps
forkserver = ["common"] # Compile C code for forkserver support
windows_asan = ["common"] # Compile C code for ASAN on Windows
whole_archive = [] # use +whole-archive to ensure the presence of weak symbols
[build-dependencies]

View File

@ -2,10 +2,6 @@
use std::{env, fs::File, io::Write, path::Path};
#[cfg(feature = "whole_archive")]
#[rustversion::not(nightly)]
compile_error!("Must use a nightly release with whole_archive!");
#[allow(clippy::too_many_lines)]
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
@ -68,6 +64,21 @@ fn main() {
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_H");
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE");
#[cfg(feature = "common")]
{
println!("cargo:rerun-if-changed=src/common.h");
println!("cargo:rerun-if-changed=src/common.c");
let mut common = cc::Build::new();
#[cfg(feature = "sanitizers_flags")]
{
common.define("DEFAULT_SANITIZERS_OPTIONS", "1");
}
common.file(src_dir.join("common.c")).compile("common");
}
#[cfg(any(feature = "sancov_value_profile", feature = "sancov_cmplog"))]
{
println!("cargo:rerun-if-changed=src/sancov_cmp.c");
@ -76,10 +87,6 @@ fn main() {
#[cfg(unix)]
sancov_cmp.flag("-Wno-sign-compare");
#[cfg(feature = "whole_archive")]
{
sancov_cmp.link_lib_modifier("+whole-archive");
}
#[cfg(feature = "sancov_value_profile")]
{
@ -133,37 +140,91 @@ fn main() {
let mut libfuzzer = cc::Build::new();
libfuzzer.file(src_dir.join("libfuzzer.c"));
#[cfg(feature = "whole_archive")]
{
libfuzzer.link_lib_modifier("+whole-archive");
}
#[cfg(feature = "libfuzzer_no_link_main")]
libfuzzer.define("FUZZER_NO_LINK_MAIN", "1");
#[cfg(feature = "libfuzzer_define_run_driver")]
libfuzzer.define("FUZZER_DEFINE_RUN_DRIVER", "1");
libfuzzer.compile("libfuzzer");
}
#[cfg(feature = "libfuzzer_interceptors")]
#[cfg(feature = "coverage")]
{
println!("cargo:rerun-if-changed=src/libfuzzer/FuzzerInterceptors.cpp");
println!("cargo:rerun-if-changed=src/coverage.c");
let mut interceptors = cc::Build::new();
interceptors.file(src_dir.join("libfuzzer/FuzzerInterceptors.cpp"));
cc::Build::new()
.file(src_dir.join("coverage.c"))
.define("EDGES_MAP_SIZE", Some(&*format!("{edges_map_size}")))
.define("ACCOUNTING_MAP_SIZE", Some(&*format!("{acc_map_size}")))
.compile("coverage");
}
#[cfg(feature = "whole_archive")]
#[cfg(feature = "cmplog")]
{
interceptors.link_lib_modifier("+whole-archive");
println!("cargo:rerun-if-changed=src/cmplog.h");
println!("cargo:rerun-if-changed=src/cmplog.c");
#[cfg(unix)]
{
cc::Build::new()
.flag("-Wno-pointer-sign") // UNIX ONLY FLAGS
.flag("-Wno-sign-compare")
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
.define(
"AFLPP_CMPLOG_MAP_W",
Some(&*format!("{aflpp_cmplog_map_w}")),
)
.define(
"AFLPP_CMPLOG_MAP_H",
Some(&*format!("{aflpp_cmplog_map_h}")),
)
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
.file(src_dir.join("cmplog.c"))
.compile("cmplog");
}
interceptors.cpp(true).compile("interceptors");
#[cfg(not(unix))]
{
cc::Build::new()
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
.define(
"AFLPP_CMPLOG_MAP_W",
Some(&*format!("{aflpp_cmplog_map_w}")),
)
.define(
"AFLPP_CMPLOG_MAP_H",
Some(&*format!("{aflpp_cmplog_map_h}")),
)
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
.file(src_dir.join("cmplog.c"))
.compile("cmplog");
}
}
println!("cargo:rerun-if-changed=src/common.h");
println!("cargo:rerun-if-changed=src/common.c");
#[cfg(feature = "forkserver")]
{
#[cfg(unix)]
{
println!("cargo:rerun-if-changed=src/forkserver.c");
cc::Build::new()
.file(src_dir.join("forkserver.c"))
.compile("forkserver");
}
}
#[cfg(all(feature = "windows_asan", windows))]
{
println!("cargo:rerun-if-changed=src/windows_asan.c");
cc::Build::new()
.file(src_dir.join("windows_asan.c"))
.compile("windows_asan");
}
// NOTE: Sanitizer interfaces doesn't require common
#[cfg(feature = "sanitizer_interfaces")]
if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" {
println!("cargo:rerun-if-changed=src/sanitizer_interfaces.h");
@ -185,99 +246,6 @@ fn main() {
write!(file, "").unwrap();
}
let mut common = cc::Build::new();
#[cfg(feature = "whole_archive")]
{
common.link_lib_modifier("+whole-archive");
}
#[cfg(feature = "sanitizers_flags")]
{
common.define("DEFAULT_SANITIZERS_OPTIONS", "1");
}
common.file(src_dir.join("common.c")).compile("common");
println!("cargo:rerun-if-changed=src/coverage.c");
let mut coverage = cc::Build::new();
#[cfg(feature = "whole_archive")]
{
coverage.link_lib_modifier("+whole-archive");
}
coverage
.file(src_dir.join("coverage.c"))
.define("EDGES_MAP_SIZE", Some(&*format!("{edges_map_size}")))
.define("ACCOUNTING_MAP_SIZE", Some(&*format!("{acc_map_size}")))
.compile("coverage");
println!("cargo:rerun-if-changed=src/cmplog.h");
println!("cargo:rerun-if-changed=src/cmplog.c");
let mut cmplog = cc::Build::new();
#[cfg(feature = "whole_archive")]
{
cmplog.link_lib_modifier("+whole-archive");
}
#[cfg(unix)]
{
cmplog
.flag("-Wno-pointer-sign") // UNIX ONLY FLAGS
.flag("-Wno-sign-compare");
}
cmplog
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
.define(
"AFLPP_CMPLOG_MAP_W",
Some(&*format!("{aflpp_cmplog_map_w}")),
)
.define(
"AFLPP_CMPLOG_MAP_H",
Some(&*format!("{aflpp_cmplog_map_h}")),
)
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
.file(src_dir.join("cmplog.c"))
.compile("cmplog");
#[cfg(unix)]
{
println!("cargo:rerun-if-changed=src/forkserver.c");
let mut forkserver = cc::Build::new();
#[cfg(feature = "whole_archive")]
{
forkserver.link_lib_modifier("+whole-archive");
}
forkserver
.file(src_dir.join("forkserver.c"))
.compile("forkserver");
}
#[cfg(windows)]
{
println!("cargo:rerun-if-changed=src/windows_asan.c");
let mut winasan = cc::Build::new();
#[cfg(feature = "whole_archive")]
{
winasan.link_lib_modifier("+whole-archive");
}
winasan
.file(src_dir.join("windows_asan.c"))
.compile("windows_asan");
}
println!("cargo:rustc-link-search=native={}", &out_dir);
println!("cargo:rerun-if-changed=build.rs");

View File

@ -46,6 +46,7 @@ pub const AFL_CMP_TYPE_RTN: u32 = 2;
// EXTERNS, GLOBALS
#[cfg(feature = "cmplog")]
// void __libafl_targets_cmplog_instructions(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2)
extern "C" {
/// Logs an instruction for feedback during fuzzing
@ -58,6 +59,7 @@ extern "C" {
pub static mut libafl_cmplog_map_ptr: *mut CmpLogMap;
}
#[cfg(feature = "cmplog")]
pub use libafl_cmplog_map_ptr as CMPLOG_MAP_PTR;
/// Value indicating if cmplog is enabled.

View File

@ -14,8 +14,9 @@ use libafl::{
};
use libafl_bolts::{ownedref::OwnedMutPtr, Named};
use crate::cmps::{libafl_cmplog_map_ptr, CmpLogMap, CMPLOG_ENABLED};
#[cfg(feature = "cmplog")]
use crate::cmps::libafl_cmplog_map_ptr;
use crate::cmps::{CmpLogMap, CMPLOG_ENABLED};
/// A [`CmpObserver`] observer for `CmpLog`
#[derive(Debug)]
pub struct CmpLogObserver {
@ -98,6 +99,7 @@ impl CmpLogObserver {
}
}
#[cfg(feature = "cmplog")]
/// Creates a new [`CmpLogObserver`] with the given name from the default cmplog map
#[must_use]
pub fn new(name: &'static str, add_meta: bool) -> Self {

View File

@ -100,7 +100,9 @@ pub mod sancov_8bit;
#[cfg(feature = "sancov_8bit")]
pub use sancov_8bit::*;
#[cfg(feature = "coverage")]
pub mod coverage;
#[cfg(feature = "coverage")]
pub use coverage::*;
pub mod value_profile;
@ -113,12 +115,12 @@ pub use cmps::*;
#[cfg(feature = "std")]
pub mod drcov;
#[cfg(all(windows, feature = "std"))]
#[cfg(all(windows, feature = "std", feture = "windows_asan"))]
pub mod windows_asan;
#[cfg(all(windows, feature = "std"))]
#[cfg(all(windows, feature = "std", feture = "windows_asan"))]
pub use windows_asan::*;
#[cfg(unix)]
#[cfg(all(unix, feature = "forkserver"))]
pub mod forkserver;
#[cfg(unix)]
#[cfg(all(unix, feature = "forkserver"))]
pub use forkserver::*;