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

[nyx] Move nyx patches to standalone files #584

Merged
merged 1 commit into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions services/nyx/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
103 changes: 9 additions & 94 deletions services/nyx/build_afl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>
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<QemuProcess, String> {
Self::prepare_redqueen_workdir(&params.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
Expand All @@ -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 '{}' +
Expand Down
178 changes: 178 additions & 0 deletions services/nyx/patches/hongfuzz-2b-chunked.diff
Original file line number Diff line number Diff line change
@@ -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
*

13 changes: 13 additions & 0 deletions services/nyx/patches/increase-map-size.diff
Original file line number Diff line number Diff line change
@@ -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. */

15 changes: 15 additions & 0 deletions services/nyx/patches/libnyx.diff
Original file line number Diff line number Diff line change
@@ -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<QemuProcess, String> {
Self::prepare_redqueen_workdir(&params.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);
42 changes: 42 additions & 0 deletions services/nyx/patches/nyx.diff
Original file line number Diff line number Diff line change
@@ -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");