about summary refs log tree commit diff
path: root/coresight_mode
diff options
context:
space:
mode:
Diffstat (limited to 'coresight_mode')
-rw-r--r--coresight_mode/.gitignore2
-rw-r--r--coresight_mode/GNUmakefile62
-rw-r--r--coresight_mode/Makefile21
-rw-r--r--coresight_mode/README.md70
m---------coresight_mode/coresight-trace0
m---------coresight_mode/patchelf0
-rw-r--r--coresight_mode/patches/0001-Add-AFL-forkserver.patch117
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);
+   }
+ }