-
-
Notifications
You must be signed in to change notification settings - Fork 394
Nyx hypercall API support for LibAFL QEMU #2801
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
Merged
Changes from 4 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
61067a9
nyx api support
rmalmain 1874566
update hash
rmalmain 2c0e69b
clippy + fmt
rmalmain ba18349
Merge branch 'main' into nyx_api
rmalmain ec486bf
fix linux kernel fuzzer
rmalmain 88c338d
fixing some stuff
rmalmain fd388fd
nyx comments
rmalmain eb41150
hash_me -> hash_64_fast
rmalmain 53e5384
separate nyx driver from std driver
rmalmain fa35d43
import
rmalmain a7b0cd4
Merge branch 'main' into nyx_api
rmalmain e0e012f
do not check libmozjpeg format.
rmalmain aeaf970
fix bloom
rmalmain 3b153c8
Merge branch 'main' into nyx_api
rmalmain 6d78309
fix merge
rmalmain 0c6da52
fix qemu launcher
rmalmain 7000f49
update qemu hash
rmalmain File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ authors = ["Romain Malmain <[email protected]>"] | |
edition = "2021" | ||
|
||
[features] | ||
nyx = [] | ||
shared = ["libafl_qemu/shared"] | ||
|
||
[profile.release] | ||
|
@@ -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" } | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
@@ -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 = [ | ||
|
@@ -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 = [ | ||
|
@@ -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" | ||
|
@@ -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"] | ||
|
@@ -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"` \ | ||
|
137 changes: 137 additions & 0 deletions
137
fuzzers/full_system/qemu_linux_process/example/harness_nyx.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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."); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.