diff options
Diffstat (limited to 'coresight_mode')
-rw-r--r-- | coresight_mode/.gitignore | 2 | ||||
-rw-r--r-- | coresight_mode/GNUmakefile | 62 | ||||
-rw-r--r-- | coresight_mode/Makefile | 21 | ||||
-rw-r--r-- | coresight_mode/README.md | 70 | ||||
m--------- | coresight_mode/coresight-trace | 0 | ||||
m--------- | coresight_mode/patchelf | 0 | ||||
-rw-r--r-- | coresight_mode/patches/0001-Add-AFL-forkserver.patch | 117 |
7 files changed, 272 insertions, 0 deletions
diff --git a/coresight_mode/.gitignore b/coresight_mode/.gitignore new file mode 100644 index 00000000..dedb1613 --- /dev/null +++ b/coresight_mode/.gitignore @@ -0,0 +1,2 @@ +.local +glibc* diff --git a/coresight_mode/GNUmakefile b/coresight_mode/GNUmakefile new file mode 100644 index 00000000..9ab30ff7 --- /dev/null +++ b/coresight_mode/GNUmakefile @@ -0,0 +1,62 @@ +#!/usr/bin/env make +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2021 Ricerca Security, Inc. All rights reserved. + +SHELL:=bash +PREFIX?=$(shell pwd)/.local + +CS_TRACE:=coresight-trace + +PATCHELF?=$(PREFIX)/bin/patchelf + +PATCH_DIR:=patches + +GLIBC_VER:=2.33 +GLIBC_NAME:=glibc-$(GLIBC_VER) +GLIBC_URL_BASE:=http://ftp.gnu.org/gnu/glibc +GLIBC_LDSO?=$(PREFIX)/lib/ld-linux-aarch64.so.1 + +OUTPUT?="$(TARGET).patched" + +all: build + +build: + git submodule update --init --recursive $(CS_TRACE) + $(MAKE) -C $(CS_TRACE) + cp $(CS_TRACE)/cs-proxy ../afl-cs-proxy + +patch: | $(PATCHELF) $(GLIBC_LDSO) + @if test -z "$(TARGET)"; then echo "TARGET is not set"; exit 1; fi + $(PATCHELF) \ + --set-interpreter $(GLIBC_LDSO) \ + --set-rpath $(dir $(GLIBC_LDSO)) \ + --output $(OUTPUT) \ + $(TARGET) + +$(PATCHELF): patchelf + git submodule update --init $< + cd $< && \ + ./bootstrap.sh && \ + ./configure --prefix=$(PREFIX) && \ + $(MAKE) && \ + $(MAKE) check && \ + $(MAKE) install + +$(GLIBC_LDSO): | $(GLIBC_NAME).tar.xz + tar -xf $(GLIBC_NAME).tar.xz + for file in $(shell find $(PATCH_DIR) -maxdepth 1 -type f); do \ + patch -p1 < $$file ; \ + done + mkdir -p $(GLIBC_NAME)/build + cd $(GLIBC_NAME)/build && \ + ../configure --prefix=$(PREFIX) && \ + $(MAKE) && \ + $(MAKE) install + +$(GLIBC_NAME).tar.xz: + wget -O $@ $(GLIBC_URL_BASE)/$@ + +clean: + $(MAKE) -C $(CS_TRACE) clean + +.PHONY: all build patch clean diff --git a/coresight_mode/Makefile b/coresight_mode/Makefile new file mode 100644 index 00000000..fb8990b9 --- /dev/null +++ b/coresight_mode/Makefile @@ -0,0 +1,21 @@ +#!/usr/bin/env make +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2021 Ricerca Security, Inc. All rights reserved. + +all: + @echo trying to use GNU make... + @gmake all || echo please install GNUmake + +build: + @echo trying to use GNU make... + @gmake build || echo please install GNUmake + +patch: + @echo trying to use GNU make... + @gmake patch || echo please install GNUmake + +clean: + @echo trying to use GNU make... + @gmake clean || echo please install GNUmake + +.PHONY: all build patch clean diff --git a/coresight_mode/README.md b/coresight_mode/README.md new file mode 100644 index 00000000..1a39d347 --- /dev/null +++ b/coresight_mode/README.md @@ -0,0 +1,70 @@ +# AFL++ CoreSight mode + +CoreSight mode enables binary-only fuzzing on ARM64 Linux using CoreSight (ARM's hardware tracing technology). + +NOTE: CoreSight mode is in the early development stage. Not applicable for production use. +Currently the following hardware boards are supported: +* NVIDIA Jetson TX2 (NVIDIA Parker) +* NVIDIA Jetson Nano (NVIDIA Tegra X1) +* GIGABYTE R181-T90 (Marvell ThunderX2 CN99XX) + +## Getting started + +Please read the [RICSec/coresight-trace README](https://github.com/RICSecLab/coresight-trace/blob/master/README.md) and check the prerequisites (capstone) before getting started. + +CoreSight mode supports the AFL++ fork server mode to reduce `exec` system call +overhead. To support it for binary-only fuzzing, it needs to modify the target +ELF binary to re-link to the patched glibc. We employ this design from +[PTrix](https://github.com/junxzm1990/afl-pt). + +Check out all the git submodules in the `cs_mode` directory: + +```bash +git submodule update --init --recursive +``` + +### Build coresight-trace + +There are some notes on building coresight-trace. Refer to the [README](https://github.com/RICSecLab/coresight-trace/blob/master/README.md) for the details. Run make in the `cs_mode` directory: + +```bash +make build +``` + +Make sure `cs-proxy` is placed in the AFL++ root directory as `afl-cs-proxy`. + +### Patch COTS binary + +The fork server mode requires patchelf and the patched glibc. The dependency build can be done by just run make: + +```bash +make patch TARGET=$BIN +``` + +The above make command builds and installs the dependencies to `$PREFIX` (default to `$PWD/.local`) at the first time. Then, it runs `patchelf` to `$BIN` with output `$OUTPUT` (`$BIN.patched` by default). + +### Run afl-fuzz + +Run `afl-fuzz` with `-A` option to use CoreSight mode. + +```bash +sudo afl-fuzz -A -i input -o output -- $OUTPUT @@ +``` + +## Environment Variables + +There are AFL++ CoreSight mode-specific environment variables for run-time configuration. + +* `AFL_CS_CUSTOM_BIN` overrides the proxy application path. `afl-cs-proxy` will be used if not defined. + +* `AFLCS_COV` specifies coverage type on CoreSight trace decoding. `edge` and `path` is supported. The default value is `edge`. +* `AFLCS_UDMABUF` is the u-dma-buf device number used to store trace data in the DMA region. The default value is `0`. + +## TODO List + +* Eliminate modified glibc dependency +* Support parallel fuzzing + +## Acknowledgements + +This project has received funding from the Acquisition, Technology & Logistics Agency (ATLA) under the National Security Technology Research Promotion Fund 2021 (JPJ004596). diff --git a/coresight_mode/coresight-trace b/coresight_mode/coresight-trace new file mode 160000 +Subproject ec0fd6104720ac0b59967616363dc18209adc02 diff --git a/coresight_mode/patchelf b/coresight_mode/patchelf new file mode 160000 +Subproject 7ec8edbe094ee13c91dadca191f92b9dfac8c0f diff --git a/coresight_mode/patches/0001-Add-AFL-forkserver.patch b/coresight_mode/patches/0001-Add-AFL-forkserver.patch new file mode 100644 index 00000000..51c242c4 --- /dev/null +++ b/coresight_mode/patches/0001-Add-AFL-forkserver.patch @@ -0,0 +1,117 @@ +diff --git a/glibc-2.33/elf/rtld.c b/glibc-2.33/elf/rtld.c +index 596b6ac3..2ee270d4 100644 +--- a/glibc-2.33/elf/rtld.c ++++ b/glibc-2.33/elf/rtld.c +@@ -169,6 +169,99 @@ uintptr_t __pointer_chk_guard_local + strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) + #endif + ++#define AFLCS_RTLD 1 ++ ++#if AFLCS_RTLD ++ ++#include <sys/shm.h> ++#include <sys/types.h> ++#include <sys/wait.h> ++#include <dlfcn.h> ++#include <signal.h> ++ ++#include <asm/unistd.h> ++#include <unistd.h> ++ ++#define FORKSRV_FD 198 ++ ++#define AFLCS_ENABLE "__AFLCS_ENABLE" ++ ++/* We use this additional AFLCS_# AFLCS_#+1 pair to communicate with proxy */ ++#define AFLCS_FORKSRV_FD (FORKSRV_FD - 3) ++#define AFLCS_RTLD_SNIPPET do { __cs_start_forkserver(); } while(0) ++ ++/* Fork server logic, invoked before we return from _dl_start. */ ++ ++static void __cs_start_forkserver(void) { ++ int status; ++ pid_t child_pid; ++ static char tmp[4] = {0, 0, 0, 0}; ++ ++ if (!getenv(AFLCS_ENABLE)) { ++ return; ++ } ++ ++ if (write(AFLCS_FORKSRV_FD + 1, tmp, 4) != 4) { ++ _exit(-1); ++ } ++ ++ /* All right, let's await orders... */ ++ while (1) { ++ /* Whoops, parent dead? */ ++ if (read(AFLCS_FORKSRV_FD, tmp, 4) != 4) { ++ _exit(1); ++ } ++ ++ child_pid = INLINE_SYSCALL(clone, 5, ++ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, ++ NULL, NULL, &THREAD_SELF->tid); ++ if (child_pid < 0) { ++ _exit(4); ++ } ++ if (!child_pid) { ++ /* Child process. Wait for parent start tracing */ ++ kill(getpid(), SIGSTOP); ++ /* Close descriptors and run free. */ ++ close(AFLCS_FORKSRV_FD); ++ close(AFLCS_FORKSRV_FD + 1); ++ return; ++ } ++ ++ /* Parent. */ ++ if (write(AFLCS_FORKSRV_FD + 1, &child_pid, 4) != 4) { ++ _exit(5); ++ } ++ ++ /* Wait until SIGCONT is signaled. */ ++ if (waitpid(child_pid, &status, WCONTINUED) < 0) { ++ _exit(6); ++ } ++ if (!WIFCONTINUED(status)) { ++ /* Relay status to proxy. */ ++ if (write(AFLCS_FORKSRV_FD + 1, &status, 4) != 4) { ++ _exit(7); ++ } ++ continue; ++ } ++ while (1) { ++ /* Get status. */ ++ if (waitpid(child_pid, &status, WUNTRACED) < 0) { ++ _exit(8); ++ } ++ /* Relay status to proxy. */ ++ if (write(AFLCS_FORKSRV_FD + 1, &status, 4) != 4) { ++ _exit(9); ++ } ++ if (!(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP)) { ++ /* The child process is exited. */ ++ break; ++ } ++ } ++ } ++} ++ ++#endif /* AFLCS_RTLD */ ++ + /* Check that AT_SECURE=0, or that the passed name does not contain + directories and is not overly long. Reject empty names + unconditionally. */ +@@ -588,6 +681,12 @@ _dl_start (void *arg) + # define ELF_MACHINE_START_ADDRESS(map, start) (start) + #endif + ++ /* AFL-CS-START */ ++#if AFLCS_RTLD ++ AFLCS_RTLD_SNIPPET; ++#endif ++ /* AFL-CS-END */ ++ + return ELF_MACHINE_START_ADDRESS (GL(dl_ns)[LM_ID_BASE]._ns_loaded, entry); + } + } |