libafl_libfuzzer: rename all symbols and allow mimalloc use (#1565)

* rename allocator symbols to avoid conflict with mimalloc

* re-add llvm-tools to CI

* rename everything

* fixup clippy lint

* make fuzzer entries more noticeable :)

* rabbit mode

* clippy
This commit is contained in:
Addison Crump 2023-11-20 21:55:40 +01:00 committed by GitHub
parent aa69436b64
commit 1e96652ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 157 additions and 14 deletions

View File

@ -124,6 +124,7 @@ jobs:
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: stable
components: llvm-tools
- name: Remove existing clang and LLVM - name: Remove existing clang and LLVM
run: sudo apt purge llvm* clang* run: sudo apt purge llvm* clang*
- name: Install and cache deps - name: Install and cache deps

View File

@ -35,6 +35,9 @@ introspection = []
## `-fsanitize=fuzzer-no-link -l:libafl_libfuzzer_runtime.a` ## `-fsanitize=fuzzer-no-link -l:libafl_libfuzzer_runtime.a`
embed-runtime = [] embed-runtime = []
## 🐇
rabbit = []
[dependencies] [dependencies]
libfuzzer-sys = { version = "0.4.7", default-features = false } libfuzzer-sys = { version = "0.4.7", default-features = false }
document-features = { version = "0.2" } document-features = { version = "0.2" }

View File

