Skip to content

Commit

Permalink
Fix broken closure hooks in libafl_qemu (#1839)
Browse files Browse the repository at this point in the history
* Fix broken crash hook

* fix hooks

* clippy

* pin
  • Loading branch information
andreafioraldi committed Feb 7, 2024
1 parent 9b82af4 commit 41d24ca
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 185 deletions.
4 changes: 3 additions & 1 deletion libafl_qemu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,11 @@ systemmode = ["libafl_qemu_sys/systemmode"]
## Automatically register all `#[derive(SerdeAny)]` types at startup.
serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"]

## Automatically register all `#[derive(SerdeAny)]` types at startup.
slirp = [ "systemmode", "libafl_qemu_sys/slirp" ] # build qemu with host libslirp (for user networking)

# disabled atm, enabled when fixed with dynamic list
# shared = [ "libafl_qemu_sys/shared" ]

[dependencies]
libafl = { path = "../libafl", version = "0.11.2", default-features = false, features = ["std", "derive", "regex"] }
libafl_bolts = { path = "../libafl_bolts", version = "0.11.2", default-features = false, features = ["std", "derive"] }
Expand Down
2 changes: 1 addition & 1 deletion libafl_qemu/build_linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,6 @@ pub fn build() {
.status()
.expect("make failed")
.success());
println!("cargo:rerun-if-changed={}/libqasan.so", target_dir.display());
// println!("cargo:rerun-if-changed={}/libqasan.so", target_dir.display());
}
}
1 change: 1 addition & 0 deletions libafl_qemu/libafl_qemu_build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ categories = [
all-features = true

[features]
shared = []
slirp = [] # build qemu with host libslirp (for user networking)

clippy = [] # special feature for clippy, don't use in normal projects§
Expand Down
276 changes: 149 additions & 127 deletions libafl_qemu/libafl_qemu_build/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
const QEMU_REVISION: &str = "75d15d54f4417a4766d2dcb493982d9df0e8eac4";

pub struct BuildResult {
pub qemu_path: PathBuf,
pub build_dir: PathBuf,
}

fn build_dep_check(tools: &[&str]) {
for tool in tools {
which(tool).unwrap_or_else(|_| panic!("Build tool {tool} not found"));
Expand All @@ -23,7 +28,7 @@ pub fn build(
is_big_endian: bool,
is_usermode: bool,
jobs: Option<u32>,
) -> (PathBuf, PathBuf) {
) -> BuildResult {
let mut cpu_target = cpu_target.to_string();
// qemu-system-arm supports both big and little endian configurations and so
// therefore the "be" feature should ignored in this configuration. Also
Expand Down Expand Up @@ -120,13 +125,19 @@ pub fn build(
"softmmu".to_string()
};

let output_lib = if is_usermode {
build_dir.join(format!("libqemu-{cpu_target}.so"))
let (output_lib, output_lib_link) = if is_usermode {
(
build_dir.join(format!("libqemu-{cpu_target}.so")),
format!("qemu-{cpu_target}"),
)
} else {
build_dir.join(format!("libqemu-system-{cpu_target}.so"))
(
build_dir.join(format!("libqemu-system-{cpu_target}.so")),
format!("qemu-system-{cpu_target}"),
)
};

println!("cargo:rerun-if-changed={}", output_lib.to_string_lossy());
// println!("cargo:rerun-if-changed={}", output_lib.to_string_lossy());

if !output_lib.is_file() || (custom_qemu_dir.is_some() && !custom_qemu_no_build) {
/*drop(
Expand Down Expand Up @@ -337,137 +348,145 @@ pub fn build(
}
*/

let compile_commands_string =
&fs::read_to_string(build_dir.join("linkinfo.json")).expect("Failed to read linkinfo.json");
if cfg!(feature = "shared") {
println!(
"cargo:rustc-link-search=native={}",
build_dir.to_string_lossy()
);
println!("cargo:rustc-link-lib=dylib={output_lib_link}");
} else {
let compile_commands_string = &fs::read_to_string(build_dir.join("linkinfo.json"))
.expect("Failed to read linkinfo.json");

let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json");
let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json");

let mut cmd = vec![];
for arg in linkinfo["cmd"].members() {
cmd.push(
arg.as_str()
.expect("linkinfo.json `cmd` values must be strings"),
);
}
let mut cmd = vec![];
for arg in linkinfo["cmd"].members() {
cmd.push(
arg.as_str()
.expect("linkinfo.json `cmd` values must be strings"),
);
}

assert!(cpp_compiler
.to_command()
.current_dir(&build_dir)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(cmd)
.status()
.expect("Partial linked failure")
.success());

/* // Old manual linking, kept here for reference and debugging
if is_usermode {
Command::new("ld")
.current_dir(out_dir_path)
assert!(cpp_compiler
.to_command()
.current_dir(&build_dir)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(objects)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.args(cmd)
.status()
.expect("Partial linked failure");
} else {
Command::new("ld")
.expect("Partial linked failure")
.success());

/* // Old manual linking, kept here for reference and debugging
if is_usermode {
Command::new("ld")
.current_dir(out_dir_path)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(objects)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_user.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.status()
.expect("Partial linked failure");
} else {
Command::new("ld")
.current_dir(out_dir_path)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(objects)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!(
"{}/subprojects/dtc/libfdt/libfdt.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user-glib.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvduse/libvduse.a",
build_dir.display()
))
.arg(format!("{}/libmigration.fa", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.status()
.expect("Partial linked failure");
}*/

Command::new("ar")
.current_dir(out_dir_path)
.arg("-o")
.arg("libqemu-partially-linked.o")
.arg("-r")
.args(objects)
.arg("--start-group")
.arg("--whole-archive")
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/libevent-loop-base.a", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg("--no-whole-archive")
.arg(format!("{}/libqemuutil.a", build_dir.display()))
.arg(format!(
"{}/subprojects/dtc/libfdt/libfdt.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user-glib.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvhost-user/libvhost-user.a",
build_dir.display()
))
.arg(format!(
"{}/subprojects/libvduse/libvduse.a",
build_dir.display()
))
.arg(format!("{}/libmigration.fa", build_dir.display()))
.arg(format!("{}/libhwcore.fa", build_dir.display()))
.arg(format!("{}/libqom.fa", build_dir.display()))
.arg(format!("{}/gdbstub/libgdb_softmmu.fa", build_dir.display()))
.arg(format!("{}/libio.fa", build_dir.display()))
.arg(format!("{}/libcrypto.fa", build_dir.display()))
.arg(format!("{}/libauthz.fa", build_dir.display()))
.arg(format!("{}/libblockdev.fa", build_dir.display()))
.arg(format!("{}/libblock.fa", build_dir.display()))
.arg(format!("{}/libchardev.fa", build_dir.display()))
.arg(format!("{}/libqmp.fa", build_dir.display()))
.arg(format!(
"--dynamic-list={}/plugins/qemu-plugins.symbols",
qemu_path.display()
))
.arg("--end-group")
.arg("crs")
.arg("libqemu-partially-linked.a")
.arg(build_dir.join("libqemu-partially-linked.o"))
.status()
.expect("Partial linked failure");
}*/

Command::new("ar")
.current_dir(out_dir_path)
.arg("crs")
.arg("libqemu-partially-linked.a")
.arg(build_dir.join("libqemu-partially-linked.o"))
.status()
.expect("Ar creation");

println!("cargo:rustc-link-search=native={out_dir}");
println!("cargo:rustc-link-lib=static=qemu-partially-linked");

for arg in linkinfo["search"].members() {
let val = arg
.as_str()
.expect("linkinfo.json `search` values must be strings");
println!("cargo:rustc-link-search={val}");
}
.expect("Ar creation");

for arg in linkinfo["libs"].members() {
let val = arg
.as_str()
.expect("linkinfo.json `libs` values must be strings");
println!("cargo:rustc-link-lib={val}");
println!("cargo:rustc-link-search=native={out_dir}");
println!("cargo:rustc-link-lib=static=qemu-partially-linked");

for arg in linkinfo["search"].members() {
let val = arg
.as_str()
.expect("linkinfo.json `search` values must be strings");
println!("cargo:rustc-link-search={val}");
}

for arg in linkinfo["libs"].members() {
let val = arg
.as_str()
.expect("linkinfo.json `libs` values must be strings");
println!("cargo:rustc-link-lib={val}");
}
}

/*
Expand Down Expand Up @@ -500,5 +519,8 @@ pub fn build(
}
}

(qemu_path, build_dir)
BuildResult {
qemu_path,
build_dir,
}
}
12 changes: 9 additions & 3 deletions libafl_qemu/libafl_qemu_build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,16 @@ pub fn build_with_bindings(
jobs: Option<u32>,
bindings_file: &Path,
) {
let (qemu_dir, build_dir) = build::build(cpu_target, is_big_endian, is_usermode, jobs);
let clang_args = qemu_bindgen_clang_args(&qemu_dir, &build_dir, cpu_target, is_usermode);
let build_result = build::build(cpu_target, is_big_endian, is_usermode, jobs);

let bind = bindings::generate(&build_dir, cpu_target, clang_args)
let clang_args = qemu_bindgen_clang_args(
&build_result.qemu_path,
&build_result.build_dir,
cpu_target,
is_usermode,
);

let bind = bindings::generate(&build_result.build_dir, cpu_target, clang_args)
.expect("Failed to generate the bindings");
bind.write_to_file(bindings_file)
.expect("Faield to write to the bindings file");
Expand Down
1 change: 1 addition & 0 deletions libafl_qemu/libafl_qemu_sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ usermode = []
systemmode = []

slirp = [ "systemmode", "libafl_qemu_build/slirp" ] # build qemu with host libslirp (for user networking)
shared = [ "libafl_qemu_build/shared" ]

clippy = [ "libafl_qemu_build/clippy" ] # special feature for clippy, don't use in normal projects§

Expand Down
Loading

0 comments on commit 41d24ca

Please sign in to comment.