Skip to content

Commit

Permalink
WIP Use display trait
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcondiro committed Jul 3, 2024
1 parent 742baff commit a03f506
Show file tree
Hide file tree
Showing 6 changed files with 337 additions and 247 deletions.
11 changes: 11 additions & 0 deletions fuzzers/qemu_systemmode/Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ dependencies = ["image"]

[tasks.run_fuzzer]
command = "${TARGET_DIR}/${PROFILE_DIR}/qemu_systemmode"
args = [
"-icount", "shift=auto,align=off,sleep=off",
"-machine", "mps2-an385",
"-monitor", "null",
"-kernel", "${TARGET_DIR}/example.elf",
"-serial", "null",
"-nographic",
"-snapshot",
"-drive", "if=none,format=qcow2,file=${TARGET_DIR}/dummy.qcow2",
"-S",
]
dependencies = ["target"]

[tasks.test_fuzzer]
Expand Down
45 changes: 21 additions & 24 deletions fuzzers/qemu_systemmode/src/fuzzer_classic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ use libafl_bolts::{
use libafl_qemu::{
edges::{edges_map_mut_ptr, QemuEdgeCoverageHelper, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND},
elf::EasyElf,
qemu_opt::{
QemuOpt, QemuOptDiskImageFileFormat, QemuOptDrive, QemuOptDriveInterface, QemuOptSerial,
},
Qemu, QemuExecutor, QemuExitError, QemuExitReason, QemuHooks, QemuRWError, QemuShutdownCause,
Regs,
qemu_opt, Qemu, QemuExecutor, QemuExitError, QemuExitReason, QemuHooks, QemuInitError,
QemuRWError, QemuShutdownCause, Regs,
};
use libafl_qemu_sys::GuestPhysAddr;

Expand Down Expand Up @@ -87,26 +84,26 @@ pub fn fuzz() {

let mut run_client = |state: Option<_>, mut mgr, _core_id| {
// Initialize QEMU
// let args: Vec<String> = env::args().collect();
let env: Vec<(String, String)> = env::vars().collect();
// let qemu = Qemu::init(&args, &env).unwrap();

//TODO: broken vars like ${TARGET_DIR}
let qemu_opt = QemuOpt::new()
.machine("mps2-an385".to_string())
.monitor(QemuOptSerial::null)
.kernel(PathBuf::from("${TARGET_DIR}/example.elf"))
.serial(QemuOptSerial::null)
.no_graphic()
.snapshot()
.add_drive(
QemuOptDrive::new()
.interface(QemuOptDriveInterface::none)
.format(QemuOptDiskImageFileFormat::qcow2)
.file(PathBuf::from("${TARGET_DIR}/dummy.qcow2")),
)
.do_not_start_cpu();
let qemu = Qemu::with_options(&qemu_opt, &env).expect("Failed to initialized QEMU");
let qemu: Qemu = Qemu::builder()
.machine(qemu_opt::Machine {
machine: "mps2-an385".to_string(),
})
.monitor(qemu_opt::Monitor::null)
.kernel(qemu_opt::Kernel {
path: PathBuf::from("target/classic/example.elf"),
})
.serial(qemu_opt::Serial::null)
.no_graphic(qemu_opt::NoGraphic::ENABLE)
.snapshot(qemu_opt::Snapshot::ENABLE)
.drives(vec![qemu_opt::Drive::builder()
.interface(qemu_opt::DriveInterface::none)
.format(qemu_opt::DiskImageFileFormat::qcow2)
.file(PathBuf::from("target/classic/dummy.qcow2"))
.build()])
.start_cpu(qemu_opt::StartCPU::DISABLE)
.build::<Result<Qemu, QemuInitError>>()
.expect("Failed to initialized QEMU");

qemu.set_breakpoint(main_addr);
unsafe {
Expand Down
108 changes: 107 additions & 1 deletion libafl_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
use syn::{parse_macro_input, Data::Struct, DeriveInput, Fields::Named, PathArguments, Type};

/// Derive macro to implement `SerdeAny`, to use a type in a `SerdeAnyMap`
#[proc_macro_derive(SerdeAny)]
Expand All @@ -69,3 +69,109 @@ pub fn libafl_serdeany_derive(input: TokenStream) -> TokenStream {
libafl_bolts::impl_serdeany!(#name);
})
}

/// Display macro to implement `Display` for a struct where all fields implement `Display`.
/// The result is the concatenation of all fields display.
/// Specifically handled cases:
/// Options: Some => inner type display None => "".
/// Vec: inner type display concatenated with spaces.
/// Generics or other more or less exotic stuff are not supported.
#[proc_macro_derive(Display)]
pub fn libafl_display(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput);

if let Struct(s) = data {
if let Named(fields) = s.fields {
let vec_fields = fields
.named
.iter()
.filter(|it| libafl_display_type(&it.ty) == TyVec)
.map(|it| &it.ident);
let options_fields = fields
.named
.iter()
.filter(|it| libafl_display_type(&it.ty) == TyOption)
.map(|it| &it.ident);
let other_fields = fields
.named
.iter()
.filter(|it| libafl_display_type(&it.ty) == TyOther)
.map(|it| &it.ident);

let fmt = " {}";
let other_fields_fmt = fmt.repeat(other_fields.clone().count());
return TokenStream::from(quote! {
impl core::fmt::Display for #ident {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
// TyVec
#( for e in &self.#vec_fields {
write!(f, #fmt, e)?;
} )*

// TyOption
#( if let Some(opt) = &self.#options_fields {
write!(f, #fmt, opt)?;
} )*

// TyOther
write!(f, #other_fields_fmt, #(self.#other_fields), *)?;

Ok(())
}
}
});
}
}
panic!("Only structs are supported");
}

