Rework of libafl_qemu configuration (#2054)
* LibAFL QEMU can now be dynamically linked * LibAFL QEMU reconfiguration happens less frequently (now using a signature check) * Possibility to have custom rpath in QEMU
This commit is contained in:
parent
da6118e61e
commit
bc3ef5952b
@ -12,6 +12,8 @@ classic = [] # The classic way to interact with LibAFL QEMU, with direct calls t
|
||||
breakpoint = [] # Uses the command system, with breakpoints
|
||||
sync_exit = [] # Uses the command system, with sync exit.
|
||||
|
||||
shared = ["libafl_qemu/shared"]
|
||||
|
||||
[profile.release]
|
||||
incremental = true
|
||||
debug = true
|
||||
@ -24,3 +26,6 @@ libafl_bolts = { path = "../../libafl_bolts/" }
|
||||
libafl_qemu = { path = "../../libafl_qemu/", features = ["arm", "systemmode"] }
|
||||
libafl_qemu_sys = { path = "../../libafl_qemu/libafl_qemu_sys", features = ["arm", "systemmode"] }
|
||||
env_logger = "*"
|
||||
|
||||
[build-dependencies]
|
||||
libafl_qemu_build = { path = "../../libafl_qemu/libafl_qemu_build" }
|
||||
|
@ -45,7 +45,6 @@ args = [
|
||||
"--no-default-features",
|
||||
"--features", "std,${FEATURE}",
|
||||
"--target-dir", "${TARGET_DIR}",
|
||||
"-vv",
|
||||
]
|
||||
dependencies = ["image"]
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
use libafl_qemu_build::build_libafl_qemu;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! assert_unique_feature {
|
||||
() => {};
|
||||
@ -12,4 +14,6 @@ macro_rules! assert_unique_feature {
|
||||
|
||||
fn main() {
|
||||
assert_unique_feature!("classic", "breakpoint", "sync_exit");
|
||||
|
||||
build_libafl_qemu();
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use libafl::{
|
||||
inputs::BytesInput,
|
||||
monitors::MultiMonitor,
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{CalibrationStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
|
@ -13,7 +13,7 @@ use libafl::{
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
monitors::MultiMonitor,
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::StdMutationalStage,
|
||||
state::{HasCorpus, StdState},
|
||||
|
@ -13,7 +13,7 @@ use libafl::{
|
||||
inputs::BytesInput,
|
||||
monitors::MultiMonitor,
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
|
||||
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
|
||||
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||
stages::{CalibrationStage, StdMutationalStage},
|
||||
state::{HasCorpus, StdState},
|
||||
|
@ -58,8 +58,8 @@ serdeany_autoreg = ["libafl_bolts/serdeany_autoreg"]
|
||||
|
||||
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" ]
|
||||
# Requires the binary's build.rs to call `build_libafl_qemu`
|
||||
shared = [ "libafl_qemu_sys/shared" ]
|
||||
|
||||
[dependencies]
|
||||
libafl = { path = "../libafl", version = "0.12.0", default-features = false, features = ["std", "derive", "regex"] }
|
||||
|
@ -6,9 +6,11 @@ use std::{
|
||||
|
||||
use which::which;
|
||||
|
||||
use crate::cargo_add_rpath;
|
||||
|
||||
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
|
||||
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
|
||||
const QEMU_REVISION: &str = "50b0c90e0aab07643ccb58cfbbef742bcfb8b7d1";
|
||||
const QEMU_REVISION: &str = "c9519ee8b6cb1ba54b7df1001f7f39f07218d514";
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub struct BuildResult {
|
||||
@ -22,6 +24,220 @@ fn build_dep_check(tools: &[&str]) {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_config_signature(config_cmd: &Command) -> String {
|
||||
let mut signature_string = String::new();
|
||||
|
||||
// Command env
|
||||
let config_env: String = config_cmd
|
||||
.get_envs()
|
||||
.map(|(key, value)| {
|
||||
format!(
|
||||
"\t{}={}",
|
||||
key.to_str().expect("Couldn't convert OsStr to str"),
|
||||
if let Some(v) = value {
|
||||
v.to_str().expect("Could't convert OsStr to str")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)
|
||||
})
|
||||
.reduce(|acc, elt| format!("{acc}\n{elt}"))
|
||||
.into_iter()
|
||||
.collect();
|
||||
signature_string += format!("Environment:\n{config_env}").as_str();
|
||||
|
||||
// Command args
|
||||
let config_args: String = config_cmd
|
||||
.get_args()
|
||||
.map(|arg| format!("\t{}", arg.to_str().expect("Couldn't convert OsStr to str")))
|
||||
.reduce(|acc, arg| format!("{acc}\n{arg}"))
|
||||
.into_iter()
|
||||
.collect();
|
||||
signature_string += format!("\n\nArguments:\n{config_args}").as_str();
|
||||
|
||||
signature_string
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn configure_qemu(
|
||||
cc_compiler: &cc::Tool,
|
||||
cpp_compiler: &cc::Tool,
|
||||
qemu_path: &PathBuf,
|
||||
build_dir: &Path,
|
||||
is_usermode: bool,
|
||||
cpu_target: &String,
|
||||
target_suffix: &String,
|
||||
) -> Command {
|
||||
let mut cmd = Command::new("./configure");
|
||||
|
||||
// Set common options for usermode and systemmode
|
||||
cmd.current_dir(qemu_path)
|
||||
.env("__LIBAFL_QEMU_CONFIGURE", "")
|
||||
.env("__LIBAFL_QEMU_BUILD_OUT", build_dir.join("linkinfo.json"))
|
||||
.env("__LIBAFL_QEMU_BUILD_CC", cc_compiler.path())
|
||||
.env("__LIBAFL_QEMU_BUILD_CXX", cpp_compiler.path())
|
||||
.arg(&format!(
|
||||
"--cc={}",
|
||||
qemu_path.join("linker_interceptor.py").display()
|
||||
))
|
||||
.arg(&format!(
|
||||
"--cxx={}",
|
||||
qemu_path.join("linker_interceptor++.py").display()
|
||||
))
|
||||
.arg("--as-shared-lib")
|
||||
.arg(&format!("--target-list={cpu_target}-{target_suffix}"))
|
||||
.arg("--disable-bsd-user")
|
||||
.arg("--disable-capstone");
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
// cmd.arg("--enable-debug");
|
||||
// .arg("--enable-debug-tcg");
|
||||
}
|
||||
|
||||
if is_usermode {
|
||||
// Usermode options
|
||||
cmd.args(["--disable-fdt", "--disable-system"]);
|
||||
} else {
|
||||
// Systemmode options
|
||||
cmd.arg(if cfg!(feature = "slirp") {
|
||||
"--enable-slirp"
|
||||
} else {
|
||||
"--disable-slirp"
|
||||
})
|
||||
.arg("--enable-fdt=internal")
|
||||
.arg("--audio-drv-list=")
|
||||
.arg("--disable-af-xdp")
|
||||
.arg("--disable-alsa")
|
||||
.arg("--disable-attr")
|
||||
.arg("--disable-auth-pam")
|
||||
.arg("--disable-dbus-display")
|
||||
.arg("--disable-bochs")
|
||||
.arg("--disable-bpf")
|
||||
.arg("--disable-brlapi")
|
||||
.arg("--disable-bzip2")
|
||||
.arg("--disable-cap-ng")
|
||||
.arg("--disable-canokey")
|
||||
.arg("--disable-cloop")
|
||||
.arg("--disable-cocoa")
|
||||
.arg("--disable-coreaudio")
|
||||
.arg("--disable-curl")
|
||||
.arg("--disable-curses")
|
||||
.arg("--disable-dmg")
|
||||
.arg("--disable-docs")
|
||||
.arg("--disable-dsound")
|
||||
.arg("--disable-fuse")
|
||||
.arg("--disable-fuse-lseek")
|
||||
.arg("--disable-gcrypt")
|
||||
.arg("--disable-gettext")
|
||||
.arg("--disable-gio")
|
||||
.arg("--disable-glusterfs")
|
||||
.arg("--disable-gnutls")
|
||||
.arg("--disable-gtk")
|
||||
.arg("--disable-guest-agent")
|
||||
.arg("--disable-guest-agent-msi")
|
||||
.arg("--disable-hvf")
|
||||
.arg("--disable-iconv")
|
||||
.arg("--disable-jack")
|
||||
.arg("--disable-keyring")
|
||||
.arg("--disable-kvm")
|
||||
.arg("--disable-libdaxctl")
|
||||
.arg("--disable-libiscsi")
|
||||
.arg("--disable-libnfs")
|
||||
.arg("--disable-libpmem")
|
||||
.arg("--disable-libssh")
|
||||
.arg("--disable-libudev")
|
||||
.arg("--disable-libusb")
|
||||
.arg("--disable-linux-aio")
|
||||
.arg("--disable-linux-io-uring")
|
||||
.arg("--disable-linux-user")
|
||||
.arg("--disable-live-block-migration")
|
||||
.arg("--disable-lzfse")
|
||||
.arg("--disable-lzo")
|
||||
.arg("--disable-l2tpv3")
|
||||
.arg("--disable-malloc-trim")
|
||||
.arg("--disable-mpath")
|
||||
.arg("--disable-multiprocess")
|
||||
.arg("--disable-netmap")
|
||||
.arg("--disable-nettle")
|
||||
.arg("--disable-numa")
|
||||
.arg("--disable-nvmm")
|
||||
.arg("--disable-opengl")
|
||||
.arg("--disable-oss")
|
||||
.arg("--disable-pa")
|
||||
.arg("--disable-parallels")
|
||||
.arg("--disable-png")
|
||||
.arg("--disable-pvrdma")
|
||||
.arg("--disable-qcow1")
|
||||
.arg("--disable-qed")
|
||||
.arg("--disable-qga-vss")
|
||||
.arg("--disable-rbd")
|
||||
.arg("--disable-rdma")
|
||||
.arg("--disable-replication")
|
||||
.arg("--disable-sdl")
|
||||
.arg("--disable-sdl-image")
|
||||
.arg("--disable-seccomp")
|
||||
.arg("--disable-selinux")
|
||||
.arg("--disable-slirp-smbd")
|
||||
.arg("--disable-smartcard")
|
||||
.arg("--disable-snappy")
|
||||
.arg("--disable-sndio")
|
||||
.arg("--disable-sparse")
|
||||
.arg("--disable-spice")
|
||||
.arg("--disable-spice-protocol")
|
||||
.arg("--disable-tools")
|
||||
.arg("--disable-tpm")
|
||||
.arg("--disable-usb-redir")
|
||||
.arg("--disable-user")
|
||||
.arg("--disable-u2f")
|
||||
.arg("--disable-vde")
|
||||
.arg("--disable-vdi")
|
||||
.arg("--disable-vduse-blk-export")
|
||||
.arg("--disable-vhost-crypto")
|
||||
.arg("--disable-vhost-kernel")
|
||||
.arg("--disable-vhost-net")
|
||||
.arg("--disable-vhost-user-blk-server")
|
||||
.arg("--disable-vhost-vdpa")
|
||||
.arg("--disable-virglrenderer")
|
||||
.arg("--disable-virtfs")
|
||||
.arg("--disable-vmnet")
|
||||
.arg("--disable-vnc")
|
||||
.arg("--disable-vnc-jpeg")
|
||||
.arg("--disable-vnc-sasl")
|
||||
.arg("--disable-vte")
|
||||
.arg("--disable-vvfat")
|
||||
.arg("--disable-whpx")
|
||||
.arg("--disable-xen")
|
||||
.arg("--disable-xen-pci-passthrough")
|
||||
.arg("--disable-xkbcommon")
|
||||
.arg("--disable-zstd")
|
||||
.arg("--disable-tests");
|
||||
}
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
fn build_qemu(
|
||||
cc_compiler: &cc::Tool,
|
||||
cpp_compiler: &cc::Tool,
|
||||
build_dir: &PathBuf,
|
||||
jobs: Option<u32>,
|
||||
) -> Command {
|
||||
let mut cmd = Command::new("make");
|
||||
|
||||
cmd.current_dir(build_dir)
|
||||
.env("__LIBAFL_QEMU_CONFIGURE", "")
|
||||
.env("__LIBAFL_QEMU_BUILD_OUT", build_dir.join("linkinfo.json"))
|
||||
.env("__LIBAFL_QEMU_BUILD_CC", cc_compiler.path())
|
||||
.env("__LIBAFL_QEMU_BUILD_CXX", cpp_compiler.path())
|
||||
.arg("-j");
|
||||
|
||||
if let Some(j) = jobs {
|
||||
cmd.arg(&format!("{j}")).env("V", "1");
|
||||
}
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines, clippy::missing_panics_doc)]
|
||||
#[must_use]
|
||||
pub fn build(
|
||||
@ -32,7 +248,7 @@ pub fn build(
|
||||
) -> 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
|
||||
// the "be" feature should be ignored in this configuration. Also
|
||||
// ignore the feature if we are running in clippy which enables all the
|
||||
// features at once (disabling the check for mutually exclusive options)
|
||||
// resulting in cpu_target being set to 'x86_64' above which obviously
|
||||
@ -49,12 +265,13 @@ pub fn build(
|
||||
cpu_target += "el";
|
||||
}
|
||||
|
||||
let custom_qemu_dir = env::var_os("CUSTOM_QEMU_DIR").map(|x| x.to_string_lossy().to_string());
|
||||
let custom_qemu_no_build = env::var("CUSTOM_QEMU_NO_BUILD").is_ok();
|
||||
let custom_qemu_no_configure = env::var("CUSTOM_QEMU_NO_CONFIGURE").is_ok();
|
||||
println!("cargo:rerun-if-env-changed=CUSTOM_QEMU_DIR");
|
||||
println!("cargo:rerun-if-env-changed=CUSTOM_QEMU_NO_BUILD");
|
||||
println!("cargo:rerun-if-env-changed=CUSTOM_QEMU_NO_CONFIGURE");
|
||||
let libafl_qemu_dir = env::var_os("LIBAFL_QEMU_DIR").map(|x| x.to_string_lossy().to_string());
|
||||
let libafl_qemu_force_configure = env::var("LIBAFL_QEMU_FORCE_CONFIGURE").is_ok();
|
||||
let libafl_qemu_no_build = env::var("LIBAFL_QEMU_NO_BUILD").is_ok();
|
||||
|
||||
println!("cargo:rerun-if-env-changed=LIBAFL_QEMU_DIR");
|
||||
println!("cargo:rerun-if-env-changed=LIBAFL_QEMU_FORCE_CONFIGURE");
|
||||
println!("cargo:rerun-if-env-changed=LIBAFL_QEMU_NO_BUILD");
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let out_dir = out_dir.to_string_lossy().to_string();
|
||||
@ -69,7 +286,7 @@ pub fn build(
|
||||
let cc_compiler = cc::Build::new().cpp(false).get_compiler();
|
||||
let cpp_compiler = cc::Build::new().cpp(true).get_compiler();
|
||||
|
||||
let qemu_path = if let Some(qemu_dir) = custom_qemu_dir.as_ref() {
|
||||
let qemu_path = if let Some(qemu_dir) = libafl_qemu_dir.as_ref() {
|
||||
Path::new(&qemu_dir).to_path_buf()
|
||||
} else {
|
||||
let qemu_path = target_dir.join(QEMU_DIRNAME);
|
||||
@ -122,7 +339,8 @@ pub fn build(
|
||||
qemu_path
|
||||
};
|
||||
|
||||
let build_dir = qemu_path.join("build");
|
||||
let qemu_build_dir = qemu_path.join("build");
|
||||
let config_signature_path = qemu_build_dir.join("libafl_config");
|
||||
|
||||
let target_suffix = if is_usermode {
|
||||
"linux-user".to_string()
|
||||
@ -132,188 +350,71 @@ pub fn build(
|
||||
|
||||
let (output_lib, output_lib_link) = if is_usermode {
|
||||
(
|
||||
build_dir.join(format!("libqemu-{cpu_target}.so")),
|
||||
qemu_build_dir.join(format!("libqemu-{cpu_target}.so")),
|
||||
format!("qemu-{cpu_target}"),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
build_dir.join(format!("libqemu-system-{cpu_target}.so")),
|
||||
qemu_build_dir.join(format!("libqemu-system-{cpu_target}.so")),
|
||||
format!("qemu-system-{cpu_target}"),
|
||||
)
|
||||
};
|
||||
|
||||
// println!("cargo:rerun-if-changed={}", output_lib.to_string_lossy());
|
||||
let libafl_config_old_signature = fs::read_to_string(&config_signature_path);
|
||||
|
||||
if !output_lib.is_file() || (custom_qemu_dir.is_some() && !custom_qemu_no_build) {
|
||||
/*drop(
|
||||
Command::new("make")
|
||||
.current_dir(&qemu_path)
|
||||
.arg("distclean")
|
||||
.status(),
|
||||
);*/
|
||||
let mut cmd = Command::new("./configure");
|
||||
cmd.current_dir(&qemu_path)
|
||||
//.arg("--as-static-lib")
|
||||
.env("__LIBAFL_QEMU_BUILD_OUT", build_dir.join("linkinfo.json"))
|
||||
.env("__LIBAFL_QEMU_BUILD_CC", cc_compiler.path())
|
||||
.env("__LIBAFL_QEMU_BUILD_CXX", cpp_compiler.path())
|
||||
.arg(&format!(
|
||||
"--cc={}",
|
||||
qemu_path.join("linker_interceptor.py").display()
|
||||
))
|
||||
.arg(&format!(
|
||||
"--cxx={}",
|
||||
qemu_path.join("linker_interceptor++.py").display()
|
||||
))
|
||||
.arg("--as-shared-lib")
|
||||
.arg(&format!("--target-list={cpu_target}-{target_suffix}"));
|
||||
if cfg!(feature = "debug_assertions") {
|
||||
cmd.arg("--enable-debug");
|
||||
}
|
||||
if is_usermode && !custom_qemu_no_configure {
|
||||
cmd.args([
|
||||
"--disable-bsd-user",
|
||||
"--disable-fdt",
|
||||
"--disable-system",
|
||||
"--disable-capstone",
|
||||
]);
|
||||
} else if !custom_qemu_no_configure {
|
||||
cmd.arg(if cfg!(feature = "slirp") {
|
||||
"--enable-slirp"
|
||||
} else {
|
||||
"--disable-slirp"
|
||||
})
|
||||
.arg("--enable-fdt=internal")
|
||||
.arg("--audio-drv-list=")
|
||||
.arg("--disable-af-xdp")
|
||||
.arg("--disable-alsa")
|
||||
.arg("--disable-attr")
|
||||
.arg("--disable-auth-pam")
|
||||
.arg("--disable-dbus-display")
|
||||
.arg("--disable-bochs")
|
||||
.arg("--disable-bpf")
|
||||
.arg("--disable-brlapi")
|
||||
.arg("--disable-bsd-user")
|
||||
.arg("--disable-bzip2")
|
||||
.arg("--disable-capstone")
|
||||
.arg("--disable-cap-ng")
|
||||
.arg("--disable-canokey")
|
||||
.arg("--disable-cloop")
|
||||
.arg("--disable-cocoa")
|
||||
.arg("--disable-coreaudio")
|
||||
.arg("--disable-curl")
|
||||
.arg("--disable-curses")
|
||||
.arg("--disable-dmg")
|
||||
.arg("--disable-docs")
|
||||
.arg("--disable-dsound")
|
||||
.arg("--disable-fuse")
|
||||
.arg("--disable-fuse-lseek")
|
||||
.arg("--disable-gcrypt")
|
||||
.arg("--disable-gettext")
|
||||
.arg("--disable-gio")
|
||||
.arg("--disable-glusterfs")
|
||||
.arg("--disable-gnutls")
|
||||
.arg("--disable-gtk")
|
||||
.arg("--disable-guest-agent")
|
||||
.arg("--disable-guest-agent-msi")
|
||||
.arg("--disable-hvf")
|
||||
.arg("--disable-iconv")
|
||||
.arg("--disable-jack")
|
||||
.arg("--disable-keyring")
|
||||
.arg("--disable-kvm")
|
||||
.arg("--disable-libdaxctl")
|
||||
.arg("--disable-libiscsi")
|
||||
.arg("--disable-libnfs")
|
||||
.arg("--disable-libpmem")
|
||||
.arg("--disable-libssh")
|
||||
.arg("--disable-libudev")
|
||||
.arg("--disable-libusb")
|
||||
.arg("--disable-linux-aio")
|
||||
.arg("--disable-linux-io-uring")
|
||||
.arg("--disable-linux-user")
|
||||
.arg("--disable-live-block-migration")
|
||||
.arg("--disable-lzfse")
|
||||
.arg("--disable-lzo")
|
||||
.arg("--disable-l2tpv3")
|
||||
.arg("--disable-malloc-trim")
|
||||
.arg("--disable-mpath")
|
||||
.arg("--disable-multiprocess")
|
||||
.arg("--disable-netmap")
|
||||
.arg("--disable-nettle")
|
||||
.arg("--disable-numa")
|
||||
.arg("--disable-nvmm")
|
||||
.arg("--disable-opengl")
|
||||
.arg("--disable-oss")
|
||||
.arg("--disable-pa")
|
||||
.arg("--disable-parallels")
|
||||
.arg("--disable-png")
|
||||
.arg("--disable-pvrdma")
|
||||
.arg("--disable-qcow1")
|
||||
.arg("--disable-qed")
|
||||
.arg("--disable-qga-vss")
|
||||
.arg("--disable-rbd")
|
||||
.arg("--disable-rdma")
|
||||
.arg("--disable-replication")
|
||||
.arg("--disable-sdl")
|
||||
.arg("--disable-sdl-image")
|
||||
.arg("--disable-seccomp")
|
||||
.arg("--disable-selinux")
|
||||
.arg("--disable-slirp-smbd")
|
||||
.arg("--disable-smartcard")
|
||||
.arg("--disable-snappy")
|
||||
.arg("--disable-sndio")
|
||||
.arg("--disable-sparse")
|
||||
.arg("--disable-spice")
|
||||
.arg("--disable-spice-protocol")
|
||||
.arg("--disable-tools")
|
||||
.arg("--disable-tpm")
|
||||
.arg("--disable-usb-redir")
|
||||
.arg("--disable-user")
|
||||
.arg("--disable-u2f")
|
||||
.arg("--disable-vde")
|
||||
.arg("--disable-vdi")
|
||||
.arg("--disable-vduse-blk-export")
|
||||
.arg("--disable-vhost-crypto")
|
||||
.arg("--disable-vhost-kernel")
|
||||
.arg("--disable-vhost-net")
|
||||
.arg("--disable-vhost-user-blk-server")
|
||||
.arg("--disable-vhost-vdpa")
|
||||
.arg("--disable-virglrenderer")
|
||||
.arg("--disable-virtfs")
|
||||
.arg("--disable-vmnet")
|
||||
.arg("--disable-vnc")
|
||||
.arg("--disable-vnc-jpeg")
|
||||
.arg("--disable-vnc-sasl")
|
||||
.arg("--disable-vte")
|
||||
.arg("--disable-vvfat")
|
||||
.arg("--disable-whpx")
|
||||
.arg("--disable-xen")
|
||||
.arg("--disable-xen-pci-passthrough")
|
||||
.arg("--disable-xkbcommon")
|
||||
.arg("--disable-zstd")
|
||||
.arg("--disable-tests");
|
||||
}
|
||||
let mut config_cmd = configure_qemu(
|
||||
&cc_compiler,
|
||||
&cpp_compiler,
|
||||
&qemu_path,
|
||||
&qemu_build_dir,
|
||||
is_usermode,
|
||||
&cpu_target,
|
||||
&target_suffix,
|
||||
);
|
||||
|
||||
let current_config_signature = get_config_signature(&config_cmd);
|
||||
let must_reconfigure = if libafl_qemu_force_configure {
|
||||
// If the user asked to reconfigure, do so
|
||||
true
|
||||
} else if let Ok(libafl_config_old_signature) = libafl_config_old_signature {
|
||||
if libafl_config_old_signature == current_config_signature {
|
||||
// Signature match, do not reconfigure
|
||||
false
|
||||
} else {
|
||||
println!("cargo:warning=QEMU configuration is outdated. Reconfiguring...");
|
||||
true
|
||||
}
|
||||
} else {
|
||||
// In worst scenario, reconfigure
|
||||
true
|
||||
};
|
||||
|
||||
if must_reconfigure {
|
||||
assert!(
|
||||
cmd.status().expect("Invoking Configure failed").success(),
|
||||
config_cmd
|
||||
.status()
|
||||
.expect("Invoking Configure failed")
|
||||
.success(),
|
||||
"Configure didn't finish successfully"
|
||||
);
|
||||
let mut cmd = Command::new("make");
|
||||
cmd.current_dir(&build_dir)
|
||||
.env("__LIBAFL_QEMU_BUILD_OUT", build_dir.join("linkinfo.json"))
|
||||
.env("__LIBAFL_QEMU_BUILD_CC", cc_compiler.path())
|
||||
.env("__LIBAFL_QEMU_BUILD_CXX", cpp_compiler.path())
|
||||
.arg("-j");
|
||||
|
||||
if let Some(j) = jobs {
|
||||
cmd.arg(&format!("{j}")).env("V", "1");
|
||||
}
|
||||
// Config succeeded at this point, (over)write the signature file
|
||||
fs::write(config_signature_path, current_config_signature)
|
||||
.expect("Couldn't write config signature file.");
|
||||
}
|
||||
|
||||
// Always build by default, make will detect if it is necessary to rebuild qemu
|
||||
if !libafl_qemu_no_build {
|
||||
let mut build_cmd = build_qemu(&cc_compiler, &cpp_compiler, &qemu_build_dir, jobs);
|
||||
|
||||
assert!(
|
||||
cmd.status().expect("Invoking Make Failed").success(),
|
||||
build_cmd.status().expect("Invoking Make Failed").success(),
|
||||
"Make didn't finish successfully"
|
||||
);
|
||||
}
|
||||
|
||||
assert!(output_lib.is_file()); // Sanity check
|
||||
|
||||
/*
|
||||
let mut objects = vec![];
|
||||
for dir in &[
|
||||
@ -338,13 +439,12 @@ pub fn build(
|
||||
*/
|
||||
|
||||
if cfg!(feature = "shared") {
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
build_dir.to_string_lossy()
|
||||
);
|
||||
let qemu_build_dir_str = qemu_build_dir.to_str().expect("Could not convert to str");
|
||||
println!("cargo:rustc-link-search=native={qemu_build_dir_str}");
|
||||
println!("cargo:rustc-link-lib=dylib={output_lib_link}");
|
||||
cargo_add_rpath(qemu_build_dir_str);
|
||||
} else {
|
||||
let compile_commands_string = &fs::read_to_string(build_dir.join("linkinfo.json"))
|
||||
let compile_commands_string = &fs::read_to_string(qemu_build_dir.join("linkinfo.json"))
|
||||
.expect("Failed to read linkinfo.json");
|
||||
|
||||
let linkinfo = json::parse(compile_commands_string).expect("Failed to parse linkinfo.json");
|
||||
@ -357,16 +457,27 @@ pub fn build(
|
||||
);
|
||||
}
|
||||
|
||||
assert!(cpp_compiler
|
||||
.to_command()
|
||||
.current_dir(&build_dir)
|
||||
let mut link_command = cpp_compiler.to_command();
|
||||
|
||||
link_command
|
||||
.current_dir(&qemu_build_dir)
|
||||
.arg("-o")
|
||||
.arg("libqemu-partially-linked.o")
|
||||
.arg("-r")
|
||||
.args(cmd)
|
||||
.status()
|
||||
.expect("Partial linked failure")
|
||||
.success());
|
||||
.args(cmd);
|
||||
|
||||
let link_str = format!("{link_command:?}");
|
||||
|
||||
let output = link_command.output().expect("Partial linked failure");
|
||||
|
||||
if !output.status.success() {
|
||||
fs::write(qemu_build_dir.join("link.command"), link_str).expect("Link command failed.");
|
||||
fs::write(qemu_build_dir.join("link.stdout"), &output.stdout)
|
||||
.expect("Link stdout failed.");
|
||||
fs::write(qemu_build_dir.join("link.stderr"), &output.stderr)
|
||||
.expect("Link stderr failed.");
|
||||
panic!("Linking failed.");
|
||||
}
|
||||
|
||||
/* // Old manual linking, kept here for reference and debugging
|
||||
if is_usermode {
|
||||
@ -456,7 +567,7 @@ pub fn build(
|
||||
.current_dir(out_dir_path)
|
||||
.arg("crs")
|
||||
.arg("libqemu-partially-linked.a")
|
||||
.arg(build_dir.join("libqemu-partially-linked.o"))
|
||||
.arg(qemu_build_dir.join("libqemu-partially-linked.o"))
|
||||
.status()
|
||||
.expect("Ar creation");
|
||||
|
||||
@ -476,6 +587,21 @@ pub fn build(
|
||||
.expect("linkinfo.json `libs` values must be strings");
|
||||
println!("cargo:rustc-link-lib={val}");
|
||||
}
|
||||
|
||||
for arg in linkinfo["rpath"].members() {
|
||||
let val = arg
|
||||
.as_str()
|
||||
.expect("linkinfo.json `libs` values must be strings")
|
||||
.to_string()
|
||||
.replace(
|
||||
"$ORIGIN",
|
||||
qemu_build_dir
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.expect("Could not convert OsStr to str"),
|
||||
);
|
||||
cargo_add_rpath(&val);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -497,7 +623,7 @@ pub fn build(
|
||||
//}
|
||||
|
||||
fs::create_dir_all(target_dir.join("pc-bios")).unwrap();
|
||||
for path in fs::read_dir(build_dir.join("pc-bios")).unwrap() {
|
||||
for path in fs::read_dir(qemu_build_dir.join("pc-bios")).unwrap() {
|
||||
let path = path.unwrap().path();
|
||||
if path.is_file() {
|
||||
if let Some(name) = path.file_name() {
|
||||
@ -510,6 +636,6 @@ pub fn build(
|
||||
|
||||
BuildResult {
|
||||
qemu_path,
|
||||
build_dir,
|
||||
build_dir: qemu_build_dir,
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use std::{
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
ptr::addr_of_mut,
|
||||
};
|
||||
|
||||
use regex::Regex;
|
||||
@ -15,6 +16,43 @@ pub use build::build;
|
||||
|
||||
const LLVM_VERSION_MAX: i32 = 33;
|
||||
|
||||
static mut CARGO_RPATH: Option<Vec<String>> = None;
|
||||
static CARGO_RPATH_SEPARATOR: &str = "|";
|
||||
|
||||
pub fn cargo_add_rpath(rpath: &str) {
|
||||
unsafe {
|
||||
if let Some(rpaths) = &mut *addr_of_mut!(CARGO_RPATH) {
|
||||
rpaths.push(rpath.to_string());
|
||||
} else {
|
||||
CARGO_RPATH = Some(vec![rpath.to_string()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cargo_propagate_rpath() {
|
||||
unsafe {
|
||||
if let Some(cargo_cmds) = &mut *addr_of_mut!(CARGO_RPATH) {
|
||||
let rpath = cargo_cmds.join(CARGO_RPATH_SEPARATOR);
|
||||
println!("cargo:rpath={rpath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Must be called from final binary crates
|
||||
pub fn build_libafl_qemu() {
|
||||
// Add rpath if there are some
|
||||
if let Some(rpaths) = env::var_os("DEP_QEMU_RPATH") {
|
||||
let rpaths: Vec<&str> = rpaths
|
||||
.to_str()
|
||||
.expect("Cannot convert OsString to str")
|
||||
.split(CARGO_RPATH_SEPARATOR)
|
||||
.collect();
|
||||
for rpath in rpaths {
|
||||
println!("cargo:rustc-link-arg-bins=-Wl,-rpath,{rpath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_with_bindings(
|
||||
cpu_target: &str,
|
||||
is_big_endian: bool,
|
||||
@ -42,6 +80,8 @@ pub fn build_with_bindings(
|
||||
let re = Regex::new("(Option<\\s*)unsafe( extern \"C\" fn\\(data: u64)").unwrap();
|
||||
let replaced = re.replace_all(&contents, "$1$2");
|
||||
fs::write(bindings_file, replaced.as_bytes()).expect("Unable to write file");
|
||||
|
||||
cargo_propagate_rpath();
|
||||
}
|
||||
|
||||
// For bindgen, the llvm version must be >= of the rust llvm version
|
||||
|
@ -10,6 +10,7 @@ license = "MIT OR Apache-2.0"
|
||||
keywords = ["fuzzing", "qemu", "instrumentation"]
|
||||
edition = "2021"
|
||||
categories = ["development-tools::testing", "emulators", "embedded", "os", "no-std"]
|
||||
links = "qemu"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["x86_64", "usermode"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user