Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libafl-qemu: It's easy to misuse the snapshot API #2621

Open
langston-barrett opened this issue Oct 16, 2024 · 0 comments
Open

libafl-qemu: It's easy to misuse the snapshot API #2621

langston-barrett opened this issue Oct 16, 2024 · 0 comments
Labels
bug Something isn't working qemu LibAFL QEMU

Comments

@langston-barrett
Copy link
Contributor

Consider the following use of SnapshotModule::{snapshot,reset}:

// cargo init
// cargo add --no-default-features --git https://github.com/AFLplusplus/LibAFL libafl_qemu
// cargo run

use std::{error, fs, io::Write as _, path, process};

use libafl_qemu::{modules::SnapshotModule, Regs};

fn run_to(
    qemu: &libafl_qemu::Qemu,
    addr: libafl_qemu::GuestAddr,
) -> Result<(), libafl_qemu::QemuExitError> {
    qemu.set_breakpoint(addr);
    unsafe { qemu.run() }.unwrap();
    qemu.remove_breakpoint(addr);
    Ok(())
}

/// Call a function with signature `u64 (*)(void)`
fn call(qemu: &libafl_qemu::Qemu, addr: libafl_qemu::GuestAddr) -> u64 {
    // Push return address
    let rip: u64 = qemu.read_reg(Regs::Rip).unwrap();
    let mut rsp: u64 = qemu.read_reg(Regs::Rsp).unwrap();
    rsp -= 8;
    qemu.write_mem(rsp, &u64::to_le_bytes(rip)).unwrap();
    qemu.write_reg(Regs::Rsp, rsp).unwrap();

    // Make call
    println!("Calling {addr:#x}");
    qemu.write_reg(Regs::Rip, addr).unwrap();
    run_to(qemu, rip).unwrap();
    let ret = qemu.read_reg::<_, u64>(Regs::Rax).unwrap();
    println!("Got {ret:#x}");
    ret
}

fn main() -> Result<(), Box<dyn error::Error>> {
    const PROG: &str = r#"
int global = 0xdeadbeef;

int get(void) { return global; }
void set(void) { global = 1; }

int main(int argc, char *argv[]) {
  set();
  return get();
}
"#;
    let target = path::PathBuf::from("set");
    fs::File::create("set.c")?.write_all(PROG.as_bytes())?;
    let out = process::Command::new("clang")
        .arg("set.c")
        .arg("-O0")
        .args(["-o", "set"])
        .output()?;
    assert!(out.status.success());

    let args = &["qemu".to_string(), target.to_string_lossy().to_string()];
    let qemu = libafl_qemu::Qemu::init(args)?;
    let mut elf_buffer = Vec::new();
    let elf = libafl_qemu::elf::EasyElf::from_file(target.as_path(), &mut elf_buffer)?;
    let get = elf.resolve_symbol("get", qemu.load_addr()).unwrap();
    let set = elf.resolve_symbol("set", qemu.load_addr()).unwrap();
    let main = elf.resolve_symbol("main", qemu.load_addr()).unwrap();
    println!("get @ {get:#x}");
    println!("set @ {set:#x}");
    println!("main @ {main:#x}");

    // Run to entrypoint
    run_to(&qemu, main).unwrap();

    // Check initial value
    let mut global = call(&qemu, get);
    assert_eq!(global, 0xdeadbeef);

    let mut snap = SnapshotModule::new();
    println!("Taking snapshot");
    snap.snapshot(qemu);

    // Check that value changes when `set` is called
    call(&qemu, set);
    global = call(&qemu, get);
    assert_eq!(global, 1);

    // Check that value is reset by snapshot
    println!("Resetting snapshot");
    snap.reset(qemu);
    global = call(&qemu, get);
    assert_eq!(global, 0xdeadbeef);  // this fails!

    Ok(())
}

The last assertion there fails. I believe this is because SnapshotModule::new doesn't actually install any sort of memory tracing infrastructure, this only happens in init_module. I would say that this is a footgun, the above API usage is pretty reasonable looking, but doesn't do at all what one might expect. I think that this module should probably not expose snapshot and reset, and that these should only be available through the impl EmulatorModule.

@langston-barrett langston-barrett added the bug Something isn't working label Oct 16, 2024
@domenukk domenukk added the qemu LibAFL QEMU label Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working qemu LibAFL QEMU
Projects
None yet
Development

No branches or pull requests

2 participants