Qemu as lib (#301)

* linking problems

* use shared lib

* ci

* clippy, ci fixegit pushs

* ingoring distclean result

* clippy

* clippy

Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
Andrea Fioraldi 2021-09-24 13:22:33 +02:00 committed by GitHub
parent 8f5df699fe
commit 1fde608145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 248 additions and 29 deletions

View File

@ -40,7 +40,7 @@ jobs:
toolchain: stable toolchain: stable
- uses: Swatinem/rust-cache@v1 - uses: Swatinem/rust-cache@v1
- name: Install deps - name: Install deps
run: sudo apt-get install -y llvm llvm-dev clang run: sudo apt-get install -y llvm llvm-dev clang ninja-build
- name: get clang version - name: get clang version
run: command -v llvm-config && clang -v run: command -v llvm-config && clang -v
- name: Install cargo-hack - name: Install cargo-hack
@ -90,7 +90,7 @@ jobs:
- name: Add nightly rustfmt and clippy - name: Add nightly rustfmt and clippy
run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade run: rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
- name: Install deps - name: Install deps
run: sudo apt-get install -y llvm llvm-dev clang nasm run: sudo apt-get install -y llvm llvm-dev clang nasm ninja-build
- name: Build and run example fuzzers - name: Build and run example fuzzers
run: ./scripts/test_all_fuzzers.sh run: ./scripts/test_all_fuzzers.sh
nostd-build: nostd-build:

View File

@ -9,9 +9,6 @@ default = ["std"]
std = [] std = []
[profile.release] [profile.release]
lto = true
codegen-units = 1
opt-level = 3
debug = true debug = true
[dependencies] [dependencies]
@ -19,7 +16,3 @@ libafl = { path = "../../libafl/" }
libafl_qemu = { path = "../../libafl_qemu/" } libafl_qemu = { path = "../../libafl_qemu/" }
clap = { version = "3.0.0-beta.2", features = ["default"] } clap = { version = "3.0.0-beta.2", features = ["default"] }
nix = "0.20.0" nix = "0.20.0"
[lib]
name = "fuzzbench_qemu"
crate-type = ["staticlib"]

View File

@ -44,13 +44,16 @@ use libafl_qemu::{
QemuExecutor, QemuExecutor,
}; };
/// The fuzzer main (as `no_mangle` C function) /// The fuzzer main
#[no_mangle] pub fn main() {
pub fn libafl_qemu_main() {
// Registry the metadata types used in this fuzzer // Registry the metadata types used in this fuzzer
// Needed only on no_std // Needed only on no_std
//RegistryBuilder::register::<Tokens>(); //RegistryBuilder::register::<Tokens>();
let args: Vec<String> = env::args().collect();
let env: Vec<(String, String)> = env::vars().collect();
emu::init(&args, &env);
let res = match App::new("libafl_qemu_fuzzbench") let res = match App::new("libafl_qemu_fuzzbench")
.version("0.4.0") .version("0.4.0")
.author("AFLplusplus team") .author("AFLplusplus team")

View File

@ -1,2 +0,0 @@
#[cfg(target_os = "linux")]
pub mod fuzzer;

View File

@ -0,0 +1,7 @@
#[cfg(target_os = "linux")]
pub mod fuzzer;
fn main() {
#[cfg(target_os = "linux")]
fuzzer::main()
}

View File

@ -25,3 +25,7 @@ libc = "0.2.97"
[build-dependencies] [build-dependencies]
cc = { version = "1.0" } cc = { version = "1.0" }
which = "4.1"
[lib]
crate-type = ["rlib", "cdylib"]

View File

@ -1,21 +1,215 @@
use std::{env, path::Path}; use std::{env, fs::copy, path::Path, process::Command};
//use std::fs::read_dir;
use which::which;
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
const QEMU_REVISION: &str = "22daaa7d0c76b32f8391bad40c0b220f3e659f66";
fn build_dep_check(tools: &[&str]) {
for tool in tools {
which(tool).unwrap_or_else(|_| panic!("Build tool {} not found", tool));
}
}
#[allow(clippy::too_many_lines)]
fn main() { fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap(); println!("cargo:rerun-if-changed=build.rs");
let out_dir = out_dir.to_string_lossy().to_string(); println!("cargo:rerun-if-env-changed=CPU_TARGET");
let src_dir = Path::new("src");
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
if target_os != "linux" {
return;
}
if target_os == "linux" { let jobs = env::var("CARGO_BUILD_JOBS").unwrap_or_else(|_| "1".to_owned());
println!("cargo:rerun-if-changed=src/weaks.c"); let cpu_target = env::var("CPU_TARGET").unwrap_or_else(|_| {
println!("cargo:warning=CPU_TARGET is not set, default to x86_64");
"x86_64".to_owned()
});
cc::Build::new() let out_dir = env::var_os("OUT_DIR").unwrap();
.file(src_dir.join("weaks.c")) let out_dir = out_dir.to_string_lossy().to_string();
.compile("weaks"); let out_dir_path = Path::new(&out_dir);
let mut target_dir = out_dir_path.to_path_buf();
target_dir.pop();
target_dir.pop();
target_dir.pop();
//let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
build_dep_check(&["git", "make"]);
let qemu_path = out_dir_path.join(QEMU_DIRNAME);
if !qemu_path.is_dir() {
println!(
"cargo:warning=Qemu not found, cloning with git ({})...",
QEMU_REVISION
);
Command::new("git")
.current_dir(&out_dir_path)
.arg("clone")
.arg(QEMU_URL)
.status()
.unwrap();
Command::new("git")
.current_dir(&qemu_path)
.arg("checkout")
.arg(QEMU_REVISION)
.status()
.unwrap();
}
let build_dir = qemu_path.join("build");
let output_lib = build_dir.join(&format!("libqemu-{}.so", cpu_target));
if !output_lib.is_file() {
drop(
Command::new("make")
.current_dir(&qemu_path)
.arg("distclean")
.status(),
);
Command::new("./configure")
.current_dir(&qemu_path)
//.arg("--as-static-lib")
.arg("--as-shared-lib")
.arg(&format!("--target-list={}-linux-user", cpu_target))
.args(&[
"--audio-drv-list=",
"--disable-blobs",
"--disable-bochs",
"--disable-brlapi",
"--disable-bsd-user",
"--disable-bzip2",
"--disable-cap-ng",
"--disable-cloop",
"--disable-curl",
"--disable-curses",
"--disable-dmg",
"--disable-fdt",
"--disable-gcrypt",
"--disable-glusterfs",
"--disable-gnutls",
"--disable-gtk",
"--disable-guest-agent",
"--disable-iconv",
"--disable-libiscsi",
"--disable-libnfs",
"--disable-libssh",
"--disable-libusb",
"--disable-linux-aio",
"--disable-live-block-migration",
"--disable-lzo",
"--disable-nettle",
"--disable-numa",
"--disable-opengl",
"--disable-parallels",
"--disable-plugins",
"--disable-qcow1",
"--disable-qed",
"--disable-rbd",
"--disable-rdma",
"--disable-replication",
"--disable-sdl",
"--disable-seccomp",
"--disable-smartcard",
"--disable-snappy",
"--disable-spice",
"--disable-system",
"--disable-tools",
"--disable-tpm",
"--disable-usb-redir",
"--disable-vde",
"--disable-vdi",
"--disable-vhost-crypto",
"--disable-vhost-kernel",
"--disable-vhost-net",
"--disable-vhost-scsi",
"--disable-vhost-user",
"--disable-vhost-vdpa",
"--disable-vhost-vsock",
"--disable-virglrenderer",
"--disable-virtfs",
"--disable-vnc",
"--disable-vnc-jpeg",
"--disable-vnc-png",
"--disable-vnc-sasl",
"--disable-vte",
"--disable-vvfat",
"--disable-xen",
"--disable-xen-pci-passthrough",
"--disable-xfsctl",
])
.status()
.expect("Configure failed");
Command::new("make")
.current_dir(&qemu_path)
.arg("-j")
.arg(&jobs)
.status()
.expect("Make failed");
//let _ = remove_file(build_dir.join(&format!("libqemu-{}.so", cpu_target)));
}
copy(
build_dir.join(&format!("libqemu-{}.so", cpu_target)),
target_dir.join(&format!("libqemu-{}.so", cpu_target)),
)
.expect("Failed to copy the QEMU shared object");
println!(
"cargo:rustc-link-search=native={}",
&target_dir.to_string_lossy().to_string()
);
println!("cargo:rustc-link-lib=qemu-{}", cpu_target);
println!("cargo:rustc-env=LD_LIBRARY_PATH={}", target_dir.display());
}
/*
// Build a static library
let mut objects = vec![];
for dir in &[
build_dir.join("libcommon.fa.p"),
build_dir.join(&format!("libqemu-{}-linux-user.fa.p", cpu_target)),
build_dir.join("libqemuutil.a.p"),
build_dir.join("libqom.fa.p"),
build_dir.join("libhwcore.fa.p"),
build_dir.join("libcapstone.a.p"),
] {
for path in read_dir(dir).unwrap() {
let path = path.unwrap().path();
if path.is_file() {
if let Some(name) = path.file_name() {
if name.to_string_lossy().starts_with("stubs") {
continue;
}
else if let Some(ext) = path.extension() {
if ext == "o" {
objects.push(path);
}
}
}
}
}
}
Command::new("ar")
.current_dir(&out_dir_path)
.arg("crus")
.arg("libqemu-bridge.a")
.args(&objects)
.status()
.expect("Ar failed");
println!("cargo:rustc-link-search=native={}", &out_dir); println!("cargo:rustc-link-search=native={}", &out_dir);
} println!("cargo:rustc-link-lib=static=qemu-bridge");
println!("cargo:rustc-link-lib=rt");
println!("cargo:rustc-link-lib=util");
println!("cargo:rustc-link-lib=gthread-2.0");
println!("cargo:rustc-link-lib=glib-2.0");
println!("cargo:rustc-link-lib=stdc++");
println!("cargo:rerun-if-changed=build.rs");
} }
*/

View File

@ -5,7 +5,7 @@ use core::{
convert::TryFrom, convert::TryFrom,
ffi::c_void, ffi::c_void,
mem::{size_of, transmute, MaybeUninit}, mem::{size_of, transmute, MaybeUninit},
ptr::copy_nonoverlapping, ptr::{copy_nonoverlapping, null},
}; };
use num::Num; use num::Num;
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
@ -83,6 +83,8 @@ impl MapInfo {
} }
extern "C" { extern "C" {
fn qemu_user_init(argc: i32, argv: *const *const u8, envp: *const *const u8) -> i32;
fn libafl_qemu_write_reg(reg: i32, val: *const u8) -> i32; fn libafl_qemu_write_reg(reg: i32, val: *const u8) -> i32;
fn libafl_qemu_read_reg(reg: i32, val: *mut u8) -> i32; fn libafl_qemu_read_reg(reg: i32, val: *mut u8) -> i32;
fn libafl_qemu_num_regs() -> i32; fn libafl_qemu_num_regs() -> i32;
@ -137,6 +139,24 @@ extern "C" {
unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult; unsafe extern "C" fn(i32, u64, u64, u64, u64, u64, u64, u64, u64) -> SyscallHookResult;
} }
#[allow(clippy::must_use_candidate, clippy::similar_names)]
pub fn init(args: &[String], env: &[(String, String)]) -> i32 {
let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect();
assert!(argv.len() < i32::MAX as usize);
let env_strs: Vec<String> = env.iter().map(|(k, v)| format!("{}={}", &k, &v)).collect();
let mut envp: Vec<*const u8> = env_strs.iter().map(|x| x.as_bytes().as_ptr()).collect();
envp.push(null());
#[allow(clippy::cast_possible_wrap)]
let argc = argv.len() as i32;
unsafe {
qemu_user_init(
argc,
argv.as_ptr() as *const *const u8,
envp.as_ptr() as *const *const u8,
)
}
}
pub struct GuestMaps { pub struct GuestMaps {
orig_c_iter: *const c_void, orig_c_iter: *const c_void,
c_iter: *const c_void, c_iter: *const c_void,