libafl-qemu: multiple consecutive `load_snapshot` calls cause segmentation fault
Like @langston-barrett in #2628, I'm trying to fuzz an EDKII image while using snapshots. I'm running into an issue where restoring a snapshot twice in a row, without starting/restarting QEMU in between those restorations, will reliably cause a segmentation fault once QEMU restarts. (Also like Langston, I can't share the compiled artifacts used here, but I strongly suspect the issue is independent of them, and should be replicable with another systemmode target.) Consider this example:
// cargo init
// cargo add --no-default-features --features=systemmode --git https://github.com/AFLplusplus/LibAFL libafl_qemu
// cargo run
use std::error;
const QEMU_FLAGS: &[&str] = &[
"-machine",
"q35",
"-kernel",
"./impl/bzImage",
"-append",
"'rootwait root=/dev/vda console=tty1 console=ttyS0 keep_bootcon'",
"-drive",
"file=./impl/rootfs.ext2,if=virtio,format=raw,readonly=on",
"-global",
"driver=cfi.pflash01,property=secure,value=on",
"-drive",
"if=pflash,format=raw,unit=1,file=./impl/OVMF_VARS.fd",
"-drive",
"if=pflash,format=raw,unit=0,readonly=on,file=./impl/OVMF_CODE.fd",
"-smp",
"2",
"-m",
"4G",
"-bios",
"./impl/OVMF.fd",
"-snapshot",
"-S",
"-nodefaults",
];
const SNAPSHOT_NAME: &'static str = "snapshot";
const SYNC: bool = true;
fn main() -> Result<(), Box<dyn error::Error>> {
let mut args = vec!["qemu".to_owned()];
args.extend(QEMU_FLAGS.iter().map(|s| (*s).to_owned()));
let qemu = libafl_qemu::Qemu::init(args.as_slice())?;
let entry = 0x7FFA3C01;
println!("Saving snapshot...");
qemu.save_snapshot(SNAPSHOT_NAME, SYNC);
println!("Loading snapshot...");
qemu.load_snapshot(SNAPSHOT_NAME, SYNC);
// println!("Loading snapshot again...");
// qemu.load_snapshot(SNAPSHOT_NAME, SYNC);
println!("Running to {entry:#x}...");
qemu.entry_break(entry);
println!("...finished.");
Ok(())
}
Without the second load_snapshot, I see this run to completion. With the second load_snapshot, I get a segmentation fault when QEMU restarts:
rom: file kvmvapic.bin : error Failed to open file “kvmvapic.bin”: No such file or directory
rom: file linuxboot_dma.bin : error Failed to open file “linuxboot_dma.bin”: No such file or directory
Saving snapshot...
Loading snapshot...
Loading snapshot again...
Running to 0x7ffa3c01...
Segmentation fault (core dumped)
Here's a backtrace:
Saving snapshot...
Loading snapshot...
Loading snapshot again...
Running to 0x7ffa3c01...
Thread 1 "scratch" received signal SIGSEGV, Segmentation fault.
0x00005555571c68c0 in ?? ()
(gdb) bt
#0 0x00005555571c68c0 in ?? ()
#1 0x0000555555a6e604 in vm_state_notify (running=running@entry=true, state=state@entry=RUN_STATE_RUNNING) at ../system/runstate.c:399
#2 0x0000555555a64fca in vm_prepare_start (step_pending=step_pending@entry=false) at ../system/cpus.c:778
#3 0x0000555555a65034 in vm_start () at ../system/cpus.c:799
#4 0x00005555558609db in libafl_qemu::qemu::Qemu::run_inner (self=0x7fffffffd917) at src/qemu/systemmode.rs:219
#5 0x000055555586116b in libafl_qemu::qemu::Qemu::run (self=0x7fffffffd917) at src/qemu/mod.rs:668
#6 0x000055555586147e in libafl_qemu::qemu::Qemu::entry_break (self=0x7fffffffd917, addr=2147105793) at src/qemu/mod.rs:864
#7 0x000055555585f3c5 in scratch::main () at src/main.rs:53
(gdb)
I've done some digging and hypothesize that this might be due to a bug in qemu-libafl-bridge, so let me know if I ought to move discussion to an issue there instead.
thank you for the report, i'll have a look this week.