@ -1,5 +1,17 @@
use std::{path::PathBuf, process::Command}; use std::{
fs::File,
io::{BufRead, BufReader, BufWriter, Write},
path::PathBuf,
process::{Command, Stdio},
};
#[cfg(feature = "rabbit")]
const NAMESPACE: &str = "🐇";
#[cfg(not(feature = "rabbit"))]
const NAMESPACE: &str = "__libafl";
const NAMESPACE_LEN: usize = NAMESPACE.as_bytes().len();
#[allow(clippy::too_many_lines)]
fn main() { fn main() {
if cfg!(any(feature = "cargo-clippy", docsrs)) { if cfg!(any(feature = "cargo-clippy", docsrs)) {
return; // skip when clippy or docs is running return; // skip when clippy or docs is running
@ -69,20 +81,143 @@ fn main() {
let mut lib_path = custom_lib_dir.join(std::env::var_os("TARGET").unwrap()); let mut lib_path = custom_lib_dir.join(std::env::var_os("TARGET").unwrap());
lib_path.push("release"); lib_path.push("release");
#[cfg(all(feature = "embed-runtime", target_family = "unix"))] if cfg!(target_family = "unix") {
use std::path::Path;
lib_path.push("libafl_libfuzzer_runtime.a");
let target_libdir = Command::new("rustc")
.args(["--print", "target-libdir"])
.output()
.expect("Couldn't find rustc's target-libdir");
let target_libdir = String::from_utf8(target_libdir.stdout).unwrap();
let target_libdir = Path::new(target_libdir.trim());
let rust_lld = target_libdir.join("../bin/rust-lld");
let rust_ar = target_libdir.join("../bin/llvm-ar"); // NOTE: depends on llvm-tools
let rust_objcopy = target_libdir.join("../bin/llvm-objcopy"); // NOTE: depends on llvm-tools
let nm = "nm"; // NOTE: we use system nm here because llvm-nm doesn't respect the encoding?
let redefined_symbols = custom_lib_dir.join("redefs.txt");
let objfile_orig = custom_lib_dir.join("libFuzzer.o");
let objfile_dest = custom_lib_dir.join("libFuzzer-mimalloc.o");
let mut command = Command::new(rust_lld);
command
.args(["-flavor", "gnu"])
.arg("-r")
.arg("--whole-archive")
.arg(lib_path)
.args(["-o", objfile_orig.to_str().expect("Invalid path characters present in your current directory prevent us from linking to the runtime")]);
assert!(
!command.status().map(|s| !s.success()).unwrap_or(true),
"Couldn't link runtime crate! Do you have the llvm-tools component installed?"
);
let mut child = Command::new(nm)
.arg(&objfile_orig)
.stdout(Stdio::piped())
.spawn()
.unwrap();
let mut redefinitions_file = BufWriter::new(File::create(&redefined_symbols).unwrap());
let replacement = format!("_ZN{NAMESPACE_LEN}{NAMESPACE}");
// redefine all the rust-mangled symbols we can
// TODO this will break when v0 mangling is stabilised
for line in BufReader::new(child.stdout.take().unwrap()).lines() {
let line = line.unwrap();
let (_, symbol) = line.rsplit_once(' ').unwrap();
if symbol.starts_with("_ZN") {
writeln!(
redefinitions_file,
"{} {}",
symbol,
symbol.replacen("_ZN", &replacement, 1)
)
.unwrap();
}
}
redefinitions_file.flush().unwrap();
drop(redefinitions_file);
assert!(
!child.wait().map(|s| !s.success()).unwrap_or(true),
"Couldn't link runtime crate! Do you have the llvm-tools component installed?"
);
let mut command = Command::new(rust_objcopy);
for symbol in [
"__rust_drop_panic",
"__rust_foreign_exception",
"rust_begin_unwind",
"rust_panic",
"rust_eh_personality",
"__rg_oom",
"__rdl_oom",
"__rdl_alloc",
"__rust_alloc",
"__rdl_dealloc",
"__rust_dealloc",
"__rdl_realloc",
"__rust_realloc",
"__rdl_alloc_zeroed",
"__rust_alloc_zeroed",
"__rust_alloc_error_handler",
"__rust_no_alloc_shim_is_unstable",
"__rust_alloc_error_handler_should_panic",
] {
command
.arg("--redefine-sym")
.arg(format!("{symbol}={symbol}_libafl_libfuzzer_runtime"));
}
command
.arg("--redefine-syms")
.arg(redefined_symbols)
.args([&objfile_orig, &objfile_dest]);
assert!(
!command.status().map(|s| !s.success()).unwrap_or(true),
"Couldn't rename allocators in the runtime crate! Do you have the llvm-tools component installed?"
);
let mut command = Command::new(rust_ar);
command
.arg("cr")
.arg(custom_lib_dir.join("libFuzzer.a"))
.arg(objfile_dest);
assert!(
!command.status().map(|s| !s.success()).unwrap_or(true),
"Couldn't create runtime archive!"
);
#[cfg(feature = "embed-runtime")]
{ {
// NOTE: lib, .a are added always on unix-like systems as described in: // NOTE: lib, .a are added always on unix-like systems as described in:
// https://gist.github.com/novafacing/1389cbb2f0a362d7eb103e67b4468e2b // https://gist.github.com/novafacing/1389cbb2f0a362d7eb103e67b4468e2b
println!( println!(
"cargo:rustc-env=LIBAFL_LIBFUZZER_RUNTIME_PATH={}", "cargo:rustc-env=LIBAFL_LIBFUZZER_RUNTIME_PATH={}",
lib_path.join("libafl_libfuzzer_runtime.a").display() custom_lib_dir.join("libFuzzer.a").display()
); );
} }
println!(
"cargo:rustc-link-search=native={}",
custom_lib_dir.to_str().unwrap()
);
println!("cargo:rustc-link-lib=static=Fuzzer");
} else {
println!( println!(
"cargo:rustc-link-search=native={}", "cargo:rustc-link-search=native={}",
lib_path.to_str().unwrap() lib_path.to_str().unwrap()
); );
println!("cargo:rustc-link-lib=static=afl_libfuzzer_runtime"); println!("cargo:rustc-link-lib=static=afl_fuzzer_runtime");
}
println!("cargo:rustc-link-lib=stdc++"); println!("cargo:rustc-link-lib=stdc++");
} }

View File

@ -37,7 +37,7 @@ libafl_targets = { path = "../../libafl_targets", features = ["sancov_8bit", "sa
ahash = { version = "0.8.3", default-features = false } ahash = { version = "0.8.3", default-features = false }
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
mimalloc = { version = "0.1.34", default-features = false, optional = true } mimalloc = { version = "0.1.34", default-features = false }
num-traits = "0.2.15" num-traits = "0.2.15"
rand = "0.8.5" rand = "0.8.5"
serde = { version = "1.0", features = ["derive"] } # serialization lib serde = { version = "1.0", features = ["derive"] } # serialization lib

View File

@ -1,5 +1,6 @@
use std::{env, path::Path}; use std::{env, path::Path};
#[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();

View File

@ -80,8 +80,11 @@ use libafl::{
}; };
use libafl_bolts::AsSlice; use libafl_bolts::AsSlice;
use libc::_exit; use libc::_exit;
use mimalloc::MiMalloc;
use crate::options::{LibfuzzerMode, LibfuzzerOptions}; use crate::options::{LibfuzzerMode, LibfuzzerOptions};
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
mod corpus; mod corpus;
mod feedbacks; mod feedbacks;