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" license = "MIT OR Apache-2.0"
keywords = ["fuzzing", "testing"] keywords = ["fuzzing", "testing"]
edition = "2021" edition = "2021"
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"] categories = [
"development-tools::testing",
"emulators",
"embedded",
"os",
"no-std",
]
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true
[features] [features]
default = ["std", "sanitizers_flags"] default = [
"std",
"sanitizers_flags",
"windows_asan",
"forkserver",
"cmplog",
"coverage",
"common",
]
std = ["libafl/std"] std = ["libafl/std"]
libfuzzer = ["std", "sanitizer_interfaces"] libfuzzer = ["std", "common", "sanitizer_interfaces"]
libfuzzer_no_link_main = ["libfuzzer"] libfuzzer_no_link_main = ["libfuzzer"]
libfuzzer_define_run_driver = ["libfuzzer"] libfuzzer_define_run_driver = ["libfuzzer"]
libfuzzer_interceptors = ["libfuzzer", "sancov_cmplog"] libfuzzer_interceptors = ["libfuzzer", "sancov_cmplog"]
libfuzzer_oom = ["libfuzzer"] libfuzzer_oom = ["libfuzzer"]
sanitizers_flags = [] sanitizers_flags = []
pointer_maps = [] pointer_maps = []
sancov_pcguard_edges = [] sancov_pcguard_edges = ["coverage"]
sancov_pcguard_hitcounts = [] sancov_pcguard_hitcounts = ["coverage"]
sancov_value_profile = [] sancov_value_profile = ["common"]
sancov_8bit = [] 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"] sancov_pcguard = ["sancov_pcguard_hitcounts"]
sanitizer_interfaces = [] sanitizer_interfaces = []
clippy = [] # Ignore compiler warnings during clippy clippy = [] # Ignore compiler warnings during clippy
observers = ["meminterval", "ahash"] 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 whole_archive = [] # use +whole-archive to ensure the presence of weak symbols
[build-dependencies] [build-dependencies]
@ -49,6 +67,6 @@ log = "0.4.20"
rangemap = "1.3" rangemap = "1.3"
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
meminterval = {version = "0.4", features = ["serde"], optional = true } meminterval = { version = "0.4", features = ["serde"], optional = true }
ahash = { version = "0.8.3", default-features = false, optional = true } ahash = { version = "0.8.3", default-features = false, optional = true }
# serde-big-array = "0.3.2" # serde-big-array = "0.3.2"

View File

@ -2,10 +2,6 @@
use std::{env, fs::File, io::Write, path::Path}; 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)] #[allow(clippy::too_many_lines)]
fn main() { fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap(); 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_CMPLOG_MAP_H");
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE"); 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"))] #[cfg(any(feature = "sancov_value_profile", feature = "sancov_cmplog"))]
{ {
println!("cargo:rerun-if-changed=src/sancov_cmp.c"); println!("cargo:rerun-if-changed=src/sancov_cmp.c");
@ -76,10 +87,6 @@ fn main() {
#[cfg(unix)] #[cfg(unix)]
sancov_cmp.flag("-Wno-sign-compare"); sancov_cmp.flag("-Wno-sign-compare");
#[cfg(feature = "whole_archive")]
{
sancov_cmp.link_lib_modifier("+whole-archive");
}
#[cfg(feature = "sancov_value_profile")] #[cfg(feature = "sancov_value_profile")]
{ {
@ -133,37 +140,91 @@ fn main() {
let mut libfuzzer = cc::Build::new(); let mut libfuzzer = cc::Build::new();
libfuzzer.file(src_dir.join("libfuzzer.c")); libfuzzer.file(src_dir.join("libfuzzer.c"));
#[cfg(feature = "whole_archive")]
{
libfuzzer.link_lib_modifier("+whole-archive");
}
#[cfg(feature = "libfuzzer_no_link_main")] #[cfg(feature = "libfuzzer_no_link_main")]
libfuzzer.define("FUZZER_NO_LINK_MAIN", "1"); libfuzzer.define("FUZZER_NO_LINK_MAIN", "1");
#[cfg(feature = "libfuzzer_define_run_driver")] #[cfg(feature = "libfuzzer_define_run_driver")]
libfuzzer.define("FUZZER_DEFINE_RUN_DRIVER", "1"); libfuzzer.define("FUZZER_DEFINE_RUN_DRIVER", "1");
libfuzzer.compile("libfuzzer"); 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(); cc::Build::new()
interceptors.file(src_dir.join("libfuzzer/FuzzerInterceptors.cpp")); .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"); #[cfg(feature = "forkserver")]
println!("cargo:rerun-if-changed=src/common.c"); {
#[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")] #[cfg(feature = "sanitizer_interfaces")]
if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" { if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" {
println!("cargo:rerun-if-changed=src/sanitizer_interfaces.h"); println!("cargo:rerun-if-changed=src/sanitizer_interfaces.h");
@ -185,99 +246,6 @@ fn main() {
write!(file, "").unwrap(); 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:rustc-link-search=native={}", &out_dir);
println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=build.rs");

View File

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

View File

@ -14,8 +14,9 @@ use libafl::{
}; };
use libafl_bolts::{ownedref::OwnedMutPtr, Named}; 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` /// A [`CmpObserver`] observer for `CmpLog`
#[derive(Debug)] #[derive(Debug)]
pub struct CmpLogObserver { 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 /// Creates a new [`CmpLogObserver`] with the given name from the default cmplog map
#[must_use] #[must_use]
pub fn new(name: &'static str, add_meta: bool) -> Self { pub fn new(name: &'static str, add_meta: bool) -> Self {

View File

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