From 388d7d5db2ce0dd20da71ab4d06a66e4be80f68d Mon Sep 17 00:00:00 2001 From: pyoor Date: Thu, 19 Dec 2024 12:07:55 -0500 Subject: [PATCH] [nyx] Move nyx patches to standalone files --- services/nyx/Dockerfile | 1 + services/nyx/build_afl.sh | 103 +--------- services/nyx/patches/hongfuzz-2b-chunked.diff | 178 ++++++++++++++++++ services/nyx/patches/increase-map-size.diff | 13 ++ services/nyx/patches/libnyx.diff | 15 ++ services/nyx/patches/nyx.diff | 42 +++++ 6 files changed, 258 insertions(+), 94 deletions(-) create mode 100644 services/nyx/patches/hongfuzz-2b-chunked.diff create mode 100644 services/nyx/patches/increase-map-size.diff create mode 100644 services/nyx/patches/libnyx.diff create mode 100644 services/nyx/patches/nyx.diff diff --git a/services/nyx/Dockerfile b/services/nyx/Dockerfile index cdcac415..afbe541c 100644 --- a/services/nyx/Dockerfile +++ b/services/nyx/Dockerfile @@ -10,6 +10,7 @@ COPY \ services/nyx/build_afl.sh \ services/nyx/clang.sh \ /srv/repos/setup/ +COPY services/nyx/patches/ /srv/repos/setup/patches/ RUN /srv/repos/setup/build_afl.sh FROM ubuntu:22.04 diff --git a/services/nyx/build_afl.sh b/services/nyx/build_afl.sh index 7ac7f375..71c8be68 100755 --- a/services/nyx/build_afl.sh +++ b/services/nyx/build_afl.sh @@ -57,66 +57,23 @@ mkdir -p /srv/repos pushd /srv/repos >/dev/null git-clone-rev https://github.com/AFLplusplus/AFLplusplus 78b7e14c73baacf1d88b3c03955e78f5080d17ba pushd AFLplusplus >/dev/null -# WIP 2-byte chunked variant of honggfuzz custom mutator -retry-curl https://github.com/AFLplusplus/AFLplusplus/commit/1b611bb30c14724f0f2eb9330772d30723ba122c.diff | git apply -git apply << "EOF" -diff --git a/custom_mutators/honggfuzz/Makefile b/custom_mutators/honggfuzz/Makefile -index 5c2fcddb..2dde8ba1 100644 ---- a/custom_mutators/honggfuzz/Makefile -+++ b/custom_mutators/honggfuzz/Makefile -@@ -1,5 +1,5 @@ - --CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic -+CFLAGS = -O3 -funroll-loops -fPIC -fblocks -lBlocksRuntime -Wl,-Bsymbolic - - all: honggfuzz-mutator.so honggfuzz-2b-chunked-mutator.so - -commit d606e18332b4f919780604b9daf9a3761602b7c5 -Author: Jesse Schwartzentruber -Date: Fri Jul 14 11:04:04 2023 -0400 - - Increase MAP_SIZE for Nyx -diff --git a/include/config.h b/include/config.h -index 8585041e..6e526717 100644 ---- a/include/config.h -+++ b/include/config.h -@@ -442,7 +442,7 @@ - problems with complex programs). You need to recompile the target binary - after changing this - otherwise, SEGVs may ensue. */ - --#define MAP_SIZE_POW2 16 -+#define MAP_SIZE_POW2 23 - - /* Do not change this unless you really know what you are doing. */ - -EOF +# WIP 2-byte chunked variant of honggfuzz custom mutator +git apply /srv/repos/setup/patches/hongfuzz-2b-chunked.diff +git apply /srv/repos/setup/patches/increase-map-size.diff make -f GNUmakefile afl-fuzz afl-showmap CODE_COVERAGE=1 pushd custom_mutators/honggfuzz >/dev/null make popd >/dev/null + pushd nyx_mode >/dev/null git submodule init + retry git submodule update --depth 1 --single-branch libnyx pushd libnyx >/dev/null -git apply << "EOF" -diff --git a/fuzz_runner/src/nyx/qemu_process.rs b/fuzz_runner/src/nyx/qemu_process.rs -index d062d87..c4ebeea 100644 ---- a/fuzz_runner/src/nyx/qemu_process.rs -+++ b/fuzz_runner/src/nyx/qemu_process.rs -@@ -97,9 +97,7 @@ impl QemuProcess { - pub fn new(params: QemuParams) -> Result { - Self::prepare_redqueen_workdir(¶ms.workdir, params.qemu_id); - -- if params.qemu_id == 0{ -- println!("[!] libnyx: spawning qemu with:\n {}", params.cmd.join(" ")); -- } -+ println!("[!] libnyx: spawning qemu with:\n {}", params.cmd.join(" ")); - - let (shm_work_dir, file_lock) = Self::create_shm_work_dir(); - let mut shm_work_dir_path = PathBuf::from(&shm_work_dir); -EOF +git apply /srv/repos/setup/patches/libnyx.diff popd >/dev/null + retry git submodule update --depth 1 --single-branch packer retry git submodule update --depth 1 --single-branch QEMU-Nyx pushd QEMU-Nyx >/dev/null @@ -126,51 +83,9 @@ retry git submodule update --depth 1 --single-branch libxdc export CAPSTONE_ROOT="$PWD/capstone_v4" export LIBXDC_ROOT="$PWD/libxdc" sed -i '/^LDFLAGS =$/d' libxdc/Makefile -git apply << "EOF" -diff --git a/nyx/hypercall/hypercall.c b/nyx/hypercall/hypercall.c -index fa06af3201..47053472ed 100644 ---- a/nyx/hypercall/hypercall.c -+++ b/nyx/hypercall/hypercall.c -@@ -746,9 +746,34 @@ static void handle_hypercall_kafl_dump_file(struct kvm_run *run, - strncpy(filename, "tmp.XXXXXX", sizeof(filename) - 1); - } - -- char *base_name = basename(filename); // clobbers the filename buffer! -- assert(asprintf(&host_path, "%s/dump/%s", GET_GLOBAL_STATE()->workdir_path, -- base_name) != -1); -+ char *slashmatch = strstr(filename, "/"); -+ char *base_name = NULL; -+ if (slashmatch) { -+ char sub_dir[256]; -+ memset(sub_dir, 0, sizeof(sub_dir)); -+ memcpy(sub_dir, filename, slashmatch - filename); -+ -+ // Safety check, avoid dots in the subdir as they might make us -+ // leave the dump directory. -+ if (strstr(sub_dir, ".") || !strlen(sub_dir)) { -+ nyx_error("Invalid filename in %s: %s. Skipping..\n", -+ __func__, filename); -+ goto err_out1; -+ } -+ -+ assert(asprintf(&host_path, "%s/dump/%s", GET_GLOBAL_STATE()->workdir_path, -+ sub_dir) != -1); -+ mkdir(host_path, 0777); // TODO: Check for errors other than EEXIST -+ -+ base_name = basename(filename); // clobbers the filename buffer! -+ assert(asprintf(&host_path, "%s/dump/%s/%s", GET_GLOBAL_STATE()->workdir_path, -+ sub_dir, base_name) != -1); -+ -+ } else { -+ base_name = basename(filename); // clobbers the filename buffer! -+ assert(asprintf(&host_path, "%s/dump/%s", GET_GLOBAL_STATE()->workdir_path, -+ base_name) != -1); -+ } - - // check if base_name is mkstemp() pattern, otherwise write/append to exact name - char *pattern = strstr(base_name, "XXXXXX"); -EOF +git apply /srv/repos/setup/patches/nyx.diff popd >/dev/null + NO_CHECKOUT=1 ./build_nyx_support.sh popd >/dev/null find . -name .git -type d -exec rm -rf '{}' + diff --git a/services/nyx/patches/hongfuzz-2b-chunked.diff b/services/nyx/patches/hongfuzz-2b-chunked.diff new file mode 100644 index 00000000..c2c3aa3e --- /dev/null +++ b/services/nyx/patches/hongfuzz-2b-chunked.diff @@ -0,0 +1,178 @@ +diff --git a/custom_mutators/honggfuzz/Makefile b/custom_mutators/honggfuzz/Makefile +index 5c2fcddb..83ae5fc7 100644 +--- a/custom_mutators/honggfuzz/Makefile ++++ b/custom_mutators/honggfuzz/Makefile +@@ -1,11 +1,14 @@ + +-CFLAGS = -O3 -funroll-loops -fPIC -Wl,-Bsymbolic ++CFLAGS = -O3 -funroll-loops -fPIC -fblocks -lBlocksRuntime -Wl,-Bsymbolic + +-all: honggfuzz-mutator.so ++all: honggfuzz-mutator.so honggfuzz-2b-chunked-mutator.so + + honggfuzz-mutator.so: honggfuzz.c input.h mangle.c ../../src/afl-performance.c + $(CC) $(CFLAGS) -I../../include -I. -shared -o honggfuzz-mutator.so honggfuzz.c mangle.c ../../src/afl-performance.c + ++honggfuzz-2b-chunked-mutator.so: honggfuzz.c input.h mangle.c ../../src/afl-performance.c ++ $(CC) $(CFLAGS) -DHONGGFUZZ_2B_CHUNKED -I../../include -I. -shared -o honggfuzz-2b-chunked-mutator.so honggfuzz.c mangle.c ../../src/afl-performance.c ++ + update: + @# seriously? --unlink is a dud option? sigh ... + rm -f mangle.c mangle.h honggfuzz.h +diff --git a/custom_mutators/honggfuzz/honggfuzz.c b/custom_mutators/honggfuzz/honggfuzz.c +index 0dd59aee..02e93575 100644 +--- a/custom_mutators/honggfuzz/honggfuzz.c ++++ b/custom_mutators/honggfuzz/honggfuzz.c +@@ -112,6 +112,142 @@ uint8_t afl_custom_queue_get(void *data, const uint8_t *filename) { + + /* here we run the honggfuzz mutator, which is really good */ + ++#ifdef HONGGFUZZ_2B_CHUNKED ++typedef uint16_t chunk_size; ++const chunk_size chunk_size_mask = 0x7ff; ++ ++typedef struct fuzz_packet { ++ chunk_size size; ++ uint16_t mut; ++ uint8_t* buf; ++} fuzz_packet_t; ++ ++void read_fuzz_packets(uint8_t *buf, size_t buf_size, fuzz_packet_t* out, size_t* out_size, size_t max_packets) { ++ size_t remain = buf_size; ++ uint8_t* cur = buf; ++ *out_size = 0; ++ ++ while(1) { ++ if (remain < sizeof(chunk_size) + 1) { ++ // Minimum length required to proceed ++ return; ++ } ++ ++ if (*out_size >= max_packets) { ++ return; ++ } ++ ++ out[*out_size].mut = 0; ++ out[*out_size].size = *(chunk_size*)cur & chunk_size_mask; // Only interpret lower bits for size ++ cur += sizeof(chunk_size); remain -= sizeof(chunk_size); ++ ++ if (remain < out[*out_size].size) { ++ // Truncate last input, if remaining data too small ++ out[*out_size].size = remain; ++ } ++ ++ out[*out_size].buf = cur; ++ cur += out[*out_size].size; remain -= out[*out_size].size; ++ ++ *out_size += 1; ++ } ++} ++ ++size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, ++ u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, ++ size_t max_size) { ++ ++ fuzz_packet_t packet_out[64]; ++ size_t packet_size = 0; ++ ++ fuzz_packet_t packet_out_add[64]; ++ size_t packet_size_add = 0; ++ ++ read_fuzz_packets(buf, buf_size, packet_out, &packet_size, 64); ++ ++ if (!packet_size) { ++ *out_buf = buf; ++ return buf_size; ++ } ++ ++ if (add_buf) { ++ read_fuzz_packets(add_buf, add_buf_size, packet_out_add, &packet_size_add, 64); ++ } ++ ++ int num_mutations = rand() % 5 + 1; ++ ++ ++ for (int i = 0; i < num_mutations; ++i) { ++ if (add_buf && packet_size_add > 0 && (rand() % 2)) { ++ // Splice one index ++ packet_out[rand() % packet_size].mut = 1; ++ } else { ++ // Mutate one index ++ packet_out[rand() % packet_size].mut = 2; ++ } ++ } ++ ++ size_t written = 0; ++ ++ *out_buf = data->mutator_buf; ++ uint8_t* cur = data->mutator_buf; ++ ++ for (size_t idx = 0; idx < packet_size; ++idx) { ++ chunk_size* size_out = (chunk_size*)cur; ++ ++ if (packet_out[idx].mut == 1) { ++ // Splice ++ size_t splice_idx = rand() % packet_size_add; ++ ++ if (written + sizeof(chunk_size) + packet_out_add[splice_idx].size >= max_size) { ++ return written; ++ } ++ ++ memcpy(cur + sizeof(chunk_size), packet_out_add[splice_idx].buf, packet_out_add[splice_idx].size); ++ *size_out = packet_out_add[splice_idx].size; ++ } else { ++ if (written + sizeof(chunk_size) + packet_out[idx].size >= max_size) { ++ return written; ++ } ++ ++ memcpy(cur + sizeof(chunk_size), packet_out[idx].buf, packet_out[idx].size); ++ if (packet_out[idx].mut == 2) { ++ // Mutate ++ run.dynfile->data = data->mutator_buf + sizeof(chunk_size); ++ run.dynfile->size = packet_out[idx].size; ++ ++ queue_input = run.dynfile->data; ++ queue_input_size = run.dynfile->size; ++ ++ run.global->mutate.maxInputSz = MAX_FILE - written - sizeof(chunk_size); ++ ++ mangle_mangleContent(&run, NUMBER_OF_MUTATIONS); ++ ++ // Truncate output ++ if (run.dynfile->size > chunk_size_mask) { ++ run.dynfile->size = chunk_size_mask; ++ } ++ ++ if (run.dynfile->data != data->mutator_buf + sizeof(chunk_size)) { ++ abort(); ++ } ++ ++ packet_out[idx].size = run.dynfile->size; ++ } ++ ++ *size_out = packet_out[idx].size; ++ } ++ ++ cur += *size_out + sizeof(chunk_size); ++ written += *size_out + sizeof(chunk_size); ++ } ++ ++ /* return size of mutated data */ ++ return written; ++} ++ ++#else ++ + size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + u8 **out_buf, uint8_t *add_buf, size_t add_buf_size, + size_t max_size) { +@@ -132,6 +268,8 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size, + + } + ++#endif ++ + /** + * Deinitialize everything + * + diff --git a/services/nyx/patches/increase-map-size.diff b/services/nyx/patches/increase-map-size.diff new file mode 100644 index 00000000..3011adc5 --- /dev/null +++ b/services/nyx/patches/increase-map-size.diff @@ -0,0 +1,13 @@ +diff --git a/include/config.h b/include/config.h +index d8177a75..6a588810 100644 +--- a/include/config.h ++++ b/include/config.h +@@ -459,7 +459,7 @@ + problems with complex programs). You need to recompile the target binary + after changing this - otherwise, SEGVs may ensue. */ + +-#define MAP_SIZE_POW2 16 ++#define MAP_SIZE_POW2 23 + + /* Do not change this unless you really know what you are doing. */ + diff --git a/services/nyx/patches/libnyx.diff b/services/nyx/patches/libnyx.diff new file mode 100644 index 00000000..200088e6 --- /dev/null +++ b/services/nyx/patches/libnyx.diff @@ -0,0 +1,15 @@ +diff --git a/fuzz_runner/src/nyx/qemu_process.rs b/fuzz_runner/src/nyx/qemu_process.rs +index d63cea7..de24fec 100644 +--- a/fuzz_runner/src/nyx/qemu_process.rs ++++ b/fuzz_runner/src/nyx/qemu_process.rs +@@ -100,9 +100,7 @@ impl QemuProcess { + pub fn new(params: QemuParams) -> Result { + Self::prepare_redqueen_workdir(¶ms.workdir, params.qemu_id); + +- if params.qemu_id == 0{ +- println!("[!] libnyx: spawning qemu with:\n {}", params.cmd.join(" ")); +- } ++ println!("[!] libnyx: spawning qemu with:\n {}", params.cmd.join(" ")); + + let (shm_work_dir, file_lock) = Self::create_shm_work_dir(); + let mut shm_work_dir_path = PathBuf::from(&shm_work_dir); diff --git a/services/nyx/patches/nyx.diff b/services/nyx/patches/nyx.diff new file mode 100644 index 00000000..e61583b0 --- /dev/null +++ b/services/nyx/patches/nyx.diff @@ -0,0 +1,42 @@ +diff --git a/nyx/hypercall/hypercall.c b/nyx/hypercall/hypercall.c +index 7ee3025..257cf2b 100644 +--- a/nyx/hypercall/hypercall.c ++++ b/nyx/hypercall/hypercall.c +@@ -751,9 +751,34 @@ static void handle_hypercall_kafl_dump_file(struct kvm_run *run, + strncpy(filename, "tmp.XXXXXX", sizeof(filename) - 1); + } + +- char *base_name = basename(filename); // clobbers the filename buffer! +- assert(asprintf(&host_path, "%s/dump/%s", GET_GLOBAL_STATE()->workdir_path, +- base_name) != -1); ++ char *slashmatch = strstr(filename, "/"); ++ char *base_name = NULL; ++ if (slashmatch) { ++ char sub_dir[256]; ++ memset(sub_dir, 0, sizeof(sub_dir)); ++ memcpy(sub_dir, filename, slashmatch - filename); ++ ++ // Safety check, avoid dots in the subdir as they might make us ++ // leave the dump directory. ++ if (strstr(sub_dir, ".") || !strlen(sub_dir)) { ++ nyx_error("Invalid filename in %s: %s. Skipping..\n", ++ __func__, filename); ++ goto err_out1; ++ } ++ ++ assert(asprintf(&host_path, "%s/dump/%s", GET_GLOBAL_STATE()->workdir_path, ++ sub_dir) != -1); ++ mkdir(host_path, 0777); // TODO: Check for errors other than EEXIST ++ ++ base_name = basename(filename); // clobbers the filename buffer! ++ assert(asprintf(&host_path, "%s/dump/%s/%s", GET_GLOBAL_STATE()->workdir_path, ++ sub_dir, base_name) != -1); ++ ++ } else { ++ base_name = basename(filename); // clobbers the filename buffer! ++ assert(asprintf(&host_path, "%s/dump/%s", GET_GLOBAL_STATE()->workdir_path, ++ base_name) != -1); ++ } + + // check if base_name is mkstemp() pattern, otherwise write/append to exact name + char *pattern = strstr(base_name, "XXXXXX");