about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.gitmodules6
-rw-r--r--GNUmakefile16
-rw-r--r--coresight_mode/.gitignore2
-rw-r--r--coresight_mode/GNUmakefile62
-rw-r--r--coresight_mode/Makefile21
-rw-r--r--coresight_mode/README.md64
m---------coresight_mode/coresight-trace0
m---------coresight_mode/patchelf0
-rw-r--r--coresight_mode/patches/0001-Add-AFL-forkserver.patch117
-rw-r--r--include/common.h1
-rw-r--r--include/forkserver.h2
-rw-r--r--src/afl-analyze.c22
-rw-r--r--src/afl-common.c29
-rw-r--r--src/afl-fuzz-init.c5
-rw-r--r--src/afl-fuzz-stats.c9
-rw-r--r--src/afl-fuzz.c51
-rw-r--r--src/afl-showmap.c25
-rw-r--r--src/afl-tmin.c21
19 files changed, 439 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index 5268bb37..22ee6bf1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@ afl-g++-fast
 afl-gotcpu
 afl-ld
 afl-ld-lto
+afl-cs-proxy
 afl-qemu-trace
 afl-showmap
 afl-tmin
@@ -94,3 +95,5 @@ utils/optimin/optimin
 utils/persistent_mode/persistent_demo
 utils/persistent_mode/persistent_demo_new
 utils/persistent_mode/test-instr
+!coresight_mode
+!coresight_mode/coresight-trace
diff --git a/.gitmodules b/.gitmodules
index 200f3ecc..cd9d73e9 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,9 @@
 [submodule "utils/optimin/EvalMaxSAT"]
 	path = utils/optimin/EvalMaxSAT
 	url = https://github.com/FlorentAvellaneda/EvalMaxSAT
+[submodule "coresight_mode/patchelf"]
+	path = coresight_mode/patchelf
+	url = https://github.com/NixOS/patchelf.git
+[submodule "coresight_mode/coresight-trace"]
+	path = coresight_mode/coresight-trace
+	url = git@github.com:RICSecLab/coresight-trace.git
diff --git a/GNUmakefile b/GNUmakefile
index 06840786..ab57e7ad 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -346,7 +346,7 @@ help:
 	@echo "HELP --- the following make targets exist:"
 	@echo "=========================================="
 	@echo "all: just the main afl++ binaries"
-	@echo "binary-only: everything for binary-only fuzzing: qemu_mode, unicorn_mode, libdislocator, libtokencap"
+	@echo "binary-only: everything for binary-only fuzzing: coresight_mode, qemu_mode, unicorn_mode, libdislocator, libtokencap"
 	@echo "source-only: everything for source code fuzzing: gcc_plugin, libdislocator, libtokencap"
 	@echo "distrib: everything (for both binary-only and source code fuzzing)"
 	@echo "man: creates simple man pages from the help option of the programs"
@@ -564,7 +564,7 @@ all_done: test_build
 
 .PHONY: clean
 clean:
