Skip to content

Commit 0018b7c

Browse files
addisoncrumptokatoka
authored andcommitted
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
1 parent fa2f11e commit 0018b7c

File tree

6 files changed

+157
-14
lines changed

6 files changed

+157
-14
lines changed

.github/workflows/build_and_test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ jobs:
124124
with:
125125
profile: minimal
126126
toolchain: stable
127+
components: llvm-tools
127128
- name: Remove existing clang and LLVM
128129
run: sudo apt purge llvm* clang*
129130
- name: Install and cache deps

libafl_libfuzzer/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ introspection = []
3535
## `-fsanitize=fuzzer-no-link -l:libafl_libfuzzer_runtime.a`
3636
embed-runtime = []
3737

38+
## 🐇
39+
rabbit = []
40+
3841
[dependencies]
3942
libfuzzer-sys = { version = "0.4.7", default-features = false }
4043
document-features = { version = "0.2" }

libafl_libfuzzer/build.rs

Lines changed: 148 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
use std::{path::PathBuf, process::Command};
2-
1+
use std::{
2+
fs::File,
3+
io::{BufRead, BufReader, BufWriter, Write},
4+
path::PathBuf,
5+
process::{Command, Stdio},
6+
};
7+
8+
#[cfg(feature = "rabbit")]
9+
const NAMESPACE: &str = "🐇";
10+
#[cfg(not(feature = "rabbit"))]
11+
const NAMESPACE: &str = "__libafl";
12+
const NAMESPACE_LEN: usize = NAMESPACE.as_bytes().len();
13+
14+
#[allow(clippy::too_many_lines)]
315
fn main() {
416
if cfg!(any(feature = "cargo-clippy", docsrs)) {
517
return; // skip when clippy or docs is running
@@ -69,20 +81,143 @@ fn main() {
6981
let mut lib_path = custom_lib_dir.join(std::env::var_os("TARGET").unwrap());
7082
lib_path.push("release");
7183

72-
#[cfg(all(feature = "embed-runtime", target_family = "unix"))]
73-
{
74-
// NOTE: lib, .a are added always on unix-like systems as described in:
75-
// https://gist.github.com/novafacing/1389cbb2f0a362d7eb103e67b4468e2b
84+
if cfg!(target_family = "unix") {
85+
use std::path::Path;
86+
87+
lib_path.push("libafl_libfuzzer_runtime.a");
88+
let target_libdir = Command::new("rustc")
89+
.args(["--print", "target-libdir"])
90+
.output()
91+
.expect("Couldn't find rustc's target-libdir");
92+
let target_libdir = String::from_utf8(target_libdir.stdout).unwrap();
93+
let target_libdir = Path::new(target_libdir.trim());
94+
95+
let rust_lld = target_libdir.join("../bin/rust-lld");
96+
let rust_ar = target_libdir.join("../bin/llvm-ar"); // NOTE: depends on llvm-tools
97+
let rust_objcopy = target_libdir.join("../bin/llvm-objcopy"); // NOTE: depends on llvm-tools
98+
let nm = "nm"; // NOTE: we use system nm here because llvm-nm doesn't respect the encoding?
99+
100+
let redefined_symbols = custom_lib_dir.join("redefs.txt");
101+
102+
let objfile_orig = custom_lib_dir.join("libFuzzer.o");
103+
let objfile_dest = custom_lib_dir.join("libFuzzer-mimalloc.o");
104+
105+
let mut command = Command::new(rust_lld);
106+
command
107+
.args(["-flavor", "gnu"])
108+
.arg("-r")
109+
.arg("--whole-archive")
110+
.arg(lib_path)
111+
.args(["-o", objfile_orig.to_str().expect("Invalid path characters present in your current directory prevent us from linking to the runtime")]);
112+
113+
assert!(
114+
!command.status().map(|s| !s.success()).unwrap_or(true),
115+
"Couldn't link runtime crate! Do you have the llvm-tools component installed?"
116+
);
117+
118+
let mut child = Command::new(nm)
119+
.arg(&objfile_orig)
120+
.stdout(Stdio::piped())
121+
.spawn()
122+
.unwrap();
123+
124+
let mut redefinitions_file = BufWriter::new(File::create(&redefined_symbols).unwrap());
125+
126+
let replacement = format!("_ZN{NAMESPACE_LEN}{NAMESPACE}");
127+
128+
// redefine all the rust-mangled symbols we can
129+
// TODO this will break when v0 mangling is stabilised
130+
for line in BufReader::new(child.stdout.take().unwrap()).lines() {
131+
let line = line.unwrap();
132+
let (_, symbol) = line.rsplit_once(' ').unwrap();
133+
if symbol.starts_with("_ZN") {
134+
writeln!(
135+
redefinitions_file,
136+
"{} {}",
137+
symbol,
138+
symbol.replacen("_ZN", &replacement, 1)
139+
)
140+
.unwrap();
141+
}
142+
}
143+
redefinitions_file.flush().unwrap();
144+
drop(redefinitions_file);
145+
146+
assert!(
147+
!child.wait().map(|s| !s.success()).unwrap_or(true),
148+
"Couldn't link runtime crate! Do you have the llvm-tools component installed?"
149+
);
150+
151+
let mut command = Command::new(rust_objcopy);
152+
153+
for symbol in [
154+
"__rust_drop_panic",
155+
"__rust_foreign_exception",
156+
"rust_begin_unwind",
157+
"rust_panic",
158+
"rust_eh_personality",
159+
"__rg_oom",
160+
"__rdl_oom",
161+
"__rdl_alloc",
162+
"__rust_alloc",
163+
"__rdl_dealloc",
164+
"__rust_dealloc",
165+
"__rdl_realloc",
166+
"__rust_realloc",
167+
"__rdl_alloc_zeroed",
168+
"__rust_alloc_zeroed",
169+
"__rust_alloc_error_handler",
170+
"__rust_no_alloc_shim_is_unstable",
171+
"__rust_alloc_error_handler_should_panic",
172+
] {
173+
command
174+
.arg("--redefine-sym")
175+
.arg(format!("{symbol}={symbol}_libafl_libfuzzer_runtime"));
176+
}
177+
178+
command
179+
.arg("--redefine-syms")
180+
.arg(redefined_symbols)
181+
.args([&objfile_orig, &objfile_dest]);
182+
183+
assert!(
184+
!command.status().map(|s| !s.success()).unwrap_or(true),
185+
"Couldn't rename allocators in the runtime crate! Do you have the llvm-tools component installed?"
186+
);
187+
188+
let mut command = Command::new(rust_ar);
189+
command
190+
.arg("cr")
191+
.arg(custom_lib_dir.join("libFuzzer.a"))
192+
.arg(objfile_dest);
193+
194+
assert!(
195+
!command.status().map(|s| !s.success()).unwrap_or(true),
196+
"Couldn't create runtime archive!"
197+
);
198+
199+
#[cfg(feature = "embed-runtime")]
200+
{
201+
// NOTE: lib, .a are added always on unix-like systems as described in:
202+
// https://gist.github.com/novafacing/1389cbb2f0a362d7eb103e67b4468e2b
203+
println!(
204+
"cargo:rustc-env=LIBAFL_LIBFUZZER_RUNTIME_PATH={}",
205+
custom_lib_dir.join("libFuzzer.a").display()
206+
);
207+
}
208+
76209
println!(
77-
"cargo:rustc-env=LIBAFL_LIBFUZZER_RUNTIME_PATH={}",
78-
lib_path.join("libafl_libfuzzer_runtime.a").display()
210+
"cargo:rustc-link-search=native={}",
211+
custom_lib_dir.to_str().unwrap()
79212
);
213+
println!("cargo:rustc-link-lib=static=Fuzzer");
214+
} else {
215+
println!(
216+
"cargo:rustc-link-search=native={}",
217+
lib_path.to_str().unwrap()
218+
);
219+
println!("cargo:rustc-link-lib=static=afl_fuzzer_runtime");
80220
}
81221

82-
println!(
83-
"cargo:rustc-link-search=native={}",
84-
lib_path.to_str().unwrap()
85-
);
86-
println!("cargo:rustc-link-lib=static=afl_libfuzzer_runtime");
87222
println!("cargo:rustc-link-lib=stdc++");
88223
}

libafl_libfuzzer/libafl_libfuzzer_runtime/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ libafl_targets = { path = "../../libafl_targets", features = ["sancov_8bit", "sa
3737
ahash = { version = "0.8.3", default-features = false }
3838
libc = "0.2.139"
3939
log = "0.4.17"
40-
mimalloc = { version = "0.1.34", default-features = false, optional = true }
40+
mimalloc = { version = "0.1.34", default-features = false }
4141
num-traits = "0.2.15"
4242
rand = "0.8.5"
4343
serde = { version = "1.0", features = ["derive"] } # serialization lib

libafl_libfuzzer/libafl_libfuzzer_runtime/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{env, path::Path};
22

3+
#[allow(clippy::too_many_lines)]
34
fn main() {
45
let out_dir = env::var_os("OUT_DIR").unwrap();
56

libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,11 @@ use libafl::{
8080
};
8181
use libafl_bolts::AsSlice;
8282
use libc::_exit;
83+
use mimalloc::MiMalloc;
8384

8485
use crate::options::{LibfuzzerMode, LibfuzzerOptions};
86+
#[global_allocator]
87+
static GLOBAL: MiMalloc = MiMalloc;
8588

8689
mod corpus;
8790
mod feedbacks;

0 commit comments

Comments
 (0)