Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions fuzzers/full_system/qemu_linux_process/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ authors = ["Romain Malmain <[email protected]>"]
edition = "2021"

[features]
nyx = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Time to add some comments here to explain the features? We're using this for the other crates.

Specifically, I would explain that this adds API compatibility but isn't doing the same as nyx

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, didn't know about this crate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should put the precision in the nyx module doc then, this feature is only for the example fuzzer.

shared = ["libafl_qemu/shared"]

[profile.release]
Expand All @@ -16,15 +17,10 @@ codegen-units = 1
[dependencies]
libafl = { path = "../../../libafl" }
libafl_bolts = { path = "../../../libafl_bolts" }
libafl_qemu = { path = "../../../libafl_qemu", features = [
libafl_qemu = { path = "../../../libafl_qemu", default-features = false, features = [
"x86_64",
"systemmode",
# "paranoid_debug"
] }
libafl_qemu_sys = { path = "../../../libafl_qemu/libafl_qemu_sys", features = [
"x86_64",
"systemmode",
# "paranoid_debug"
# "paranoid_debug",
] }
env_logger = "0.11.5"
libafl_targets = { path = "../../../libafl_targets" }
Expand Down
48 changes: 41 additions & 7 deletions fuzzers/full_system/qemu_linux_process/Makefile.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
env_scripts = ['''
#!@duckscript
profile = get_env PROFILE
harness_api = get_env HARNESS_API

if eq ${profile} "dev"
set_env PROFILE_DIR debug
else
set_env PROFILE_DIR ${profile}
end

if eq ${harness_api} "nyx"
set_env FEATURE nyx
else
set_env FEATURE ""
end

''', '''
#!@duckscript
runs_on_ci = get_env RUN_ON_CI
Expand All @@ -25,12 +33,12 @@ TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}"
LIBAFL_QEMU_CLONE_DIR = { value = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/qemu-libafl-bridge", condition = { env_not_set = [
"LIBAFL_QEMU_DIR",
] } }

LINUX_BUILDER_URL = "[email protected]:AFLplusplus/linux-qemu-image-builder.git"
LINUX_BUILDER_DIR = { value = "${TARGET_DIR}/linux_builder", condition = { env_not_set = [
"LINUX_BUILDER_DIR",
] } }
LINUX_BUILDER_OUT = "${LINUX_BUILDER_DIR}/output"
HARNESS_API = { value = "lqemu", condition = { env_not_set = ["HARNESS_API"] } }

[tasks.target_dir]
condition = { files_not_exist = [
Expand All @@ -51,7 +59,22 @@ script = '''
git clone ${LINUX_BUILDER_URL} ${LINUX_BUILDER_DIR}
'''

[tasks.compile_target]
[tasks.compile_target_nyx]
condition = { env = { "HARNESS_API" = "nyx" } }
dependencies = ["target_dir", "linux_builder_dir"]
command = "clang"
args = [
"-O0",
"-static",
"${WORKING_DIR}/example/harness_nyx.c",
"-o",
"${TARGET_DIR}/runtime/harness",
"-I",
"${TARGET_DIR}/${PROFILE_DIR}/include",
]

[tasks.compile_target_native]
condition = { env = { "HARNESS_API" = "lqemu" } }
dependencies = ["target_dir", "linux_builder_dir"]
command = "clang"
args = [
Expand All @@ -64,6 +87,9 @@ args = [
"${TARGET_DIR}/${PROFILE_DIR}/include",
]

[tasks.compile_target]
dependencies = ["compile_target_native", "compile_target_nyx"]

[tasks.target]
dependencies = ["build", "compile_target"]
script_runner = "@shell"
Expand Down Expand Up @@ -96,7 +122,15 @@ ${LINUX_BUILDER_DIR}/update.sh
[tasks.build]
dependencies = ["target_dir"]
command = "cargo"
args = ["build", "--profile", "${PROFILE}", "--target-dir", "${TARGET_DIR}"]
args = [
"build",
"--profile",
"${PROFILE}",
"--target-dir",
"${TARGET_DIR}",
"--features",
"${FEATURE}",
]

[tasks.run]
dependencies = ["build"]
Expand All @@ -111,15 +145,15 @@ else
LIBAFL_QEMU_BIOS_DIR=${LIBAFL_QEMU_CLONE_DIR}/build/qemu-bundle/usr/local/share/qemu
fi

cp ${LINUX_BUILDER_OUT}/OVMF_CODE.fd ${LINUX_BUILDER_OUT}/OVMF_CODE.fd.clone
cp ${LINUX_BUILDER_OUT}/OVMF_VARS.fd ${LINUX_BUILDER_OUT}/OVMF_VARS.fd.clone
cp ${LINUX_BUILDER_OUT}/OVMF_CODE.4m.fd ${LINUX_BUILDER_OUT}/OVMF_CODE.fd.clone
cp ${LINUX_BUILDER_OUT}/OVMF_VARS.4m.fd ${LINUX_BUILDER_OUT}/OVMF_VARS.fd.clone
cp ${LINUX_BUILDER_OUT}/linux.qcow2 ${LINUX_BUILDER_OUT}/linux.qcow2.clone

${TARGET_DIR}/${PROFILE_DIR}/qemu_linux_process \
-accel tcg \
-m 4G \
-drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_CODE.fd" `# OVMF code pflash` \
-drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_VARS.fd" `# OVMF vars pflash` \
-drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_CODE.4m.fd" `# OVMF code pflash` \
-drive if=pflash,format=raw,file="${LINUX_BUILDER_OUT}/OVMF_VARS.4m.fd" `# OVMF vars pflash` \
-device virtio-scsi-pci,id=scsi0 `# SCSI bus` \
-device scsi-hd,bus=scsi0.0,drive=disk,id=virtio-disk0,bootindex=1 \
-blockdev driver=file,filename="${LINUX_BUILDER_OUT}/linux.qcow2",node-name=storage `# Backend file of "disk"` \
Expand Down
137 changes: 137 additions & 0 deletions fuzzers/full_system/qemu_linux_process/example/harness_nyx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Adapted from
// https://github.com/google/fuzzing/blob/master/tutorial/libFuzzer/fuzz_me.cc
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <assert.h>

#include <nyx_api.h>

#define PAGE_SIZE 4096
#define PAYLOAD_MAX_SIZE (1 * 1024 * 1024)

bool FuzzMe(const uint8_t *Data, size_t DataSize) {
if (DataSize > 3) {
if (Data[0] == 'F') {
if (Data[1] == 'U') {
if (Data[2] == 'Z') {
if (Data[3] == 'Z') { return true; }
}
}
}
}

return false;
}

/**
* Allocate page-aligned memory
*/
void *malloc_resident_pages(size_t num_pages) {
size_t data_size = PAGE_SIZE * num_pages;
void *ptr = NULL;

if ((ptr = aligned_alloc(PAGE_SIZE, data_size)) == NULL) {
fprintf(stderr, "Allocation failure: %s\n", strerror(errno));
goto err_out;
}

// ensure pages are aligned and resident
memset(ptr, 0x42, data_size);
if (mlock(ptr, data_size) == -1) {
fprintf(stderr, "Error locking scratch buffer: %s\n", strerror(errno));
goto err_out;
}

assert(((uintptr_t)ptr % PAGE_SIZE) == 0);
return ptr;
err_out:
free(ptr);
return NULL;
}

int agent_init(int verbose) {
host_config_t host_config;

// set ready state
kAFL_hypercall(HYPERCALL_KAFL_ACQUIRE, 0);
kAFL_hypercall(HYPERCALL_KAFL_RELEASE, 0);

kAFL_hypercall(HYPERCALL_KAFL_GET_HOST_CONFIG, (uintptr_t)&host_config);

if (verbose) {
fprintf(stderr, "GET_HOST_CONFIG\n");
fprintf(stderr, "\thost magic: 0x%x, version: 0x%x\n",
host_config.host_magic, host_config.host_version);
fprintf(stderr, "\tbitmap size: 0x%x, ijon: 0x%x\n",
host_config.bitmap_size, host_config.ijon_bitmap_size);
fprintf(stderr, "\tpayload size: %u KB\n",
host_config.payload_buffer_size / 1024);
fprintf(stderr, "\tworker id: %d\n", host_config.worker_id);
}

if (host_config.host_magic != NYX_HOST_MAGIC) {
hprintf("HOST_MAGIC mismatch: %08x != %08x\n", host_config.host_magic,
NYX_HOST_MAGIC);
habort("HOST_MAGIC mismatch!");
return -1;
}

if (host_config.host_version != NYX_HOST_VERSION) {
hprintf("HOST_VERSION mismatch: %08x != %08x\n", host_config.host_version,
NYX_HOST_VERSION);
habort("HOST_VERSION mismatch!");
return -1;
}

if (host_config.payload_buffer_size > PAYLOAD_MAX_SIZE) {
hprintf("Fuzzer payload size too large: %lu > %lu\n",
host_config.payload_buffer_size, PAYLOAD_MAX_SIZE);
habort("Host payload size too large!");
return -1;
}

agent_config_t agent_config = {0};
agent_config.agent_magic = NYX_AGENT_MAGIC;
agent_config.agent_version = NYX_AGENT_VERSION;
// agent_config.agent_timeout_detection = 0; // timeout by host
// agent_config.agent_tracing = 0; // trace by host
// agent_config.agent_ijon_tracing = 0; // no IJON
agent_config.agent_non_reload_mode = 0; // no persistent mode
// agent_config.trace_buffer_vaddr = 0xdeadbeef;
// agent_config.ijon_trace_buffer_vaddr = 0xdeadbeef;
agent_config.coverage_bitmap_size = host_config.bitmap_size;
// agent_config.input_buffer_size;
// agent_config.dump_payloads; // set by hypervisor (??)

kAFL_hypercall(HYPERCALL_KAFL_SET_AGENT_CONFIG, (uintptr_t)&agent_config);

return 0;
}

int main() {
kAFL_payload *pbuf = malloc_resident_pages(PAYLOAD_MAX_SIZE / PAGE_SIZE);
assert(pbuf);

agent_init(1);

kAFL_hypercall(HYPERCALL_KAFL_GET_PAYLOAD, (uint64_t)pbuf);

hprintf("payload size addr: %p", &pbuf->size);
hprintf("payload addr: %p", &pbuf->data);

kAFL_hypercall(HYPERCALL_KAFL_NEXT_PAYLOAD, 0);
kAFL_hypercall(HYPERCALL_KAFL_ACQUIRE, 0);

// Call the target
bool ret = FuzzMe(pbuf->data, pbuf->size);

kAFL_hypercall(HYPERCALL_KAFL_RELEASE, 0);

habort("Error: post-release code has been triggered.");
}
62 changes: 56 additions & 6 deletions fuzzers/full_system/qemu_linux_process/src/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
use core::time::Duration;
use std::{env, path::PathBuf, process};

#[cfg(not(feature = "nyx"))]
use libafl::state::{HasExecutions, State};
use libafl::{
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::{launcher::Launcher, EventConfig},
executors::ShadowExecutor,
feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::BytesInput,
inputs::{BytesInput, HasTargetBytes, UsesInput},
monitors::MultiMonitor,
mutators::{havoc_mutations, I2SRandReplaceBinonly, StdScheduledMutator},
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
Expand All @@ -27,13 +29,64 @@ use libafl_bolts::{
shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list,
};
#[cfg(feature = "nyx")]
use libafl_qemu::{command::nyx::NyxCommandManager, NyxEmulatorDriver};
#[cfg(not(feature = "nyx"))]
use libafl_qemu::{command::StdCommandManager, StdEmulatorDriver};
use libafl_qemu::{
emu::Emulator,
executor::QemuExecutor,
modules::{cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, CmpLogModule},
modules::{
cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, CmpLogModule,
EmulatorModuleTuple,
},
FastSnapshotManager, QemuInitError,
};
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};

#[cfg(feature = "nyx")]
fn get_emulator<ET, S>(
args: Vec<String>,
modules: ET,
) -> Result<
Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, FastSnapshotManager>,
QemuInitError,
>
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
<S as UsesInput>::Input: HasTargetBytes,
{
Emulator::empty()
.qemu_cli(args)
.modules(modules)
.driver(
NyxEmulatorDriver::builder()
.allow_page_on_start(true)
.process_only(true)
.build(),
)
.command_manager(NyxCommandManager::default())
.snapshot_manager(FastSnapshotManager::default())
.build()
}

#[cfg(not(feature = "nyx"))]
fn get_emulator<ET, S>(
args: Vec<String>,
modules: ET,
) -> Result<
Emulator<StdCommandManager<S>, StdEmulatorDriver, ET, S, FastSnapshotManager>,
QemuInitError,
>
where
ET: EmulatorModuleTuple<S>,
S: State + HasExecutions + Unpin,
<S as UsesInput>::Input: HasTargetBytes,
{
Emulator::builder().qemu_cli(args).modules(modules).build()
}

pub fn fuzz() {
env_logger::init();

Expand Down Expand Up @@ -69,10 +122,7 @@ pub fn fuzz() {
CmpLogModule::default(),
);

let emu = Emulator::builder()
.qemu_cli(args)
.modules(modules)
.build()?;
let emu = get_emulator(args, modules)?;

// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
Expand Down
4 changes: 2 additions & 2 deletions fuzzers/inprocess/libfuzzer_libmozjpeg/hook_allocs.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
#ifdef _WIN32
#define posix_memalign(p, a, s) \
(((*(p)) = _aligned_malloc((s), (a))), *(p) ? 0 : errno)
#define RETADDR (uintptr_t)_ReturnAddress()
#define RETADDR (uintptr_t) _ReturnAddress()
#else
#define RETADDR (uintptr_t)__builtin_return_address(0)
#define RETADDR (uintptr_t) __builtin_return_address(0)
#endif

#ifdef __GNUC__
Expand Down
3 changes: 3 additions & 0 deletions libafl_qemu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ default = [
"injections",
]
document-features = ["dep:document-features"]

qemu_sanitizers = ["libafl_qemu_sys/qemu_sanitizers"]

paranoid_debug = [
"libafl_qemu_sys/paranoid_debug",
] # Will perform as many checks as possible. The target will be greatly slowed down.
Expand Down
Loading
Loading