-	rm -rf $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM
+	rm -rf $(PROGS) libradamsa.so afl-fuzz-document afl-as as afl-g++ afl-clang afl-clang++ *.o src/*.o *~ a.out core core.[1-9][0-9]* *.stackdump .test .test1 .test2 test-instr .test-instr0 .test-instr1 afl-cs-proxy afl-qemu-trace afl-gcc-fast afl-gcc-pass.so afl-g++-fast ld *.so *.8 test/unittests/*.o test/unittests/unit_maybe_alloc test/unittests/preallocable .afl-* afl-gcc afl-g++ afl-clang afl-clang++ test/unittests/unit_hash test/unittests/unit_rand *.dSYM
 	-$(MAKE) -f GNUmakefile.llvm clean
 	-$(MAKE) -f GNUmakefile.gcc_plugin clean
 	$(MAKE) -C utils/libdislocator clean
@@ -579,19 +579,23 @@ clean:
 	$(MAKE) -C qemu_mode/libqasan clean
 	-$(MAKE) -C frida_mode clean
 ifeq "$(IN_REPO)" "1"
+	-test -e coresight_mode/coresight-trace/Makefile && $(MAKE) -C coresight_mode/coresight-trace clean || true
 	-test -e qemu_mode/qemuafl/Makefile && $(MAKE) -C qemu_mode/qemuafl clean || true
 	test -e unicorn_mode/unicornafl/Makefile && $(MAKE) -C unicorn_mode/unicornafl clean || true
 else
+	rm -rf coresight_mode/coresight_trace
 	rm -rf qemu_mode/qemuafl
 	rm -rf unicorn_mode/unicornafl
 endif
 
 .PHONY: deepclean
 deepclean:	clean
+	rm -rf coresight_mode/coresight-trace
 	rm -rf unicorn_mode/unicornafl
 	rm -rf qemu_mode/qemuafl
 ifeq "$(IN_REPO)" "1"
 # NEVER EVER ACTIVATE THAT!!!!! git reset --hard >/dev/null 2>&1 || true
+	git checkout coresight_mode/coresight-trace
 	git checkout unicorn_mode/unicornafl
 	git checkout qemu_mode/qemuafl
 endif
@@ -610,6 +614,9 @@ endif
 	# -$(MAKE) -C utils/plot_ui
 	-$(MAKE) -C frida_mode
 ifneq "$(SYS)" "Darwin"
+ifeq "$(ARCH)" "aarch64"
+	-$(MAKE) -C coresight_mode
+endif
 	-cd qemu_mode && sh ./build_qemu_support.sh
 	-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
 endif
@@ -624,6 +631,9 @@ binary-only: test_shm test_python ready $(PROGS)
 	# -$(MAKE) -C utils/plot_ui
 	-$(MAKE) -C frida_mode
 ifneq "$(SYS)" "Darwin"
+ifeq "$(ARCH)" "aarch64"
+	-$(MAKE) -C coresight_mode
+endif
 	-cd qemu_mode && sh ./build_qemu_support.sh
 	-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
 endif
@@ -695,7 +705,7 @@ endif
 
 .PHONY: uninstall
 uninstall:
-	-cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto*
+	-cd $${DESTDIR}$(BIN_PATH) && rm -f $(PROGS) $(SH_PROGS) afl-cs-proxy afl-qemu-trace afl-plot-ui afl-fuzz-document afl-network-server afl-g* afl-plot.sh afl-as afl-ld-lto afl-c* afl-lto*
 	-cd $${DESTDIR}$(HELPER_PATH) && rm -f afl-g*.*o afl-llvm-*.*o afl-compiler-*.*o libdislocator.so libtokencap.so libcompcov.so libqasan.so afl-frida-trace.so socketfuzz*.so argvfuzz*.so libAFLDriver.a libAFLQemuDriver.a as afl-as SanitizerCoverage*.so compare-transform-pass.so cmplog-*-pass.so split-*-pass.so dynamic_list.txt
 	-rm -rf $${DESTDIR}$(MISC_PATH)/testcases $${DESTDIR}$(MISC_PATH)/dictionaries
 	-sh -c "ls docs/*.md | sed 's|^docs/|$${DESTDIR}$(DOC_PATH)/|' | xargs rm -f"
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..31e77d92
--- /dev/null
+++ b/coresight_mode/README.md
@@ -0,0 +1,64 @@
+# AFL++ CoreSight mode
+
+CoreSight mode enables binary-only fuzzing on ARM64 Linux using CoreSight.
+
+NOTE: CoreSight mode is in the early development stage. Not applicable for production use.
+
+## Getting started
+
+Please read the [RICSec/coresight-trace README](https://github.com/RICSecLab/coresight-trace/blob/master/README.md) and check the prerequisites 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
+
+* Change `afl-showmap` ARM CoreSight mode option to `-A` without conflict
+* 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);
+   }
+ }
diff --git a/include/common.h b/include/common.h
index e3997aa4..6c8e3b3a 100644
--- a/include/common.h
+++ b/include/common.h
@@ -46,6 +46,7 @@ void check_environment_vars(char **env);
 char **argv_cpy_dup(int argc, char **argv);
 void   argv_cpy_free(char **argv);
 
+char **get_cs_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
 char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
 char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv);
 char * get_afl_env(char *env);
diff --git a/include/forkserver.h b/include/forkserver.h
index 7af01cb2..464f208d 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -82,6 +82,8 @@ typedef struct afl_forkserver {
 
   bool frida_asan;                    /* if running with asan in frida mode */
 
+  bool cs_mode;                      /* if running in CoreSight mode or not */
+
   bool use_stdin;                       /* use stdin for sending data       */
 
   bool no_unlink;                       /* do not unlink cur_input          */
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index d52a6d6e..bc562c15 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -77,6 +77,7 @@ static volatile u8 stop_soon;          /* Ctrl-C pressed?                   */
 static u8 *target_path;
 static u8  frida_mode;
 static u8  qemu_mode;
+static u8  cs_mode;
 static u32 map_size = MAP_SIZE;
 
 static afl_forkserver_t fsrv = {0};   /* The forkserver                     */