#[allow(clippy::enum_variant_names)]
#[derive(Debug, PartialEq, Eq)]
enum LibaflDisplayFieldType {
TyOption,
TyVec,
TyOther,
}
use LibaflDisplayFieldType::{TyOption, TyOther, TyVec};

fn libafl_display_type(ty: &Type) -> LibaflDisplayFieldType {
if let Type::Path(type_path) = ty {
if type_path.qself.is_none() && type_path.path.segments.len() == 1 {
let segment = &type_path.path.segments[0];
if segment.ident == "Option" {
if let PathArguments::AngleBracketed(ref generic_args) = segment.arguments {
if generic_args.args.len() == 1 {
return TyOption;
}
}
} else if segment.ident == "Vec" {
if let PathArguments::AngleBracketed(ref generic_args) = segment.arguments {
if generic_args.args.len() == 1 {
return TyVec;
}
}
}
}
}
TyOther
}

#[cfg(test)]
mod tests {
use syn::parse_quote;
use LibaflDisplayFieldType::{TyOption, TyOther, TyVec};

use super::*;

#[test]
fn libafl_display_type_works() {
let ty: Type = parse_quote!(Option<(String, i8)>);
assert!(libafl_display_type(&ty) == TyOption);

let ty: Type = parse_quote!(Vec<u8>);
assert!(libafl_display_type(&ty) == TyVec);

let ty: Type = parse_quote!(Optionsus<u8>);
assert!(libafl_display_type(&ty) == TyOther);
}
}
1 change: 1 addition & 0 deletions libafl_qemu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ libafl = { path = "../libafl", version = "0.13.1", default-features = false, fea
libafl_bolts = { path = "../libafl_bolts", version = "0.13.1", default-features = false, features = ["std", "derive"] }
libafl_targets = { path = "../libafl_targets", version = "0.13.1" }
libafl_qemu_sys = { path = "./libafl_qemu_sys", version = "0.13.1" }
libafl_derive = { path = "../libafl_derive", version = "0.13.1" }

serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
hashbrown = { version = "0.14", features = ["serde"] } # A faster hashmap, nostd compatible
Expand Down
19 changes: 6 additions & 13 deletions libafl_qemu/src/qemu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use strum::IntoEnumIterator;
use crate::{GuestAddrKind, GuestReg, Regs};

pub mod qemu_opt;
use qemu_opt::QemuOpt;
use qemu_opt::{QemuConfig, QemuConfigBuilder};

#[cfg(emulation_mode = "usermode")]
mod usermode;
Expand Down Expand Up @@ -572,18 +572,11 @@ impl From<u8> for HookData {

#[allow(clippy::unused_self)]
impl Qemu {
#[allow(clippy::must_use_candidate)]
pub fn with_options(
qemu_opts: &QemuOpt,
env: &[(String, String)],
) -> Result<Self, QemuInitError> {
//TODO: do it properly without this shortcut
let args = qemu_opts
.to_string()
.split(' ')
.map(std::string::ToString::to_string)
.collect::<Vec<String>>();
Self::init(&args, env)
pub fn builder() -> QemuConfigBuilder {
// Since Qemu is a zero sized struct, this is not a completely standard builder pattern.
// The Qemu configuration is not stored in the Qemu struct after build().
// Therefore, to use the derived builder and avoid boilerplate a builder for QemuBuilder is derived.
QemuConfig::builder()
}

#[allow(clippy::must_use_candidate, clippy::similar_names)]
Expand Down
Loading

0 comments on commit a03f506

Please sign in to comment.