@@ -790,6 +791,8 @@ static void set_up_environment(char **argv) {
 
     } else {
 
+      /* CoreSight mode uses the default behavior. */
+
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
       setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
 
@@ -845,6 +848,7 @@ static void usage(u8 *argv0) {
       "  -f file       - input file read by the tested program (stdin)\n"
       "  -t msec       - timeout for each run (%u ms)\n"
       "  -m megs       - memory limit for child process (%u MB)\n"
+      "  -A            - use binary-only instrumentation (ARM CoreSight mode)\n"
       "  -O            - use binary-only instrumentation (FRIDA mode)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
@@ -890,7 +894,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   afl_fsrv_init(&fsrv);
 
-  while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWh")) > 0) {
 
     switch (opt) {
 
@@ -989,6 +993,18 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      case 'A':                                           /* CoreSight mode */
+
+#if !defined(__aarch64__) || !defined(__linux__)
+        FATAL("-A option is not supported on this platform");
+#endif
+
+        if (cs_mode) { FATAL("Multiple -A options not supported"); }
+
+        cs_mode = 1;
+        fsrv.cs_mode = cs_mode;
+        break;
+
       case 'O':                                               /* FRIDA mode */
 
         if (frida_mode) { FATAL("Multiple -O options not supported"); }
@@ -1080,6 +1096,10 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
+  } else if (cs_mode) {
+
+    use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
+
   } else {
 
     use_argv = argv + optind;
diff --git a/src/afl-common.c b/src/afl-common.c
index ec3b2f3f..6c2d0753 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -204,6 +204,35 @@ void argv_cpy_free(char **argv) {
 
 }
 
+/* Rewrite argv for CoreSight process tracer. */
+
+char **get_cs_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
+
+  if (unlikely(getenv("AFL_CS_CUSTOM_BIN"))) {
+
+    WARNF(
+        "AFL_CS_CUSTOM_BIN is enabled. "
+        "You must run your target under afl-cs-proxy on your own!");
+    return argv;
+
+  }
+
+  char **new_argv = ck_alloc(sizeof(char *) * (argc + 4));
+  if (unlikely(!new_argv)) { FATAL("Illegal amount of arguments specified"); }
+
+  memcpy(&new_argv[3], &argv[1], (int)(sizeof(char *)) * (argc - 1));
+  new_argv[argc + 3] = NULL;
+
+  new_argv[2] = *target_path_p;
+  new_argv[1] = "--";
+
+  /* Now we need to actually find the cs-proxy binary to put in argv[0]. */
+
+  *target_path_p = new_argv[0] = find_afl_binary(own_loc, "afl-cs-proxy");
+  return new_argv;
+
+}
+
 /* Rewrite argv for QEMU. */
 
 char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 9262d718..e5a4d3d1 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -2645,6 +2645,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
   if (afl->afl_env.afl_skip_bin_check || afl->use_wine || afl->unicorn_mode ||
       (afl->fsrv.qemu_mode && getenv("AFL_QEMU_CUSTOM_BIN")) ||
+      (afl->fsrv.cs_mode && getenv("AFL_CS_CUSTOM_BIN")) ||
       afl->non_instrumented_mode) {
 
     return;
@@ -2721,7 +2722,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 #endif                                                       /* ^!__APPLE__ */
 
   if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode &&
-      !afl->non_instrumented_mode &&
+      !afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
       !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
     SAYF("\n" cLRD "[-] " cRST
@@ -2752,7 +2753,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 
   }
 
-  if ((afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
+  if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
       memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
     SAYF("\n" cLRD "[-] " cRST
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 808bf258..426580d2 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -285,7 +285,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
           "afl_banner        : %s\n"
           "afl_version       : " VERSION
           "\n"
-          "target_mode       : %s%s%s%s%s%s%s%s%s\n"
+          "target_mode       : %s%s%s%s%s%s%s%s%s%s\n"
           "command_line      : %s\n",
           (afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000,
           (afl->prev_run_time + cur_time - afl->start_time) / 1000,
@@ -321,12 +321,13 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
           afl->q_testcase_cache_count, afl->q_testcase_evictions,
           afl->use_banner, afl->unicorn_mode ? "unicorn" : "",
           afl->fsrv.qemu_mode ? "qemu " : "",
+          afl->fsrv.cs_mode ? "coresight" : "",
           afl->non_instrumented_mode ? " non_instrumented " : "",
           afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
           afl->persistent_mode ? "persistent " : "",
           afl->shmem_testcase_mode ? "shmem_testcase " : "",
           afl->deferred_mode ? "deferred " : "",
-          (afl->unicorn_mode || afl->fsrv.qemu_mode ||
+          (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->fsrv.cs_mode ||
            afl->non_instrumented_mode || afl->no_forkserver ||
            afl->crash_mode || afl->persistent_mode || afl->deferred_mode)
               ? ""
@@ -1238,7 +1239,9 @@ void show_init_stats(afl_state_t *afl) {
 
   // SAYF("\n");
 
-  if (avg_us > ((afl->fsrv.qemu_mode || afl->unicorn_mode) ? 50000 : 10000)) {
+  if (avg_us > ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->unicorn_mode)
+                    ? 50000
+                    : 10000)) {
 
     WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.md.",
           doc_path);
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index c08b8fbb..dfd62db8 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -113,6 +113,7 @@ static void usage(u8 *argv0, int more_help) {
       "maximum.\n"
       "  -m megs       - memory limit for child process (%u MB, 0 = no limit "
       "[default])\n"
+      "  -A            - use binary-only instrumentation (ARM CoreSight mode)\n"
       "  -O            - use binary-only instrumentation (FRIDA mode)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
@@ -434,7 +435,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
   while ((opt = getopt(
               argc, argv,
-              "+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) > 0) {
+              "+Ab:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) >
+         0) {
 
     switch (opt) {
 
@@ -563,6 +565,12 @@ int main(int argc, char **argv_orig, char **envp) {
 
         }
 
+        if (afl->fsrv.cs_mode) {
+
+          FATAL("-M is not supported in ARM CoreSight mode");
+
+        }
+
         if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
 
         /* sanity check for argument: should not begin with '-' (possible
@@ -609,6 +617,12 @@ int main(int argc, char **argv_orig, char **envp) {
 
         }
 
+        if (afl->fsrv.cs_mode) {
+
+          FATAL("-S is not supported in ARM CoreSight mode");
+
+        }
+
         if (afl->sync_id) { FATAL("Multiple -S or -M options not supported"); }
 
         /* sanity check for argument: should not begin with '-' (possible
@@ -825,6 +839,24 @@ int main(int argc, char **argv_orig, char **envp) {
         afl->use_banner = optarg;
         break;
 
+      case 'A':                                           /* CoreSight mode */
+
+  #if !defined(__aarch64__) || !defined(__linux__)
+        FATAL("-A option is not supported on this platform");
+  #endif
+
+        if (afl->is_main_node || afl->is_secondary_node) {
+
+          FATAL("ARM CoreSight mode is not supported with -M / -S");
+
+        }
+
+        if (afl->fsrv.cs_mode) { FATAL("Multiple -A options not supported"); }
+
+        afl->fsrv.cs_mode = 1;
+
+        break;
+
       case 'O':                                               /* FRIDA mode */
 
         if (afl->fsrv.frida_mode) {
@@ -1212,6 +1244,7 @@ int main(int argc, char **argv_orig, char **envp) {
     if (afl->crash_mode) { FATAL("-C and -n are mutually exclusive"); }
     if (afl->fsrv.frida_mode) { FATAL("-O and -n are mutually exclusive"); }
     if (afl->fsrv.qemu_mode) { FATAL("-Q and -n are mutually exclusive"); }
+    if (afl->fsrv.cs_mode) { FATAL("-A and -n are mutually exclusive"); }
     if (afl->unicorn_mode) { FATAL("-U and -n are mutually exclusive"); }
 
   }
@@ -1458,6 +1491,8 @@ int main(int argc, char **argv_orig, char **envp) {
 
     } else {
 
+      /* CoreSight mode uses the default behavior. */
+
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
       setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
 
@@ -1651,7 +1686,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
-    if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode &&
+    if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
         !afl->non_instrumented_mode) {
 
       check_binary(afl, afl->cmplog_binary);
@@ -1697,6 +1732,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
+  } else if (afl->fsrv.cs_mode) {
+
+    use_argv = get_cs_argv(argv[0], &afl->fsrv.target_path, argc - optind,
+                           argv + optind);
+
   } else {
 
     use_argv = argv + optind;
@@ -1704,7 +1744,7 @@ int main(int argc, char **argv_orig, char **envp) {
   }
 
   if (afl->non_instrumented_mode || afl->fsrv.qemu_mode ||
-      afl->fsrv.frida_mode || afl->unicorn_mode) {
+      afl->fsrv.frida_mode || afl->fsrv.cs_mode || afl->unicorn_mode) {
 
     map_size = afl->fsrv.real_map_size = afl->fsrv.map_size = MAP_SIZE;
     afl->virgin_bits = ck_realloc(afl->virgin_bits, map_size);
@@ -1724,7 +1764,7 @@ int main(int argc, char **argv_orig, char **envp) {
       afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->non_instrumented_mode);
 
   if (!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
-      !afl->unicorn_mode && !afl->fsrv.frida_mode &&
+      !afl->unicorn_mode && !afl->fsrv.frida_mode && !afl->fsrv.cs_mode &&
       !afl->afl_env.afl_skip_bin_check) {
 
     if (map_size <= DEFAULT_SHMEM_SIZE) {
@@ -1777,6 +1817,7 @@ int main(int argc, char **argv_orig, char **envp) {
     afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
     // TODO: this is semi-nice
     afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
+    afl->cmplog_fsrv.cs_mode = afl->fsrv.cs_mode;
     afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
     afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode;
     afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
@@ -1785,7 +1826,7 @@ int main(int argc, char **argv_orig, char **envp) {
     if ((map_size <= DEFAULT_SHMEM_SIZE ||
          afl->cmplog_fsrv.map_size < map_size) &&
         !afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
-        !afl->fsrv.frida_mode && !afl->unicorn_mode &&
+        !afl->fsrv.frida_mode && !afl->unicorn_mode && !afl->fsrv.cs_mode &&
         !afl->afl_env.afl_skip_bin_check) {
 
       afl->cmplog_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 6c06c476..899baaa0 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -690,6 +690,8 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
 
     } else {
 
+      /* CoreSight mode uses the default behavior. */
+
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
       setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
 
@@ -843,6 +845,7 @@ static void usage(u8 *argv0) {
       "  -t msec    - timeout for each run (none)\n"
       "  -m megs    - memory limit for child process (%u MB)\n"
       "  -O         - use binary-only instrumentation (FRIDA mode)\n"
+      "  -P         - use binary-only instrumentation (ARM CoreSight mode)\n"
       "  -Q         - use binary-only instrumentation (QEMU mode)\n"
       "  -U         - use Unicorn-based instrumentation (Unicorn mode)\n"
       "  -W         - use qemu-based instrumentation with Wine (Wine mode)\n"
@@ -917,7 +920,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOPQUWbcrsh")) > 0) {
 
     switch (opt) {
 
@@ -1060,6 +1063,19 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      /* FIXME: We want to use -P for consistency, but it is already unsed for
+       * undocumenetd feature "Another afl-cmin specific feature." */
+      case 'P':                                           /* CoreSight mode */
+
+#if !defined(__aarch64__) || !defined(__linux__)
+        FATAL("-P option is not supported on this platform");
+#endif
+
+        if (fsrv->cs_mode) { FATAL("Multiple -P options not supported"); }
+
+        fsrv->cs_mode = true;
+        break;
+
       case 'Q':
 
         if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); }
@@ -1204,6 +1220,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
+  } else if (fsrv->cs_mode) {
+
+    use_argv =
+        get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+
   } else {
 
     use_argv = argv + optind;
@@ -1230,7 +1251,7 @@ int main(int argc, char **argv_orig, char **envp) {
   fsrv->shmem_fuzz_len = (u32 *)map;
   fsrv->shmem_fuzz = map + sizeof(u32);
 
-  if (!fsrv->qemu_mode && !unicorn_mode) {
+  if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) {
 
     u32 save_be_quiet = be_quiet;
     be_quiet = !debug;
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 3f6f14f9..22383a4e 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -808,6 +808,8 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
 
     } else {
 
+      /* CoreSight mode uses the default behavior. */
+
       setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1);
       setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1);
 
@@ -864,6 +866,7 @@ static void usage(u8 *argv0) {
       "  -f file       - input file read by the tested program (stdin)\n"
       "  -t msec       - timeout for each run (%u ms)\n"
       "  -m megs       - memory limit for child process (%u MB)\n"
+      "  -A            - use binary-only instrumentation (ARM CoreSight mode)\n"
       "  -O            - use binary-only instrumentation (FRIDA mode)\n"
       "  -Q            - use binary-only instrumentation (QEMU mode)\n"
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
@@ -921,7 +924,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeOQUWHh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWHh")) > 0) {
 
     switch (opt) {
 
@@ -1033,6 +1036,17 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      case 'A':                                           /* CoreSight mode */
+
+#if !defined(__aarch64__) || !defined(__linux__)
+        FATAL("-A option is not supported on this platform");
+#endif
+
+        if (fsrv->cs_mode) { FATAL("Multiple -A options not supported"); }
+
+        fsrv->cs_mode = 1;
+        break;
+
       case 'O':                                               /* FRIDA mode */
 
         if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); }
@@ -1152,6 +1166,11 @@ int main(int argc, char **argv_orig, char **envp) {
 
     }
 
+  } else if (fsrv->cs_mode) {
+
+    use_argv =
+        get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+
   } else {
 
     use_argv = argv + optind;