Remove AFL Integration by reverting
This commit is contained in:
parent
7ac7c23c12
commit
e695686c15
@ -35,8 +35,6 @@ else()
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
# Try to build AFL support on all other platform.
|
||||
set(UNICORN_HAS_AFL TRUE)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
@ -328,10 +326,6 @@ else()
|
||||
OUTPUT_FILE ${CMAKE_BINARY_DIR}/riscv64-softmmu/config-target.h
|
||||
)
|
||||
endif()
|
||||
if (UNICORN_HAS_AFL)
|
||||
# Make it globally
|
||||
set (UNICORN_CFLAGS ${UNICORN_CFLAGS} -DUNICORN_HAS_AFL)
|
||||
endif()
|
||||
add_compile_options(
|
||||
${UNICORN_CFLAGS}
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/tcg/${UNICORN_TARGET_ARCH}
|
||||
|
@ -24,8 +24,8 @@ build:
|
||||
$(MAKE) -C go gen_const
|
||||
$(MAKE) -C java gen_const
|
||||
$(MAKE) -C ruby gen_const
|
||||
python3 const_generator.py dotnet
|
||||
python3 const_generator.py pascal
|
||||
python const_generator.py dotnet
|
||||
python const_generator.py pascal
|
||||
|
||||
install: build
|
||||
$(MAKE) -C python install
|
||||
|
@ -28,7 +28,6 @@ module Common =
|
||||
|
||||
let UC_MODE_LITTLE_ENDIAN = 0
|
||||
let UC_MODE_BIG_ENDIAN = 1073741824
|
||||
let UC_MODE_AFL = 536870912
|
||||
|
||||
let UC_MODE_ARM = 0
|
||||
let UC_MODE_THUMB = 16
|
||||
@ -76,10 +75,6 @@ module Common =
|
||||
let UC_ERR_HOOK_EXIST = 19
|
||||
let UC_ERR_RESOURCE = 20
|
||||
let UC_ERR_EXCEPTION = 21
|
||||
let UC_ERR_AFL_RET_ERROR = 22
|
||||
let UC_ERR_AFL_RET_NO_AFL = 23
|
||||
let UC_ERR_AFL_RET_CALLED_TWICE = 24
|
||||
let UC_ERR_AFL_RET_FINISHED = 25
|
||||
let UC_MEM_READ = 16
|
||||
let UC_MEM_WRITE = 17
|
||||
let UC_MEM_FETCH = 18
|
||||
|
@ -6,7 +6,7 @@ all: gen_const
|
||||
cd unicorn && go build
|
||||
|
||||
gen_const:
|
||||
cd .. && python3 const_generator.py go
|
||||
cd .. && python const_generator.py go
|
||||
|
||||
test: all
|
||||
cd unicorn && LD_LIBRARY_PATH=../../../ DYLD_LIBRARY_PATH=../../../ go test
|
||||
|
@ -23,7 +23,6 @@ const (
|
||||
|
||||
MODE_LITTLE_ENDIAN = 0
|
||||
MODE_BIG_ENDIAN = 1073741824
|
||||
MODE_AFL = 536870912
|
||||
|
||||
MODE_ARM = 0
|
||||
MODE_THUMB = 16
|
||||
@ -71,10 +70,6 @@ const (
|
||||
ERR_HOOK_EXIST = 19
|
||||
ERR_RESOURCE = 20
|
||||
ERR_EXCEPTION = 21
|
||||
ERR_AFL_RET_ERROR = 22
|
||||
ERR_AFL_RET_NO_AFL = 23
|
||||
ERR_AFL_RET_CALLED_TWICE = 24
|
||||
ERR_AFL_RET_FINISHED = 25
|
||||
MEM_READ = 16
|
||||
MEM_WRITE = 17
|
||||
MEM_FETCH = 18
|
||||
|
@ -19,7 +19,7 @@ uninstall:
|
||||
$(MAKE) -f Makefile.build uninstall
|
||||
|
||||
gen_const:
|
||||
cd .. && python3 const_generator.py java
|
||||
cd .. && python const_generator.py java
|
||||
|
||||
clean:
|
||||
rm -f unicorn/*.class
|
||||
|
@ -25,7 +25,6 @@ public interface UnicornConst {
|
||||
|
||||
public static final int UC_MODE_LITTLE_ENDIAN = 0;
|
||||
public static final int UC_MODE_BIG_ENDIAN = 1073741824;
|
||||
public static final int UC_MODE_AFL = 536870912;
|
||||
|
||||
public static final int UC_MODE_ARM = 0;
|
||||
public static final int UC_MODE_THUMB = 16;
|
||||
@ -73,10 +72,6 @@ public interface UnicornConst {
|
||||
public static final int UC_ERR_HOOK_EXIST = 19;
|
||||
public static final int UC_ERR_RESOURCE = 20;
|
||||
public static final int UC_ERR_EXCEPTION = 21;
|
||||
public static final int UC_ERR_AFL_RET_ERROR = 22;
|
||||
public static final int UC_ERR_AFL_RET_NO_AFL = 23;
|
||||
public static final int UC_ERR_AFL_RET_CALLED_TWICE = 24;
|
||||
public static final int UC_ERR_AFL_RET_FINISHED = 25;
|
||||
public static final int UC_MEM_READ = 16;
|
||||
public static final int UC_MEM_WRITE = 17;
|
||||
public static final int UC_MEM_FETCH = 18;
|
||||
|
@ -26,7 +26,6 @@ const UC_API_MAJOR = 2;
|
||||
|
||||
UC_MODE_LITTLE_ENDIAN = 0;
|
||||
UC_MODE_BIG_ENDIAN = 1073741824;
|
||||
UC_MODE_AFL = 536870912;
|
||||
|
||||
UC_MODE_ARM = 0;
|
||||
UC_MODE_THUMB = 16;
|
||||
@ -74,10 +73,6 @@ const UC_API_MAJOR = 2;
|
||||
UC_ERR_HOOK_EXIST = 19;
|
||||
UC_ERR_RESOURCE = 20;
|
||||
UC_ERR_EXCEPTION = 21;
|
||||
UC_ERR_AFL_RET_ERROR = 22;
|
||||
UC_ERR_AFL_RET_NO_AFL = 23;
|
||||
UC_ERR_AFL_RET_CALLED_TWICE = 24;
|
||||
UC_ERR_AFL_RET_FINISHED = 25;
|
||||
UC_MEM_READ = 16;
|
||||
UC_MEM_WRITE = 17;
|
||||
UC_MEM_FETCH = 18;
|
||||
|
@ -3,16 +3,16 @@
|
||||
.PHONY: gen_const install install3 clean sdist sdist3 bdist bdist3 sdist_win bdist_win
|
||||
|
||||
gen_const:
|
||||
cd .. && python3 const_generator.py python
|
||||
cd .. && python const_generator.py python
|
||||
|
||||
install:
|
||||
rm -rf src/ dist/
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
if test -n "${DESTDIR}"; then \
|
||||
python3 setup.py install --root="${DESTDIR}"; \
|
||||
python setup.py install --root="${DESTDIR}"; \
|
||||
else \
|
||||
python3 setup.py install; \
|
||||
python setup.py install; \
|
||||
fi
|
||||
|
||||
install3:
|
||||
@ -30,7 +30,7 @@ sdist:
|
||||
rm -rf src/ dist/
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
python3 setup.py sdist register upload
|
||||
python setup.py sdist register upload
|
||||
|
||||
# build & upload PyPi package with source code of the core
|
||||
sdist3:
|
||||
@ -44,7 +44,7 @@ bdist:
|
||||
rm -rf src/ dist/
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
python3 setup.py bdist_wheel register upload
|
||||
python setup.py bdist_wheel register upload
|
||||
|
||||
# build & upload PyPi package with precompiled core
|
||||
bdist3:
|
||||
@ -57,7 +57,7 @@ bdist3:
|
||||
# NOTE: be sure to have precompiled core under prebuilt/win*/ beforehand
|
||||
sdist_win:
|
||||
rm -rf src/ dist/
|
||||
python3 setup.py sdist register upload
|
||||
python setup.py sdist register upload
|
||||
|
||||
# build & upload PyPi package with prebuilt core
|
||||
# NOTE: be sure to have precompiled core under prebuilt/win*/ beforehand
|
||||
|
@ -9,7 +9,7 @@ import os.path
|
||||
import sys
|
||||
import weakref
|
||||
import functools
|
||||
import gc
|
||||
|
||||
from . import x86_const, arm64_const, unicorn_const as uc
|
||||
|
||||
if not hasattr(sys.modules[__name__], "__file__"):
|
||||
@ -120,15 +120,6 @@ class _uc_mem_region(ctypes.Structure):
|
||||
("perms", ctypes.c_uint32),
|
||||
]
|
||||
|
||||
#typedef bool (*uc_afl_cb_place_input_t)(uc_engine *uc, char *input,
|
||||
# size_t input_len, uint32_t persistent_round, void *data);
|
||||
AFL_PLACE_INPUT_CB = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.POINTER(ctypes.c_char),
|
||||
ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p)
|
||||
|
||||
#typedef bool (*uc_afl_cb_validate_crash_t)(uc_engine *uc, uc_err unicorn_result, char *input,
|
||||
# int input_len, int persistent_round, void *data);
|
||||
AFL_VALIDATE_CRASH_CB = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ucerr, ctypes.POINTER(ctypes.c_char),
|
||||
ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p)
|
||||
|
||||
_setup_prototype(_uc, "uc_version", ctypes.c_uint, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
|
||||
_setup_prototype(_uc, "uc_arch_supported", ctypes.c_bool, ctypes.c_int)
|
||||
@ -160,7 +151,6 @@ _setup_prototype(_uc, "uc_context_free", ucerr, uc_context)
|
||||
_setup_prototype(_uc, "uc_mem_regions", ucerr, uc_engine, ctypes.POINTER(ctypes.POINTER(_uc_mem_region)), ctypes.POINTER(ctypes.c_uint32))
|
||||
# https://bugs.python.org/issue42880
|
||||
_setup_prototype(_uc, "uc_hook_add", ucerr, uc_engine, ctypes.POINTER(uc_hook_h), ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64)
|
||||
_setup_prototype(_uc, "uc_afl_fuzz", ucerr, uc_engine, ctypes.c_char_p, ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint64), ctypes.c_size_t, ctypes.c_void_p, ctypes.c_bool, ctypes.c_uint32, ctypes.c_void_p)
|
||||
|
||||
UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p)
|
||||
UC_HOOK_INSN_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.c_void_p)
|
||||
@ -421,8 +411,6 @@ class Uc(object):
|
||||
self._callback_count = 0
|
||||
self._cleanup.register(self)
|
||||
|
||||
self.afl_called_before = False # type: bool
|
||||
|
||||
@staticmethod
|
||||
def release_handle(uch):
|
||||
if uch:
|
||||
@ -444,127 +432,6 @@ class Uc(object):
|
||||
status = _uc.uc_emu_stop(self._uch)
|
||||
if status != uc.UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
def afl_fuzz(
|
||||
self, # type: Uc
|
||||
input_file, # type: str
|
||||
place_input_callback, # type: Callable[[Uc, bytes, int, Any], Optional[bool]]
|
||||
exits, # type: List[int]
|
||||
validate_crash_callback=None, # type: Optional[Callable[[Uc, UcError, bytes, int, Any], Optional[bool]]]
|
||||
always_validate=False, # type: bool
|
||||
persistent_iters=1, # type: int
|
||||
data=None, # type: Any
|
||||
):
|
||||
# type: (...) -> bool
|
||||
"""
|
||||
The main fuzzer.
|
||||
Starts the forkserver, then beginns a persistent loop.
|
||||
Reads input, calls the place_input callback, emulates, repeats.
|
||||
If unicorn errors out, will call the validate_crash_callback, if set.
|
||||
Will only return in the parent after the whole fuzz thing has been finished and afl died.
|
||||
The child processes never return from here.
|
||||
|
||||
:param input_file: filename/path to the (AFL) inputfile. Usually supplied on the commandline.
|
||||
:param place_input_callback: Callback function that will be called before each test runs.
|
||||
This function needs to write the input from afl to the correct position on the unicorn object.
|
||||
This function is mandatory.
|
||||
It's purpose is to place the input at the right place in unicorn.
|
||||
|
||||
@uc: (Uc) Unicorn instance
|
||||
@input: (bytes) The current input we're working on. Place this somewhere in unicorn's memory now.
|
||||
@persistent_round: (int) which round we are currently crashing in, if using persistent mode.
|
||||
@data: (Any) Data pointer passed to uc_afl_fuzz(...).
|
||||
|
||||
@return: (bool)
|
||||
If you return is True (or None) all is well. Fuzzing starts.
|
||||
If you return False, the input is rejected; we will continue with the next input.
|
||||
:param exits: address list of exits where fuzzing should stop
|
||||
:param persistent_iters:
|
||||
The amount of loop iterations in persistent mode before restarting with a new forked child.
|
||||
If your target cannot be fuzzed using persistent mode (global state changes a lot),
|
||||
set persistent_iters = 1 for the normal fork-server experience.
|
||||
Else, the default is usually around 1000.
|
||||
If your target is super stable (and unicorn is, too - not sure about that one),
|
||||
you may pass persistent_iter = 0 for that an infinite fuzz loop.
|
||||
:param validate_crash_callback: Optional callback (if not needed, pass NULL), that determines
|
||||
if a non-OK uc_err is an actual error. If false is returned, the test-case will not crash.
|
||||
Callback function called after a non-UC_ERR_OK returncode was returned by Unicorn.
|
||||
This function is not mandatory.
|
||||
@uc: Unicorn instance
|
||||
@unicorn_result: The error state returned by the current testcase
|
||||
@input: The current input we're working with.
|
||||
@persistent_round: which round we are currently crashing in, if using persistent mode.
|
||||
@data: Data pointer passed to uc_afl_fuzz(...).
|
||||
|
||||
@Return:
|
||||
If you return false, the crash is considered invalid and not reported to AFL.
|
||||
-> Next loop iteration begins.
|
||||
If return is true, the crash is reported // the program crashes.
|
||||
-> The child will die and the forkserver will spawn a new child.
|
||||
:param always_validate: If false, validate_crash_callback will only be called for crashes.
|
||||
:param data: Your very own data pointer. This will passed into every callback.
|
||||
|
||||
:return:
|
||||
True, if we fuzzed.
|
||||
False, if AFL was not available but we ran once.
|
||||
raises UcAflException if nothing worked.
|
||||
"""
|
||||
if self.afl_called_before:
|
||||
raise UcError(uc.UC_ERR_AFL_RET_CALLED_TWICE)
|
||||
self.afl_called_before = True
|
||||
self._pre_afl()
|
||||
exit_count = len(exits)
|
||||
|
||||
def place_input_wrapper(c_uc, input, input_len, persistent_round, c_data):
|
||||
# print("Calling back home. :)", c_uc, input, input_len, persistent_round, c_data)
|
||||
ret = place_input_callback(
|
||||
self,
|
||||
ctypes.cast(input, ctypes.POINTER(ctypes.c_char * input_len)).contents,
|
||||
persistent_round,
|
||||
data
|
||||
)
|
||||
if ret is False:
|
||||
return False
|
||||
return True
|
||||
|
||||
def validate_crash_wrapper(c_uc, uc_err, input, input_len, persistent_round, c_data):
|
||||
# print("Calling after crash!", c_uc, input, input_len, persistent_round, c_data)
|
||||
# assert type(uc_err) == int
|
||||
ret = validate_crash_callback(
|
||||
self,
|
||||
UcError(uc_err),
|
||||
ctypes.cast(input, ctypes.POINTER(ctypes.c_char * input_len)).contents,
|
||||
persistent_round,
|
||||
data
|
||||
)
|
||||
if ret is False or (ret is None and uc_err == uc.UC_ERR_OK):
|
||||
return False
|
||||
return True
|
||||
|
||||
# This only returns in the parent, child processes all die or loop or other things.
|
||||
status = _uc.uc_afl_fuzz(
|
||||
self._uch,
|
||||
input_file.encode('utf-8'),
|
||||
AFL_PLACE_INPUT_CB(place_input_wrapper),
|
||||
(ctypes.c_uint64 * exit_count)(*exits),
|
||||
exit_count, # bad languages, like c, need more params.
|
||||
AFL_VALIDATE_CRASH_CB(validate_crash_wrapper) if validate_crash_callback else None,
|
||||
always_validate,
|
||||
persistent_iters,
|
||||
None # no need to pass the user data through C as the callback keeps it as closure.
|
||||
)
|
||||
if status != uc.UC_ERR_OK:
|
||||
# Something went wrong.
|
||||
raise UcError(status)
|
||||
|
||||
def _pre_afl(self):
|
||||
# type: (Uc) -> None
|
||||
"""
|
||||
Internal func making sure exits are set and flushing buffers/gc
|
||||
:param exits: exits
|
||||
"""
|
||||
sys.stdout.flush() # otherwise children will inherit the unflushed buffer
|
||||
gc.collect() # Collect all unneeded memory, No need to clone it on fork.
|
||||
|
||||
# return the value of a register
|
||||
def reg_read(self, reg_id, opt=None):
|
||||
|
@ -21,7 +21,6 @@ UC_ARCH_MAX = 9
|
||||
|
||||
UC_MODE_LITTLE_ENDIAN = 0
|
||||
UC_MODE_BIG_ENDIAN = 1073741824
|
||||
UC_MODE_AFL = 536870912
|
||||
|
||||
UC_MODE_ARM = 0
|
||||
UC_MODE_THUMB = 16
|
||||
@ -69,10 +68,6 @@ UC_ERR_FETCH_UNALIGNED = 18
|
||||
UC_ERR_HOOK_EXIST = 19
|
||||
UC_ERR_RESOURCE = 20
|
||||
UC_ERR_EXCEPTION = 21
|
||||
UC_ERR_AFL_RET_ERROR = 22
|
||||
UC_ERR_AFL_RET_NO_AFL = 23
|
||||
UC_ERR_AFL_RET_CALLED_TWICE = 24
|
||||
UC_ERR_AFL_RET_FINISHED = 25
|
||||
UC_MEM_READ = 16
|
||||
UC_MEM_WRITE = 17
|
||||
UC_MEM_FETCH = 18
|
||||
|
@ -8,4 +8,4 @@ install: gen_const
|
||||
cd unicorn_gem && gem install --local pkg/unicorn-engine-1.0.1.gem
|
||||
|
||||
gen_const:
|
||||
cd .. && python3 const_generator.py ruby
|
||||
cd .. && python const_generator.py ruby
|
||||
|
@ -23,7 +23,6 @@ module UnicornEngine
|
||||
|
||||
UC_MODE_LITTLE_ENDIAN = 0
|
||||
UC_MODE_BIG_ENDIAN = 1073741824
|
||||
UC_MODE_AFL = 536870912
|
||||
|
||||
UC_MODE_ARM = 0
|
||||
UC_MODE_THUMB = 16
|
||||
@ -71,10 +70,6 @@ module UnicornEngine
|
||||
UC_ERR_HOOK_EXIST = 19
|
||||
UC_ERR_RESOURCE = 20
|
||||
UC_ERR_EXCEPTION = 21
|
||||
UC_ERR_AFL_RET_ERROR = 22
|
||||
UC_ERR_AFL_RET_NO_AFL = 23
|
||||
UC_ERR_AFL_RET_CALLED_TWICE = 24
|
||||
UC_ERR_AFL_RET_FINISHED = 25
|
||||
UC_MEM_READ = 16
|
||||
UC_MEM_WRITE = 17
|
||||
UC_MEM_FETCH = 18
|
||||
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
/* NeverZero */
|
||||
|
||||
#if (defined(__x86_64__) || defined(__i386__)) && defined(AFL_QEMU_NOT_ZERO)
|
||||
#define INC_AFL_AREA(loc) \
|
||||
asm volatile( \
|
||||
"addb $1, (%0, %1, 1)\n" \
|
||||
"adcb $0, (%0, %1, 1)\n" \
|
||||
: /* no out */ \
|
||||
: "r"(afl_area_ptr), "r"(loc) \
|
||||
: "memory", "eax")
|
||||
#else
|
||||
#define INC_AFL_AREA(loc) afl_area_ptr[loc]++
|
||||
#endif
|
||||
|
@ -1,527 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unicorn.h>
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "afl-common.h"
|
||||
|
||||
/* We use one additional file descriptor to relay "needs translation"
|
||||
or "child done" messages between the child and the fork server. */
|
||||
|
||||
#define FF16 (0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
/* Copied from aflpp/types.h to talk to forkserver */
|
||||
#define FS_OPT_ENABLED 0x80000001
|
||||
#define FS_OPT_SHDMEM_FUZZ 0x01000000
|
||||
|
||||
/**
|
||||
* The correct fds for reading and writing pipes
|
||||
*/
|
||||
|
||||
#define _R(pipe) ((pipe)[0])
|
||||
#define _W(pipe) ((pipe)[1])
|
||||
|
||||
/* Function declarations. */
|
||||
|
||||
static void afl_setup(struct uc_struct*);
|
||||
static inline uc_afl_ret afl_forkserver(CPUState*);
|
||||
static int afl_find_wifsignaled_id(void);
|
||||
|
||||
static enum afl_child_ret afl_handle_child_requests(CPUState*);
|
||||
static void afl_request_tsl(CPUState *cpu, target_ulong, target_ulong, uint64_t, uint32_t);
|
||||
static uc_afl_ret afl_request_next(struct uc_struct* uc, bool found_crash);
|
||||
|
||||
// static TranslationBlock* tb_find_slow(CPUArchState*, target_ulong, target_ulong, uint64_t);
|
||||
|
||||
/* Data structure passed around by the translate handlers: */
|
||||
|
||||
struct afl_tsl {
|
||||
|
||||
target_ulong pc;
|
||||
target_ulong cs_base;
|
||||
uint64_t flags;
|
||||
uint32_t cf_mask;
|
||||
#if defined(TARGET_MIPS)
|
||||
target_ulong hflags;
|
||||
target_ulong btarget;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/* Current state, as forwarded from forkserver child to parent */
|
||||
|
||||
enum afl_child_ret {
|
||||
|
||||
// Persistent
|
||||
AFL_CHILD_NEXT,
|
||||
// Crash discovered but still alive in persistent mode
|
||||
AFL_CHILD_FOUND_CRASH,
|
||||
// Read again, one afl_tsl struct.
|
||||
AFL_CHILD_TSL_REQUEST,
|
||||
// Child no longer there. Read status code.
|
||||
AFL_CHILD_EXITED,
|
||||
|
||||
};
|
||||
|
||||
static int wifsignaled;
|
||||
|
||||
/*************************
|
||||
* ACTUAL IMPLEMENTATION *
|
||||
*************************/
|
||||
|
||||
/* Set up SHM region and initialize other stuff. */
|
||||
|
||||
static void afl_setup(struct uc_struct* uc) {
|
||||
|
||||
char *id_str = getenv(SHM_ENV_VAR);
|
||||
char *inst_r = getenv("AFL_INST_RATIO");
|
||||
|
||||
// A value we can use to tell AFL our persistent mode found a crash
|
||||
wifsignaled = afl_find_wifsignaled_id();
|
||||
|
||||
int shm_id;
|
||||
|
||||
if (inst_r) {
|
||||
|
||||
unsigned int r;
|
||||
|
||||
r = atoi(inst_r);
|
||||
|
||||
if (r > 100) r = 100;
|
||||
if (!r) r = 1;
|
||||
|
||||
uc->afl_inst_rms = MAP_SIZE * r / 100;
|
||||
|
||||
} else {
|
||||
|
||||
uc->afl_inst_rms = MAP_SIZE;
|
||||
|
||||
}
|
||||
|
||||
if (id_str) {
|
||||
|
||||
shm_id = atoi(id_str);
|
||||
uc->afl_area_ptr = shmat(shm_id, NULL, 0);
|
||||
uc->afl_prev_loc = 0;
|
||||
uc->afl_area_ptr[0] = 1;
|
||||
|
||||
if (uc->afl_area_ptr == (void*)-1) exit(1);
|
||||
|
||||
}
|
||||
|
||||
/* Maintain for compatibility */
|
||||
if (getenv("AFL_QEMU_COMPCOV")) { uc->afl_compcov_level = 1; }
|
||||
if (getenv("AFL_COMPCOV_LEVEL")) {
|
||||
|
||||
uc->afl_compcov_level = atoi(getenv("AFL_COMPCOV_LEVEL"));
|
||||
|
||||
}
|
||||
#if defined(AFL_DEBUG)
|
||||
if (uc->afl_compcov_level) {
|
||||
printf("[d] USING AFL_COMPCOV_LEVEL %d\n", uc->afl_compcov_level);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// Some dirty hack to come up with a valid statuscode that AFL will just accept.
|
||||
|
||||
static int afl_find_wifsignaled_id(void) {
|
||||
|
||||
int ret = 0; // A faux status code that AFL will accept as signaled/crashed. 1 on linux.
|
||||
while (!(WIFSIGNALED(ret))) ret++;
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] wifsignaled is %d (WIFSIGNALED(x)=%d)\n", ret, WIFSIGNALED(ret));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* Fork server logic, invoked by calling uc_afl_forkserver_start.
|
||||
Roughly follows https://github.com/vanhauser-thc/AFLplusplus/blob/c83e8e1e6255374b085292ba8673efdca7388d76/llvm_mode/afl-llvm-rt.o.c#L130
|
||||
*/
|
||||
|
||||
static inline uc_afl_ret afl_forkserver(CPUState* cpu) {
|
||||
|
||||
unsigned char tmp[4] = {0};
|
||||
pid_t child_pid;
|
||||
enum afl_child_ret child_ret = AFL_CHILD_EXITED;
|
||||
bool first_round = true;
|
||||
u32 status = 0;
|
||||
|
||||
if (!cpu->uc->afl_area_ptr) return UC_AFL_RET_NO_AFL;
|
||||
|
||||
if (cpu->uc->afl_testcase_ptr) {
|
||||
/* Parent supports testcases via shared map - and the user wants to use it. Tell AFL. */
|
||||
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
|
||||
}
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) return UC_AFL_RET_NO_AFL;
|
||||
|
||||
/* afl tells us in an extra message if it accepted this option or not */
|
||||
if (cpu->uc->afl_testcase_ptr && getenv(SHM_FUZZ_ENV_VAR)) {
|
||||
if (read(FORKSRV_FD, &status, 4) != 4) {
|
||||
fprintf(stderr, "[!] AFL parent exited before forkserver was up\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
if (status != (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
||||
fprintf(stderr, "[!] Unexpected response from AFL++ on forkserver setup\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
} else {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] AFL++ sharedmap fuzzing not supported/SHM_FUZZ_ENV_VAR not set\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Entering forkserver loop\n");
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
|
||||
uint32_t was_killed;
|
||||
int status;
|
||||
|
||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) return UC_AFL_RET_FINISHED;
|
||||
|
||||
/* If we stopped the child in persistent mode, but there was a race
|
||||
condition and afl-fuzz already issued SIGKILL, write off the old
|
||||
process. */
|
||||
|
||||
if ((child_ret != AFL_CHILD_EXITED) && was_killed) {
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Child was killed by AFL in the meantime.\n");
|
||||
#endif
|
||||
|
||||
child_ret = AFL_CHILD_EXITED;
|
||||
if (waitpid(child_pid, &status, 0) < 0) {
|
||||
perror("[!] Error waiting for child!");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (child_ret == AFL_CHILD_EXITED) {
|
||||
|
||||
/* Child dead. Establish new a channel with child to grab translation commands.
|
||||
We'll read from _R(afl_child_pipe), child will write to _W(afl_child_pipe). */
|
||||
|
||||
/* close the read fd of previous round. */
|
||||
|
||||
if (_R(cpu->uc->afl_child_pipe)) {
|
||||
close(_R(cpu->uc->afl_child_pipe));
|
||||
close(_W(cpu->uc->afl_parent_pipe));
|
||||
}
|
||||
|
||||
if (pipe(cpu->uc->afl_child_pipe)) {
|
||||
perror("[!] Error creating pipe to child");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
if (pipe(cpu->uc->afl_parent_pipe)) {
|
||||
perror("[!] Error creating pipe to parent");
|
||||
close(_R(cpu->uc->afl_child_pipe));
|
||||
close(_W(cpu->uc->afl_child_pipe));
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
/* Create a clone of our process. */
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
perror("[!] Could not fork! ");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
/* In child process: close fds, resume execution. */
|
||||
|
||||
if (!child_pid) { // New child
|
||||
|
||||
signal(SIGCHLD, old_sigchld_handler);
|
||||
// FORKSRV_FD is for communication with AFL, we don't need it in the child.
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
close(_R(cpu->uc->afl_child_pipe));
|
||||
close(_W(cpu->uc->afl_parent_pipe));
|
||||
cpu->uc->afl_child_request_next = afl_request_next;
|
||||
|
||||
memset(cpu->uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
MEM_BARRIER(); // Make very sure everything has been written to the map at this point
|
||||
|
||||
if (!first_round) {
|
||||
|
||||
// For persistent mode: Clear the map manually after forks.
|
||||
memset(cpu->uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
|
||||
} else {
|
||||
// For persistent mode: Clear the map manually after forks.
|
||||
//memset(env->uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
|
||||
first_round = false;
|
||||
}
|
||||
|
||||
cpu->uc->afl_prev_loc = 0;
|
||||
// Tell AFL we're alive
|
||||
cpu->uc->afl_area_ptr[0] = 1;
|
||||
|
||||
return UC_AFL_RET_CHILD;
|
||||
|
||||
} else { // parent for new child
|
||||
|
||||
/* If we don't close this in parent, we don't get notified on afl_child_pipe once child is gone. */
|
||||
|
||||
close(_W(cpu->uc->afl_child_pipe));
|
||||
close(_R(cpu->uc->afl_parent_pipe));
|
||||
|
||||
}
|
||||
|
||||
} else { // parent, in persistent mode
|
||||
|
||||
/* Special handling for persistent mode: if the child is alive but
|
||||
currently stopped, simply restart it with a write to afl_parent_pipe.
|
||||
In case we fuzz using shared map, use this method to forward the size
|
||||
of the current testcase to the child without cost. */
|
||||
|
||||
if (write(_W(cpu->uc->afl_parent_pipe), tmp, 4) != 4) {
|
||||
|
||||
fprintf(stderr,"[!] Child died when we tried to resume it\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* In parent process: write PID to AFL. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
|
||||
return UC_AFL_RET_FINISHED;
|
||||
}
|
||||
|
||||
/* Collect translation requests until child finishes a run or dies */
|
||||
|
||||
child_ret = afl_handle_child_requests(cpu);
|
||||
|
||||
if (child_ret == AFL_CHILD_NEXT) {
|
||||
|
||||
/* Child asks for next in persistent mode */
|
||||
|
||||
status = 0;
|
||||
|
||||
} else if (child_ret == AFL_CHILD_FOUND_CRASH) {
|
||||
|
||||
/* WIFSIGNALED(wifsignaled) == 1 -> tells AFL the child crashed (even though it's still alive for persistent mode) */
|
||||
|
||||
status = wifsignaled;
|
||||
|
||||
} else if (child_ret == AFL_CHILD_EXITED) {
|
||||
|
||||
/* If child exited, get and relay exit status to parent through waitpid. */
|
||||
|
||||
if (waitpid(child_pid, &status, 0) < 0) {
|
||||
|
||||
// Zombie Child could not be collected. Scary!
|
||||
perror("[!] The child's exit code could not be determined. ");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Relay wait status to AFL pipe, then loop back. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) return UC_AFL_RET_FINISHED;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This code is invoked whenever Unicorn decides that it doesn't have a
|
||||
translation of a particular block and needs to compute it. When this happens,
|
||||
we tell the parent to mirror the operation, so that the next fork() has a
|
||||
cached copy. */
|
||||
|
||||
static inline void afl_request_tsl(CPUState *cpu, target_ulong pc, target_ulong cb, uint64_t flags, uint32_t cf_mask) {
|
||||
|
||||
/* Dual use: if this func is not set, we're not a child process */
|
||||
|
||||
struct uc_struct* uc = cpu->uc;
|
||||
if (uc->afl_child_request_next == NULL) return;
|
||||
enum afl_child_ret tsl_req = AFL_CHILD_TSL_REQUEST;
|
||||
#if defined(TARGET_MIPS)
|
||||
CPUArchState* env = cpu->env_ptr;
|
||||
#endif
|
||||
|
||||
struct afl_tsl t = {
|
||||
.pc = pc,
|
||||
.cs_base = cb,
|
||||
.flags = flags,
|
||||
.cf_mask = cf_mask,
|
||||
#if defined(TARGET_MIPS)
|
||||
.hflags = env->hflags,
|
||||
.btarget = env->btarget,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("Requesting tsl, pc=0x%llx, cb=0x%llx, flags=0x%llx\n", (unsigned long long) pc, (unsigned long long) cb, (unsigned long long) flags);
|
||||
#endif
|
||||
|
||||
// We write tsl requests in two steps but that's fine since cache requests are not very common over the time of fuzzing.
|
||||
|
||||
if ((write(_W(uc->afl_child_pipe), &tsl_req, sizeof(enum afl_child_ret)) != sizeof(enum afl_child_ret))
|
||||
|| write(_W(uc->afl_child_pipe), &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) {
|
||||
|
||||
fprintf(stderr, "Error writing to child pipe. Parent dead?\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This code is invoked whenever the child decides that it is done with one fuzz-case. */
|
||||
|
||||
static uc_afl_ret afl_request_next(struct uc_struct* uc, bool crash_found) {
|
||||
|
||||
enum afl_child_ret msg = crash_found? AFL_CHILD_FOUND_CRASH : AFL_CHILD_NEXT;
|
||||
char tmp[4];
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] request next. crash found: %s\n", crash_found ? "true": "false");
|
||||
#endif
|
||||
|
||||
MEM_BARRIER(); // Make very sure everything has been written to the map at this point
|
||||
|
||||
if (write(_W(uc->afl_child_pipe), &msg, sizeof(msg)) != sizeof(msg)) {
|
||||
|
||||
fprintf(stderr, "[!] Error writing to parent pipe. Parent dead?\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
// Once the parent has written something, the next persistent loop starts.
|
||||
// The parent itself will wait for AFL to signal the new testcases is available.
|
||||
// This blocks until the next testcase is ready.
|
||||
if (read(_R(uc->afl_parent_pipe), tmp, 4) != 4) {
|
||||
|
||||
fprintf(stderr, "[!] Error reading from parent pipe. Parent dead?\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
|
||||
}
|
||||
|
||||
/* For shared map fuzzing, the forkserver parent forwards the size of the current testcase. */
|
||||
memset(uc->afl_area_ptr, 0, MAP_SIZE);
|
||||
MEM_BARRIER(); // Also make sure nothing read before this point.
|
||||
|
||||
// Start with a clean slate.
|
||||
uc->afl_prev_loc = 0;
|
||||
uc->afl_area_ptr[0] = 1;
|
||||
|
||||
return UC_AFL_RET_CHILD;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* This is the reading side of afl_child_pipe. It will handle persistent mode and (tsl) cache requests.
|
||||
Since timeouts are handled by afl-fuzz simply killing the child, we can just wait until the pipe breaks.
|
||||
For persistent mode, we will also receive child responses over this chanel.
|
||||
For persistent mode, if child is still alive, this will return if the child crashed or not */
|
||||
|
||||
static enum afl_child_ret afl_handle_child_requests(CPUState* cpu) {
|
||||
|
||||
enum afl_child_ret child_msg;
|
||||
struct afl_tsl t;
|
||||
#if defined(TARGET_MIPS)
|
||||
CPUArchState* env = cpu->env_ptr;
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Broken pipe means it's time to return to the fork server routine. */
|
||||
|
||||
if (read(_R(cpu->uc->afl_child_pipe), &child_msg, sizeof(enum afl_child_ret)) != sizeof(enum afl_child_ret)) return AFL_CHILD_EXITED; // child is dead.
|
||||
|
||||
if (child_msg == AFL_CHILD_NEXT || child_msg == AFL_CHILD_FOUND_CRASH) {
|
||||
|
||||
// Forward if child found a crash or not, for persistent mode.
|
||||
return child_msg;
|
||||
|
||||
} else if (child_msg == AFL_CHILD_TSL_REQUEST) {
|
||||
|
||||
// TODO: Add option to disable cache for self-modifying code? // Ignore code that has not been loaded?
|
||||
|
||||
// Child will send a tsl request next, that we have to cache.
|
||||
if (read(_R(cpu->uc->afl_child_pipe), &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) return AFL_CHILD_EXITED; // child is dead.
|
||||
|
||||
// Prepare hflags for delay slot
|
||||
#if defined(TARGET_MIPS)
|
||||
struct afl_tsl tmp;
|
||||
tmp.hflags = env->hflags;
|
||||
tmp.btarget = env->btarget;
|
||||
env->hflags = t.hflags;
|
||||
env->btarget = t.btarget;
|
||||
#endif
|
||||
|
||||
// Cache.
|
||||
//tb_find_slow(env, t.pc, t.cs_base, t.flags);
|
||||
|
||||
// TODO: Caching! tb = tb_find(cpu, last_tb, tb_exit, t.cflags);
|
||||
|
||||
// Restore hflags
|
||||
#if defined(TARGET_MIPS)
|
||||
env->hflags = tmp.hflags;
|
||||
env->btarget = tmp.btarget;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
|
||||
fprintf(stderr, "[!] Unexpected response by child! %d. Please report this as bug for unicornafl.\n"
|
||||
" Expected one of {AFL_CHILD_NEXT: %d, AFL_CHILD_FOUND_CRASH: %d, AFL_CHILD_TSL_REQUEST: %d}.\n",
|
||||
child_msg, AFL_CHILD_NEXT, AFL_CHILD_FOUND_CRASH, AFL_CHILD_TSL_REQUEST);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
|
||||
/* These are executed on code generation. Execution is in afl-unicorn-tcg-runtime-inl.h */
|
||||
/* Roughly afl_gen_maybe_log -> gen_afl_maybe_log -> emit HELPER(afl_maybe_log) -> call afl_maybe_log */
|
||||
|
||||
static void afl_gen_maybe_log(TCGContext *s, uint64_t cur_loc) {
|
||||
|
||||
if (!s->uc->afl_area_ptr) return;
|
||||
|
||||
/* "Hash" */
|
||||
|
||||
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
|
||||
cur_loc &= MAP_SIZE - 7;
|
||||
|
||||
/* Implement probabilistic instrumentation by looking at scrambled block
|
||||
address. This keeps the instrumented locations stable across runs. */
|
||||
|
||||
if (cur_loc >= s->uc->afl_inst_rms) return;
|
||||
|
||||
gen_afl_maybe_log(s, cur_loc);
|
||||
|
||||
}
|
||||
|
||||
// Currently only arm32 and x86. We undefine it for others to silence unused func compiler warnings.
|
||||
#if defined(ARCH_HAS_COMPCOV)
|
||||
static void afl_gen_compcov(TCGContext *s, uint64_t cur_loc, TCGv arg1,
|
||||
TCGv arg2, TCGMemOp ot, int is_imm) {
|
||||
|
||||
if (!s->uc->afl_compcov_level || !s->uc->afl_area_ptr) return;
|
||||
|
||||
if (!is_imm && s->uc->afl_compcov_level < 2) return;
|
||||
|
||||
cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
|
||||
cur_loc &= MAP_SIZE - 7;
|
||||
|
||||
if (cur_loc >= s->uc->afl_inst_rms) return;
|
||||
|
||||
switch (ot) {
|
||||
|
||||
case MO_64: gen_afl_compcov_log_64(s, cur_loc, (TCGv_i64)arg1, (TCGv_i64)arg2); break;
|
||||
case MO_32: gen_afl_compcov_log_32(s, cur_loc, (TCGv_i32)arg1, (TCGv_i32)arg2); break;
|
||||
case MO_16: gen_afl_compcov_log_16(s, cur_loc, (TCGv_i32)arg1, (TCGv_i32)arg2); break;
|
||||
default: return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
static inline void gen_afl_maybe_log(TCGContext *tcg_ctx, uint64_t cur_loc) {
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
gen_helper_afl_maybe_log(tcg_ctx, tuc, tcur_loc);
|
||||
|
||||
}
|
||||
|
||||
static inline void gen_afl_compcov_log_16(TCGContext *tcg_ctx, uint64_t cur_loc,
|
||||
TCGv_i32 arg1, TCGv_i32 arg2) {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Emitting 16 bit COMPCOV instrumentation for loc 0x%lx\n", cur_loc);
|
||||
#endif
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
gen_helper_afl_compcov_log_16(tcg_ctx, tuc, tcur_loc, arg1, arg2);
|
||||
|
||||
}
|
||||
|
||||
static inline void gen_afl_compcov_log_32(TCGContext *tcg_ctx, uint64_t cur_loc,
|
||||
TCGv_i32 arg1, TCGv_i32 arg2) {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Emitting 32 bit COMPCOV instrumentation for loc 0x%lux\n", cur_loc);
|
||||
#endif
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
gen_helper_afl_compcov_log_32(tcg_ctx, tuc, tcur_loc, arg1, arg2);
|
||||
|
||||
}
|
||||
|
||||
static inline void gen_afl_compcov_log_64(TCGContext *tcg_ctx, uint64_t cur_loc,
|
||||
TCGv_i64 arg1, TCGv_i64 arg2) {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] Emitting 64 bit COMPCOV instrumentation for loc 0x%lux\n", cur_loc);
|
||||
#endif
|
||||
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, tcg_ctx->uc);
|
||||
TCGv_i64 tcur_loc = tcg_const_i64(tcg_ctx, cur_loc);
|
||||
gen_helper_afl_compcov_log_64(tcg_ctx, tuc, tcur_loc, arg1, arg2);
|
||||
|
||||
}
|
||||
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - unicorn instrumentation
|
||||
----------------------------------------------
|
||||
|
||||
Originally written by Andrew Griffiths <agriffiths@google.com> and
|
||||
Michal Zalewski
|
||||
|
||||
Adapted for afl-unicorn by Dominik Maier <mail@dmnk.co>
|
||||
|
||||
CompareCoverage and NeverZero counters by Andrea Fioraldi
|
||||
<andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
This code is a shim patched into the separately-distributed source
|
||||
code of Unicorn 1.0.1. It leverages the built-in QEMU tracing functionality
|
||||
to implement AFL-style instrumentation and to take care of the remaining
|
||||
parts of the AFL fork server logic.
|
||||
|
||||
The resulting libunicorn binary is essentially a standalone instrumentation
|
||||
tool; for an example of how to leverage it for other purposes, you can
|
||||
have a look at afl-showmap.c.
|
||||
|
||||
*/
|
||||
|
||||
#include "uc_priv.h"
|
||||
#include "afl-common.h"
|
||||
|
||||
/* This is the main instrumentation function, patched in at translate.
|
||||
cur_loc has already been shifted in afl-unicorn-translate-inl.h at this point.
|
||||
Also this helper will only be emitted if running instrumented. */
|
||||
|
||||
void HELPER(afl_maybe_log)(void* uc_ptr, uint64_t cur_loc) {
|
||||
|
||||
struct uc_struct* uc = (struct uc_struct*) uc_ptr;
|
||||
u8* afl_area_ptr = uc->afl_area_ptr; // Don't remove, it's used by INC_AFL_AREA implicitly;
|
||||
|
||||
register uintptr_t afl_idx = cur_loc ^ uc->afl_prev_loc;
|
||||
|
||||
INC_AFL_AREA(afl_idx);
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] At loc 0x%llx: prev: 0x%llx, afl_idx: %lu, map[afl_idx]: %d\n", (unsigned long long) cur_loc, (unsigned long long) uc->afl_prev_loc, (unsigned long) afl_idx, afl_area_ptr[afl_idx]);
|
||||
#endif
|
||||
|
||||
uc->afl_prev_loc = cur_loc >> 1;
|
||||
|
||||
}
|
||||
|
||||
void HELPER(afl_compcov_log_16)(void* uc_ptr, uint64_t cur_loc, uint32_t arg1,
|
||||
uint32_t arg2) {
|
||||
|
||||
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
|
||||
|
||||
if ((arg1 & 0xff00) == (arg2 & 0xff00)) { INC_AFL_AREA(cur_loc); }
|
||||
|
||||
}
|
||||
|
||||
void HELPER(afl_compcov_log_32)(void* uc_ptr, uint64_t cur_loc, uint32_t arg1,
|
||||
uint32_t arg2) {
|
||||
|
||||
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
|
||||
|
||||
if ((arg1 & 0xff000000) == (arg2 & 0xff000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 2);
|
||||
if ((arg1 & 0xff0000) == (arg2 & 0xff0000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 1);
|
||||
if ((arg1 & 0xff00) == (arg2 & 0xff00)) { INC_AFL_AREA(cur_loc); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HELPER(afl_compcov_log_64)(void* uc_ptr, uint64_t cur_loc, uint64_t arg1,
|
||||
uint64_t arg2) {
|
||||
|
||||
u8* afl_area_ptr = ((struct uc_struct*)uc_ptr)->afl_area_ptr;
|
||||
|
||||
if ((arg1 & 0xff00000000000000) == (arg2 & 0xff00000000000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 6);
|
||||
if ((arg1 & 0xff000000000000) == (arg2 & 0xff000000000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 5);
|
||||
if ((arg1 & 0xff0000000000) == (arg2 & 0xff0000000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 4);
|
||||
if ((arg1 & 0xff00000000) == (arg2 & 0xff00000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 3);
|
||||
if ((arg1 & 0xff000000) == (arg2 & 0xff000000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 2);
|
||||
if ((arg1 & 0xff0000) == (arg2 & 0xff0000)) {
|
||||
|
||||
INC_AFL_AREA(cur_loc + 1);
|
||||
if ((arg1 & 0xff00) == (arg2 & 0xff00)) { INC_AFL_AREA(cur_loc); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,510 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - vaguely configurable bits
|
||||
------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2021 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_CONFIG_H
|
||||
#define _HAVE_CONFIG_H
|
||||
|
||||
/* Version string: */
|
||||
|
||||
// c = release, a = volatile github dev, e = experimental branch
|
||||
#define VERSION "++3.15a"
|
||||
|
||||
/******************************************************
|
||||
* *
|
||||
* Settings that may be of interest to power users: *
|
||||
* *
|
||||
******************************************************/
|
||||
|
||||
/* Default shared memory map size. Most targets just need a coverage map
|
||||
between 20-250kb. Plus there is an auto-detection feature in afl-fuzz.
|
||||
However if a target has problematic constructors and init arrays then
|
||||
this can fail. Hence afl-fuzz deploys a larger default map. The largest
|
||||
map seen so far is the xlsx fuzzer for libreoffice which is 5MB.
|
||||
At runtime this value can be overriden via AFL_MAP_SIZE.
|
||||
Default: 8MB (defined in bytes) */
|
||||
#define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024)
|
||||
|
||||
/* Default file permission umode when creating files (default: 0600) */
|
||||
#define DEFAULT_PERMISSION 0600
|
||||
|
||||
/* CMPLOG/REDQUEEN TUNING
|
||||
*
|
||||
* Here you can modify tuning and solving options for CMPLOG.
|
||||
* Note that these are run-time options for afl-fuzz, no target
|
||||
* recompilation required.
|
||||
*
|
||||
*/
|
||||
|
||||
/* if TRANSFORM is enabled with '-l T', this additionally enables base64
|
||||
encoding/decoding */
|
||||
// #define CMPLOG_SOLVE_TRANSFORM_BASE64
|
||||
|
||||
/* If a redqueen pass finds more than one solution, try to combine them? */
|
||||
#define CMPLOG_COMBINE
|
||||
|
||||
/* Minimum % of the corpus to perform cmplog on. Default: 10% */
|
||||
#define CMPLOG_CORPUS_PERCENT 5U
|
||||
|
||||
/* Number of potential positions from which we decide if cmplog becomes
|
||||
useless, default 8096 */
|
||||
#define CMPLOG_POSITIONS_MAX (12 * 1024)
|
||||
|
||||
/* Maximum allowed fails per CMP value. Default: 128 */
|
||||
#define CMPLOG_FAIL_MAX 96
|
||||
|
||||
/* -------------------------------------*/
|
||||
/* Now non-cmplog configuration options */
|
||||
/* -------------------------------------*/
|
||||
|
||||
/* If a persistent target keeps state and found crashes are not reproducable
|
||||
then enable this option and set the AFL_PERSISTENT_RECORD env variable
|
||||
to a number. These number of testcases prior and including the crash case
|
||||
will be kept and written to the crash/ directory as RECORD:... files.
|
||||
Note that every crash will be written, not only unique ones! */
|
||||
|
||||
//#define AFL_PERSISTENT_RECORD
|
||||
|
||||
/* console output colors: There are three ways to configure its behavior
|
||||
* 1. default: colored outputs fixed on: defined USE_COLOR && defined
|
||||
* ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect
|
||||
* 2. defined USE_COLOR && !defined ALWAYS_COLORED
|
||||
* -> depending on env var AFL_NO_COLOR=1 colors can be switched off
|
||||
* at run-time. Default is to use colors.
|
||||
* 3. colored outputs fixed off: !defined USE_COLOR
|
||||
* The env var. AFL_NO_COLOR will have no effect
|
||||
*/
|
||||
|
||||
/* Comment out to disable terminal colors (note that this makes afl-analyze
|
||||
a lot less nice): */
|
||||
|
||||
#define USE_COLOR
|
||||
|
||||
#ifdef USE_COLOR
|
||||
/* Comment in to always enable terminal colors */
|
||||
/* Comment out to enable runtime controlled terminal colors via AFL_NO_COLOR
|
||||
*/
|
||||
#define ALWAYS_COLORED 1
|
||||
#endif
|
||||
|
||||
/* StatsD config
|
||||
Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment
|
||||
variable.
|
||||
*/
|
||||
#define STATSD_UPDATE_SEC 1
|
||||
#define STATSD_DEFAULT_PORT 8125
|
||||
#define STATSD_DEFAULT_HOST "127.0.0.1"
|
||||
|
||||
/* If you want to have the original afl internal memory corruption checks.
|
||||
Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */
|
||||
|
||||
// #define _WANT_ORIGINAL_AFL_ALLOC
|
||||
|
||||
/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */
|
||||
|
||||
#ifndef ANDROID_DISABLE_FANCY // Fancy boxes are ugly from adb
|
||||
#define FANCY_BOXES
|
||||
#endif
|
||||
|
||||
/* Default timeout for fuzzed code (milliseconds). This is the upper bound,
|
||||
also used for detecting hangs; the actual value is auto-scaled: */
|
||||
|
||||
#define EXEC_TIMEOUT 1000U
|
||||
|
||||
/* Timeout rounding factor when auto-scaling (milliseconds): */
|
||||
|
||||
#define EXEC_TM_ROUND 20U
|
||||
|
||||
/* 64bit arch MACRO */
|
||||
#if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__))
|
||||
#define WORD_SIZE_64 1
|
||||
#endif
|
||||
|
||||
/* Default memory limit for child process (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT 0U
|
||||
|
||||
/* Default memory limit when running in QEMU mode (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT_QEMU 0U
|
||||
|
||||
/* Default memory limit when running in Unicorn mode (MB) 0 = disabled : */
|
||||
|
||||
#define MEM_LIMIT_UNICORN 0U
|
||||
|
||||
/* Number of calibration cycles per every new test case (and for test
|
||||
cases that show variable behavior): */
|
||||
|
||||
#define CAL_CYCLES 8U
|
||||
#define CAL_CYCLES_LONG 20U
|
||||
|
||||
/* Number of subsequent timeouts before abandoning an input file: */
|
||||
|
||||
#define TMOUT_LIMIT 250U
|
||||
|
||||
/* Maximum number of unique hangs or crashes to record: */
|
||||
|
||||
#define KEEP_UNIQUE_HANG 500U
|
||||
#define KEEP_UNIQUE_CRASH 10000U
|
||||
|
||||
/* Baseline number of random tweaks during a single 'havoc' stage: */
|
||||
|
||||
#define HAVOC_CYCLES 256U
|
||||
#define HAVOC_CYCLES_INIT 1024U
|
||||
|
||||
/* Maximum multiplier for the above (should be a power of two, beware
|
||||
of 32-bit int overflows): */
|
||||
|
||||
#define HAVOC_MAX_MULT 64U
|
||||
#define HAVOC_MAX_MULT_MOPT 64U
|
||||
|
||||
/* Absolute minimum number of havoc cycles (after all adjustments): */
|
||||
|
||||
#define HAVOC_MIN 12U
|
||||
|
||||
/* Power Schedule Divisor */
|
||||
#define POWER_BETA 1U
|
||||
#define MAX_FACTOR (POWER_BETA * 32)
|
||||
|
||||
/* Maximum stacking for havoc-stage tweaks. The actual value is calculated
|
||||
like this:
|
||||
|
||||
n = random between 1 and HAVOC_STACK_POW2
|
||||
stacking = 2^n
|
||||
|
||||
In other words, the default (n = 4) produces 2, 4, 8, 16
|
||||
stacked tweaks: */
|
||||
|
||||
#define HAVOC_STACK_POW2 4U
|
||||
|
||||
/* Caps on block sizes for cloning and deletion operations. Each of these
|
||||
ranges has a 33% probability of getting picked, except for the first
|
||||
two cycles where smaller blocks are favored: */
|
||||
|
||||
#define HAVOC_BLK_SMALL 32U
|
||||
#define HAVOC_BLK_MEDIUM 128U
|
||||
#define HAVOC_BLK_LARGE 1500U
|
||||
|
||||
/* Extra-large blocks, selected very rarely (<5% of the time): */
|
||||
|
||||
#define HAVOC_BLK_XL 32768U
|
||||
|
||||
/* Probabilities of skipping non-favored entries in the queue, expressed as
|
||||
percentages: */
|
||||
|
||||
#define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */
|
||||
#define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */
|
||||
#define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */
|
||||
|
||||
/* Splicing cycle count: */
|
||||
|
||||
#define SPLICE_CYCLES 15
|
||||
|
||||
/* Nominal per-splice havoc cycle length: */
|
||||
|
||||
#define SPLICE_HAVOC 32
|
||||
|
||||
/* Maximum offset for integer addition / subtraction stages: */
|
||||
|
||||
#define ARITH_MAX 35
|
||||
|
||||
/* Limits for the test case trimmer. The absolute minimum chunk size; and
|
||||
the starting and ending divisors for chopping up the input file: */
|
||||
|
||||
#define TRIM_MIN_BYTES 4
|
||||
#define TRIM_START_STEPS 16
|
||||
#define TRIM_END_STEPS 1024
|
||||
|
||||
/* Maximum size of input file, in bytes (keep under 100MB, default 1MB):
|
||||
(note that if this value is changed, several areas in afl-cc.c, afl-fuzz.c
|
||||
and afl-fuzz-state.c have to be changed as well! */
|
||||
|
||||
#define MAX_FILE (1 * 1024 * 1024L)
|
||||
|
||||
/* The same, for the test case minimizer: */
|
||||
|
||||
#define TMIN_MAX_FILE (10 * 1024 * 1024L)
|
||||
|
||||
/* Block normalization steps for afl-tmin: */
|
||||
|
||||
#define TMIN_SET_MIN_SIZE 4
|
||||
#define TMIN_SET_STEPS 128
|
||||
|
||||
/* Maximum dictionary token size (-x), in bytes: */
|
||||
|
||||
#define MAX_DICT_FILE 128
|
||||
|
||||
/* Length limits for auto-detected dictionary tokens: */
|
||||
|
||||
#define MIN_AUTO_EXTRA 3
|
||||
#define MAX_AUTO_EXTRA 32
|
||||
|
||||
/* Maximum number of user-specified dictionary tokens to use in deterministic
|
||||
steps; past this point, the "extras/user" step will be still carried out,
|
||||
but with proportionally lower odds: */
|
||||
|
||||
#define MAX_DET_EXTRAS 256
|
||||
|
||||
/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing
|
||||
(first value), and to keep in memory as candidates. The latter should be much
|
||||
higher than the former. */
|
||||
|
||||
#define USE_AUTO_EXTRAS 128
|
||||
#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64)
|
||||
|
||||
/* Scaling factor for the effector map used to skip some of the more
|
||||
expensive deterministic steps. The actual divisor is set to
|
||||
2^EFF_MAP_SCALE2 bytes: */
|
||||
|
||||
#define EFF_MAP_SCALE2 3
|
||||
|
||||
/* Minimum input file length at which the effector logic kicks in: */
|
||||
|
||||
#define EFF_MIN_LEN 128
|
||||
|
||||
/* Maximum effector density past which everything is just fuzzed
|
||||
unconditionally (%): */
|
||||
|
||||
#define EFF_MAX_PERC 90
|
||||
|
||||
/* UI refresh frequency (Hz): */
|
||||
|
||||
#define UI_TARGET_HZ 5
|
||||
|
||||
/* Fuzzer stats file and plot update intervals (sec): */
|
||||
|
||||
#define STATS_UPDATE_SEC 60
|
||||
#define PLOT_UPDATE_SEC 5
|
||||
|
||||
/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */
|
||||
|
||||
#define AVG_SMOOTHING 16
|
||||
|
||||
/* Sync interval (every n havoc cycles): */
|
||||
|
||||
#define SYNC_INTERVAL 8
|
||||
|
||||
/* Sync time (minimum time between syncing in ms, time is halfed for -M main
|
||||
nodes) - default is 30 minutes: */
|
||||
|
||||
#define SYNC_TIME (30 * 60 * 1000)
|
||||
|
||||
/* Output directory reuse grace period (minutes): */
|
||||
|
||||
#define OUTPUT_GRACE 25
|
||||
|
||||
/* Uncomment to use simple file names (id_NNNNNN): */
|
||||
|
||||
// #define SIMPLE_FILES
|
||||
|
||||
/* List of interesting values to use in fuzzing. */
|
||||
|
||||
#define INTERESTING_8 \
|
||||
-128, /* Overflow signed 8-bit when decremented */ \
|
||||
-1, /* */ \
|
||||
0, /* */ \
|
||||
1, /* */ \
|
||||
16, /* One-off with common buffer size */ \
|
||||
32, /* One-off with common buffer size */ \
|
||||
64, /* One-off with common buffer size */ \
|
||||
100, /* One-off with common buffer size */ \
|
||||
127 /* Overflow signed 8-bit when incremented */
|
||||
|
||||
#define INTERESTING_8_LEN 9
|
||||
|
||||
#define INTERESTING_16 \
|
||||
-32768, /* Overflow signed 16-bit when decremented */ \
|
||||
-129, /* Overflow signed 8-bit */ \
|
||||
128, /* Overflow signed 8-bit */ \
|
||||
255, /* Overflow unsig 8-bit when incremented */ \
|
||||
256, /* Overflow unsig 8-bit */ \
|
||||
512, /* One-off with common buffer size */ \
|
||||
1000, /* One-off with common buffer size */ \
|
||||
1024, /* One-off with common buffer size */ \
|
||||
4096, /* One-off with common buffer size */ \
|
||||
32767 /* Overflow signed 16-bit when incremented */
|
||||
|
||||
#define INTERESTING_16_LEN 10
|
||||
|
||||
#define INTERESTING_32 \
|
||||
-2147483648LL, /* Overflow signed 32-bit when decremented */ \
|
||||
-100663046, /* Large negative number (endian-agnostic) */ \
|
||||
-32769, /* Overflow signed 16-bit */ \
|
||||
32768, /* Overflow signed 16-bit */ \
|
||||
65535, /* Overflow unsig 16-bit when incremented */ \
|
||||
65536, /* Overflow unsig 16 bit */ \
|
||||
100663045, /* Large positive number (endian-agnostic) */ \
|
||||
2147483647 /* Overflow signed 32-bit when incremented */
|
||||
|
||||
#define INTERESTING_32_LEN 8
|
||||
|
||||
/***********************************************************
|
||||
* *
|
||||
* Really exotic stuff you probably don't want to touch: *
|
||||
* *
|
||||
***********************************************************/
|
||||
|
||||
/* Call count interval between reseeding the libc PRNG from /dev/urandom: */
|
||||
|
||||
#define RESEED_RNG 100000
|
||||
|
||||
/* The default maximum testcase cache size in MB, 0 = disable.
|
||||
A value between 50 and 250 is a good default value. Note that the
|
||||
number of entries will be auto assigned if not specified via the
|
||||
AFL_TESTCACHE_ENTRIES env variable */
|
||||
|
||||
#define TESTCASE_CACHE_SIZE 50
|
||||
|
||||
/* Maximum line length passed from GCC to 'as' and used for parsing
|
||||
configuration files: */
|
||||
|
||||
#define MAX_LINE 8192
|
||||
|
||||
/* Environment variable used to pass SHM ID to the called program. */
|
||||
|
||||
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||
|
||||
/* Environment variable used to pass SHM FUZZ ID to the called program. */
|
||||
|
||||
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
||||
|
||||
/* Other less interesting, internal-only variables. */
|
||||
|
||||
#define CLANG_ENV_VAR "__AFL_CLANG_MODE"
|
||||
#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK"
|
||||
#define PERSIST_ENV_VAR "__AFL_PERSISTENT"
|
||||
#define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV"
|
||||
|
||||
/* In-code signatures for deferred and persistent mode. */
|
||||
|
||||
#define PERSIST_SIG "##SIG_AFL_PERSISTENT##"
|
||||
#define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##"
|
||||
|
||||
/* Distinctive bitmap signature used to indicate failed execution: */
|
||||
|
||||
#define EXEC_FAIL_SIG 0xfee1dead
|
||||
|
||||
/* Distinctive exit code used to indicate MSAN trip condition: */
|
||||
|
||||
#define MSAN_ERROR 86
|
||||
|
||||
/* Distinctive exit code used to indicate LSAN trip condition: */
|
||||
|
||||
#define LSAN_ERROR 23
|
||||
|
||||
/* Designated file descriptors for forkserver commands (the application will
|
||||
use FORKSRV_FD and FORKSRV_FD + 1): */
|
||||
|
||||
#define FORKSRV_FD 198
|
||||
|
||||
/* Fork server init timeout multiplier: we'll wait the user-selected
|
||||
timeout plus this much for the fork server to spin up. */
|
||||
|
||||
#define FORK_WAIT_MULT 10
|
||||
|
||||
/* Calibration timeout adjustments, to be a bit more generous when resuming
|
||||
fuzzing sessions or trying to calibrate already-added internal finds.
|
||||
The first value is a percentage, the other is in milliseconds: */
|
||||
|
||||
#define CAL_TMOUT_PERC 125
|
||||
#define CAL_TMOUT_ADD 50
|
||||
|
||||
/* Number of chances to calibrate a case before giving up: */
|
||||
|
||||
#define CAL_CHANCES 3
|
||||
|
||||
/* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than
|
||||
2; you probably want to keep it under 18 or so for performance reasons
|
||||
(adjusting AFL_INST_RATIO when compiling is probably a better way to solve
|
||||
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 (1U << MAP_SIZE_POW2)
|
||||
|
||||
/* Maximum allocator request size (keep well under INT_MAX): */
|
||||
|
||||
#define MAX_ALLOC 0x40000000
|
||||
|
||||
/* A made-up hashing seed: */
|
||||
|
||||
#define HASH_CONST 0xa5b35705
|
||||
|
||||
/* Constants for afl-gotcpu to control busy loop timing: */
|
||||
|
||||
#define CTEST_TARGET_MS 5000
|
||||
#define CTEST_CORE_TRG_MS 1000
|
||||
#define CTEST_BUSY_CYCLES (10 * 1000 * 1000)
|
||||
|
||||
/* Enable NeverZero counters in QEMU mode */
|
||||
|
||||
#define AFL_QEMU_NOT_ZERO
|
||||
|
||||
/* AFL RedQueen */
|
||||
|
||||
#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
|
||||
|
||||
/* CPU Affinity lockfile env var */
|
||||
|
||||
#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
|
||||
|
||||
/* Uncomment this to use inferior block-coverage-based instrumentation. Note
|
||||
that you need to recompile the target binary for this to have any effect: */
|
||||
|
||||
// #define COVERAGE_ONLY
|
||||
|
||||
/* Uncomment this to ignore hit counts and output just one bit per tuple.
|
||||
As with the previous setting, you will need to recompile the target
|
||||
binary: */
|
||||
|
||||
// #define SKIP_COUNTS
|
||||
|
||||
/* Uncomment this to use instrumentation data to record newly discovered paths,
|
||||
but do not use them as seeds for fuzzing. This is useful for conveniently
|
||||
measuring coverage that could be attained by a "dumb" fuzzing algorithm: */
|
||||
|
||||
// #define IGNORE_FINDS
|
||||
|
||||
/* Text mutations */
|
||||
|
||||
/* Minimum length of a queue input to be evaluated for "is_ascii"? */
|
||||
|
||||
#define AFL_TXT_MIN_LEN 12
|
||||
|
||||
/* What is the minimum percentage of ascii characters present to be classifed
|
||||
as "is_ascii"? */
|
||||
|
||||
#define AFL_TXT_MIN_PERCENT 94
|
||||
|
||||
/* How often to perform ASCII mutations 0 = disable, 1-8 are good values */
|
||||
|
||||
#define AFL_TXT_BIAS 6
|
||||
|
||||
/* Maximum length of a string to tamper with */
|
||||
|
||||
#define AFL_TXT_STRING_MAX_LEN 1024
|
||||
|
||||
/* Maximum mutations on a string */
|
||||
|
||||
#define AFL_TXT_STRING_MAX_MUTATIONS 6
|
||||
|
||||
#endif /* ! _HAVE_CONFIG_H */
|
||||
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
american fuzzy lop++ - type definitions and minor macros
|
||||
--------------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_TYPES_H
|
||||
#define _HAVE_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
#ifdef WORD_SIZE_64
|
||||
typedef unsigned __int128 uint128_t;
|
||||
typedef uint128_t u128;
|
||||
#endif
|
||||
|
||||
/* Extended forkserver option values */
|
||||
|
||||
/* Reporting errors */
|
||||
#define FS_OPT_ERROR 0xf800008f
|
||||
#define FS_OPT_GET_ERROR(x) ((x & 0x00ffff00) >> 8)
|
||||
#define FS_OPT_SET_ERROR(x) ((x & 0x0000ffff) << 8)
|
||||
#define FS_ERROR_MAP_SIZE 1
|
||||
#define FS_ERROR_MAP_ADDR 2
|
||||
#define FS_ERROR_SHM_OPEN 4
|
||||
#define FS_ERROR_SHMAT 8
|
||||
#define FS_ERROR_MMAP 16
|
||||
|
||||
/* Reporting options */
|
||||
#define FS_OPT_ENABLED 0x80000001
|
||||
#define FS_OPT_MAPSIZE 0x40000000
|
||||
#define FS_OPT_SNAPSHOT 0x20000000
|
||||
#define FS_OPT_AUTODICT 0x10000000
|
||||
#define FS_OPT_SHDMEM_FUZZ 0x01000000
|
||||
#define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
|
||||
// FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
|
||||
#define FS_OPT_MAX_MAPSIZE ((0x00fffffeU >> 1) + 1)
|
||||
#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
|
||||
#define FS_OPT_SET_MAPSIZE(x) \
|
||||
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
||||
|
||||
typedef unsigned long long u64;
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
#ifdef WORD_SIZE_64
|
||||
typedef __int128 int128_t;
|
||||
typedef int128_t s128;
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a < _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
|
||||
#define MAX(a, b) \
|
||||
({ \
|
||||
\
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a > _b ? _a : _b; \
|
||||
\
|
||||
})
|
||||
|
||||
#endif /* !MIN */
|
||||
|
||||
#define SWAP16(_x) \
|
||||
({ \
|
||||
\
|
||||
u16 _ret = (_x); \
|
||||
(u16)((_ret << 8) | (_ret >> 8)); \
|
||||
\
|
||||
})
|
||||
|
||||
#define SWAP32(_x) \
|
||||
({ \
|
||||
\
|
||||
u32 _ret = (_x); \
|
||||
(u32)((_ret << 24) | (_ret >> 24) | ((_ret << 8) & 0x00FF0000) | \
|
||||
((_ret >> 8) & 0x0000FF00)); \
|
||||
\
|
||||
})
|
||||
|
||||
#define SWAP64(_x) \
|
||||
({ \
|
||||
\
|
||||
u64 _ret = (_x); \
|
||||
_ret = \
|
||||
(_ret & 0x00000000FFFFFFFF) << 32 | (_ret & 0xFFFFFFFF00000000) >> 32; \
|
||||
_ret = \
|
||||
(_ret & 0x0000FFFF0000FFFF) << 16 | (_ret & 0xFFFF0000FFFF0000) >> 16; \
|
||||
_ret = \
|
||||
(_ret & 0x00FF00FF00FF00FF) << 8 | (_ret & 0xFF00FF00FF00FF00) >> 8; \
|
||||
_ret; \
|
||||
\
|
||||
})
|
||||
|
||||
// It is impossible to define 128 bit constants, so ...
|
||||
#ifdef WORD_SIZE_64
|
||||
#define SWAPN(_x, _l) \
|
||||
({ \
|
||||
\
|
||||
u128 _res = (_x), _ret; \
|
||||
char *d = (char *)&_ret, *s = (char *)&_res; \
|
||||
int i; \
|
||||
for (i = 0; i < 16; i++) \
|
||||
d[15 - i] = s[i]; \
|
||||
u32 sr = 128U - ((_l) << 3U); \
|
||||
(_ret >>= sr); \
|
||||
(u128) _ret; \
|
||||
\
|
||||
})
|
||||
#endif
|
||||
|
||||
#define SWAPNN(_x, _y, _l) \
|
||||
({ \
|
||||
\
|
||||
char *d = (char *)(_x), *s = (char *)(_y); \
|
||||
u32 i, l = (_l)-1; \
|
||||
for (i = 0; i <= l; i++) \
|
||||
d[l - i] = s[i]; \
|
||||
\
|
||||
})
|
||||
|
||||
#ifdef AFL_LLVM_PASS
|
||||
#if defined(__linux__) || !defined(__ANDROID__)
|
||||
#define AFL_SR(s) (srandom(s))
|
||||
#define AFL_R(x) (random() % (x))
|
||||
#else
|
||||
#define AFL_SR(s) ((void)s)
|
||||
#define AFL_R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#else
|
||||
#if defined(__linux__) || !defined(__ANDROID__)
|
||||
#define SR(s) (srandom(s))
|
||||
#define R(x) (random() % (x))
|
||||
#else
|
||||
#define SR(s) ((void)s)
|
||||
#define R(x) (arc4random_uniform(x))
|
||||
#endif
|
||||
#endif /* ^AFL_LLVM_PASS */
|
||||
|
||||
#define STRINGIFY_INTERNAL(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY_INTERNAL(x)
|
||||
|
||||
#define MEM_BARRIER() __asm__ volatile("" ::: "memory")
|
||||
|
||||
#if __GNUC__ < 6
|
||||
#ifndef likely
|
||||
#define likely(_x) (_x)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(_x) (_x)
|
||||
#endif
|
||||
#else
|
||||
#ifndef likely
|
||||
#define likely(_x) __builtin_expect(!!(_x), 1)
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(_x) __builtin_expect(!!(_x), 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* ! _HAVE_TYPES_H */
|
||||
|
@ -15,31 +15,14 @@
|
||||
|
||||
// These are masks of supported modes for each cpu/arch.
|
||||
// They should be updated when changes are made to the uc_mode enum typedef.
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
#define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN|UC_MODE_MCLASS \
|
||||
|UC_MODE_ARM926|UC_MODE_ARM946|UC_MODE_ARM1176|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_PPC_MASK (UC_MODE_PPC32|UC_MODE_PPC64|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN|UC_MODE_AFL)
|
||||
#define UC_MODE_RISCV_MASK (UC_MODE_RISCV32|UC_MODE_RISCV64|UC_MODE_LITTLE_ENDIAN|UC_MODE_AFL)
|
||||
#else
|
||||
#define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN|UC_MODE_MCLASS \
|
||||
|UC_MODE_ARM926|UC_MODE_ARM946|UC_MODE_ARM1176|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN)
|
||||
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN)
|
||||
#define UC_MODE_PPC_MASK (UC_MODE_PPC32|UC_MODE_PPC64|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_RISCV_MASK (UC_MODE_RISCV32|UC_MODE_RISCV64|UC_MODE_LITTLE_ENDIAN)
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define UCLOG(...) fprintf(stderr, __VA_ARGS__)
|
||||
#else
|
||||
#define UCLOG(...)
|
||||
#endif
|
||||
|
||||
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
@ -112,20 +95,6 @@ typedef void (*uc_softfloat_initialize)(void);
|
||||
// tcg flush softmmu tlb
|
||||
typedef void (*uc_tcg_flush_tlb)(struct uc_struct *uc);
|
||||
|
||||
typedef enum uc_afl_ret {
|
||||
UC_AFL_RET_ERROR = 0, // Something went horribly wrong in the parent
|
||||
UC_AFL_RET_CHILD, // Fork worked. we are a child
|
||||
UC_AFL_RET_NO_AFL, // No AFL, no need to fork.
|
||||
UC_AFL_RET_CALLED_TWICE, // AFL has already been started before.
|
||||
UC_AFL_RET_FINISHED, // We forked before but now AFL is gone (parent)
|
||||
} uc_afl_ret;
|
||||
|
||||
// we use this as shortcut deep inside uc_afl for the arch specific uc_afl_next(uc, bool)
|
||||
typedef uc_afl_ret(*uc_afl_ret_uc_bool_t)(struct uc_struct*, bool);
|
||||
|
||||
// afl_forkserver_start
|
||||
typedef int (*uc_afl_forkserver_t)(struct uc_struct*);
|
||||
|
||||
struct hook {
|
||||
int type; // UC_HOOK_*
|
||||
int insn; // instruction for HOOK_INSN
|
||||
@ -313,23 +282,6 @@ struct uc_struct {
|
||||
bool first_tb; // is this the first Translation-Block ever generated since uc_emu_start()?
|
||||
struct list saved_contexts; // The contexts saved by this uc_struct.
|
||||
bool no_exit_request; // Disable check_exit_request temporarily. A workaround to treat the IT block as a whole block.
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
bool afl;
|
||||
uc_afl_forkserver_t afl_forkserver_start; // function to start afl forkserver
|
||||
uc_afl_ret_uc_bool_t afl_child_request_next; // function from child to ask for new testcase (if in child)
|
||||
int afl_child_pipe[2]; // pipe used to send information from child process to forkserver
|
||||
int afl_parent_pipe[2]; // pipe used to send information from parent to child in forkserver
|
||||
uint8_t *afl_area_ptr; // map, shared with afl, to report coverage feedback etc. during runs
|
||||
uint64_t afl_prev_loc; // previous location
|
||||
int afl_compcov_level; // how much compcove we want
|
||||
unsigned int afl_inst_rms;
|
||||
size_t exit_count; // number of exits set in afl_fuzz or afl_forkserver
|
||||
uint64_t *exits; // pointer to the actual exits
|
||||
char *afl_testcase_ptr; // map, shared with afl, to get testcases delivered from for each run
|
||||
uint32_t *afl_testcase_size_p; // size of the current testcase, if using shared map fuzzing with afl.
|
||||
void *afl_data_ptr; // Pointer for various (bindings-related) uses.
|
||||
#endif
|
||||
};
|
||||
|
||||
// Metadata stub for the variable-size cpu context used with uc_context_*()
|
||||
|
@ -105,7 +105,6 @@ typedef enum uc_arch {
|
||||
typedef enum uc_mode {
|
||||
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||
UC_MODE_AFL = 1 << 29,
|
||||
|
||||
// arm / arm64
|
||||
UC_MODE_ARM = 0, // ARM mode
|
||||
@ -172,10 +171,6 @@ typedef enum uc_err {
|
||||
UC_ERR_HOOK_EXIST, // hook for this event already existed
|
||||
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
|
||||
UC_ERR_EXCEPTION, // Unhandled CPU exception
|
||||
UC_ERR_AFL_RET_ERROR, // Something went horribly wrong in the parent
|
||||
UC_ERR_AFL_RET_NO_AFL, // No AFL, no need to fork.
|
||||
UC_ERR_AFL_RET_CALLED_TWICE, // AFL has already been started before.
|
||||
UC_ERR_AFL_RET_FINISHED, // We forked before but now AFL is gone (parent)
|
||||
} uc_err;
|
||||
|
||||
|
||||
@ -573,82 +568,6 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
|
||||
|
||||
/* Callback function called for each input from AFL.
|
||||
This function is mandatory.
|
||||
It's purpose is to place the input at the right place in unicorn.
|
||||
@uc: Unicorn instance
|
||||
@input: The current input we're working on. Place this somewhere in unicorn's memory now.
|
||||
@input_len: length of the input
|
||||
@persistent_round: which round we are currently crashing in, if using persistent mode.
|
||||
@data: Data pointer passed to uc_afl_fuzz(...).
|
||||
@return:
|
||||
If you return is true, all is well. Fuzzing starts.
|
||||
If you return false, the input is rejected; we will continue with the next input.
|
||||
*/
|
||||
typedef bool (*uc_afl_cb_place_input_t)(uc_engine *uc, char *input, size_t input_len, uint32_t persistent_round, void *data);
|
||||
|
||||
/* Callback function called after a non-UC_ERR_OK returncode was returned by Unicorn.
|
||||
This function is not mandatory (pass NULL).
|
||||
@uc: Unicorn instance
|
||||
@unicorn_result: The error state returned by the current testcase
|
||||
@input: The current input we're workin with.
|
||||
@input_len: length of the input
|
||||
@persistent_round: which round we are currently crashing in, if using persistent mode.
|
||||
@data: Data pointer passed to uc_afl_fuzz(...).
|
||||
@Return:
|
||||
If you return false, the crash is considered invalid and not reported to AFL.
|
||||
If return is true, the crash is reported.
|
||||
-> The child will die and the forkserver will spawn a new child.
|
||||
*/
|
||||
typedef bool (*uc_afl_cb_validate_crash_t)(uc_engine *uc, uc_err unicorn_result, char *input, int input_len, int persistent_round, void *data);
|
||||
|
||||
/*
|
||||
The main fuzzer.
|
||||
Starts uc_afl_forkserver(), then beginns a persistent loop.
|
||||
Reads input, calls the place_input callback, emulates, uc_afl_next(...), repeats.
|
||||
If unicorn errors out, will call the validate_crash_callback, if set.
|
||||
Will only retrun in the parent after the whole fuzz thing has been finished and afl died.
|
||||
The child processes never return from here.
|
||||
|
||||
Note: This API is not supported on Windows.
|
||||
|
||||
@uc: handle returned by uc_open()
|
||||
@input_file: filename/path to the (AFL) inputfile. Usualy suplied on the commandline.
|
||||
@place_input_callback: Callback function that will be called before each test runs.
|
||||
This function needs to write the input from afl to the correct position on the unicorn object.
|
||||
@exits: address list of exits where fuzzing should stop (len == exit_count)
|
||||
@exit_count: number of exits where fuzzing should stop
|
||||
@validate_crash_callback: Optional callback (if not needed, pass NULL), that determines
|
||||
if a non-OK uc_err is an actual error. If false is returned, the test-case will not crash.
|
||||
@always_validate: If false, validate_crash_callback will only be called for crashes.
|
||||
@persistent_iters:
|
||||
The amount of loop iterations in persistent mode before restarteing with a new forked child.
|
||||
If your target cannot be fuzzed using persistent mode (global state changes a lot),
|
||||
set persistent_iters = 1 for the normal fork-server experience.
|
||||
Else, the default is usually around 1000.
|
||||
If your target is super stable (and unicorn is, too - not sure about that one),
|
||||
you may pass persistent_iter = 0 for that an infinite fuzz loop.
|
||||
@data: Your very own data pointer. This will passed into every callback.
|
||||
@return uc_afl_ret:
|
||||
>UC_AFL_RET_ERROR = 0, // Something went horribly wrong in the parent
|
||||
>UC_AFL_RET_CHILD, // Can never happen, the child will loop happily or exit.
|
||||
>UC_AFL_RET_NO_AFL, // No AFL, we ran the testacse once and are done.
|
||||
>UC_AFL_RET_FINISHED, // We forked before but now AFL is gone (parent)
|
||||
>> We're retuning after having fuzzed. We may now pack our bags and exit.
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_afl_fuzz(
|
||||
uc_engine *uc,
|
||||
char* input_file,
|
||||
uc_afl_cb_place_input_t place_input_callback,
|
||||
uint64_t *exits,
|
||||
size_t exit_count,
|
||||
uc_afl_cb_validate_crash_t validate_crash_callback,
|
||||
bool always_validate,
|
||||
uint32_t persistent_iters,
|
||||
void *data
|
||||
);
|
||||
|
||||
/*
|
||||
Stop emulation (which was started by uc_emu_start() API.
|
||||
This is typically called from callback functions registered via tracing APIs.
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _aarch64
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_aarch64
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_aarch64
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_aarch64
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_aarch64
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_aarch64
|
||||
#define use_idiv_instructions use_idiv_instructions_aarch64
|
||||
#define arm_arch arm_arch_aarch64
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_aarch64
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _aarch64eb
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_aarch64eb
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_aarch64eb
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_aarch64eb
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_aarch64eb
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_aarch64eb
|
||||
#define use_idiv_instructions use_idiv_instructions_aarch64eb
|
||||
#define arm_arch arm_arch_aarch64eb
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_aarch64eb
|
||||
|
@ -29,10 +29,6 @@
|
||||
#include "sysemu/cpus.h"
|
||||
#include "uc_priv.h"
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
#include "afl/afl-cpu-inl.h"
|
||||
#endif
|
||||
|
||||
/* -icount align implementation. */
|
||||
|
||||
typedef struct SyncClocks {
|
||||
@ -258,11 +254,6 @@ static inline TranslationBlock *tb_find(CPUState *cpu,
|
||||
/* We add the TB in the virtual pc hash table for the fast lookup */
|
||||
cpu->tb_jmp_cache[tb_jmp_cache_hash_func(cpu->uc, pc)] = tb;
|
||||
}
|
||||
|
||||
#if defined(UNICORN_HAS_AFL)
|
||||
afl_request_tsl(cpu, pc, cs_base, flags, cf_mask);
|
||||
#endif
|
||||
|
||||
/* We don't take care of direct jumps when address mapping changes in
|
||||
* system emulation. So it's not safe to make a direct jump to a TB
|
||||
* spanning two pages because the mapping for the second page can change.
|
||||
@ -588,31 +579,3 @@ int cpu_exec(struct uc_struct *uc, CPUState *cpu)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
int afl_forkserver_start(struct uc_struct *uc)
|
||||
{
|
||||
// Not sure if we need all of this setup foo.
|
||||
CPUState *cpu = uc->cpu;
|
||||
if (!cpu->created) {
|
||||
cpu->created = true;
|
||||
cpu->halted = 0;
|
||||
qemu_init_vcpu(cpu);
|
||||
|
||||
}
|
||||
cpu_resume(cpu);
|
||||
|
||||
if (uc->count_hook != 0) {
|
||||
uc_hook_del(uc, uc->count_hook);
|
||||
uc->count_hook = 0;
|
||||
}
|
||||
|
||||
uc->quit_request = false;
|
||||
uc->cpu = cpu;
|
||||
smp_mb();
|
||||
|
||||
// Would love to not have the extra step in cpus.c, but it doesn't work otherwise(?)
|
||||
afl_setup(uc);
|
||||
return afl_forkserver(cpu);
|
||||
}
|
||||
#endif
|
@ -32,10 +32,6 @@
|
||||
|
||||
#include <uc_priv.h>
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
#include "afl/afl-tcg-runtime-inl.h"
|
||||
#endif
|
||||
|
||||
/* 32-bit helpers */
|
||||
|
||||
int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2)
|
||||
|
@ -259,10 +259,3 @@ DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
|
||||
|
||||
#if defined(UNICORN_HAS_AFL)
|
||||
DEF_HELPER_FLAGS_2(afl_maybe_log, 0, void, ptr, i64)
|
||||
DEF_HELPER_FLAGS_4(afl_compcov_log_16, 0, void, ptr, i64, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(afl_compcov_log_32, 0, void, ptr, i64, i32, i32)
|
||||
DEF_HELPER_FLAGS_4(afl_compcov_log_64, 0, void, ptr, i64, i64, i64)
|
||||
#endif
|
@ -17,11 +17,6 @@
|
||||
|
||||
#include <uc_priv.h>
|
||||
|
||||
#if defined(UNICORN_HAS_AFL)
|
||||
#undef ARCH_HAS_COMPCOV
|
||||
#include "afl/afl-cpu-translate-inl.h"
|
||||
#endif
|
||||
|
||||
/* Pairs with tcg_clear_temp_count.
|
||||
To be called by #TranslatorOps.{translate_insn,tb_stop} if
|
||||
(1) the target is sufficiently clean to support reporting,
|
||||
@ -61,29 +56,6 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
/* Reset the temp count so that we can identify leaks */
|
||||
tcg_clear_temp_count();
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = cpu->uc->exits;
|
||||
size_t exit_count = cpu->uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (tb->pc == exits[i]) {
|
||||
// This should catch that instruction is at the end
|
||||
// and generate appropriate halting code.
|
||||
gen_tb_start(tcg_ctx, db->tb);
|
||||
ops->tb_start(db, cpu);
|
||||
db->num_insns++;
|
||||
ops->insn_start(db, cpu);
|
||||
ops->translate_insn(db, cpu);
|
||||
goto _end_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Unicorn: early check to see if the address of this block is
|
||||
* the "run until" address. */
|
||||
if (tb->pc == cpu->uc->addr_end) {
|
||||
@ -109,10 +81,6 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
|
||||
|
||||
// tcg_dump_ops(tcg_ctx, false, "translator loop");
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
afl_gen_maybe_log(tcg_ctx, tb->pc);
|
||||
#endif
|
||||
|
||||
/* Start translating. */
|
||||
gen_tb_start(tcg_ctx, db->tb);
|
||||
// tcg_dump_ops(tcg_ctx, false, "tb start");
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _arm
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_arm
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_arm
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_arm
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_arm
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_arm
|
||||
#define use_idiv_instructions use_idiv_instructions_arm
|
||||
#define arm_arch arm_arch_arm
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_arm
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _armeb
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_armeb
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_armeb
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_armeb
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_armeb
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_armeb
|
||||
#define use_idiv_instructions use_idiv_instructions_armeb
|
||||
#define arm_arch arm_arch_armeb
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_armeb
|
||||
|
@ -29,10 +29,6 @@
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
#include "afl/afl-tcg-op-inl.h"
|
||||
#endif
|
||||
|
||||
static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t type, void *uc, uint64_t pc)
|
||||
{
|
||||
TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size);
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _m68k
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_m68k
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_m68k
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_m68k
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_m68k
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_m68k
|
||||
#define use_idiv_instructions use_idiv_instructions_m68k
|
||||
#define arm_arch arm_arch_m68k
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_m68k
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mips
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_mips
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_mips
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_mips
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_mips
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_mips
|
||||
#define use_idiv_instructions use_idiv_instructions_mips
|
||||
#define arm_arch arm_arch_mips
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_mips
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mips64
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_mips64
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_mips64
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_mips64
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_mips64
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_mips64
|
||||
#define use_idiv_instructions use_idiv_instructions_mips64
|
||||
#define arm_arch arm_arch_mips64
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_mips64
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mips64el
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_mips64el
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_mips64el
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_mips64el
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_mips64el
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_mips64el
|
||||
#define use_idiv_instructions use_idiv_instructions_mips64el
|
||||
#define arm_arch arm_arch_mips64el
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_mips64el
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _mipsel
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_mipsel
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_mipsel
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_mipsel
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_mipsel
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_mipsel
|
||||
#define use_idiv_instructions use_idiv_instructions_mipsel
|
||||
#define arm_arch arm_arch_mipsel
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_mipsel
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _ppc
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_ppc
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_ppc
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_ppc
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_ppc
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_ppc
|
||||
#define use_idiv_instructions use_idiv_instructions_ppc
|
||||
#define arm_arch arm_arch_ppc
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_ppc
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _ppc64
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_ppc64
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_ppc64
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_ppc64
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_ppc64
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_ppc64
|
||||
#define use_idiv_instructions use_idiv_instructions_ppc64
|
||||
#define arm_arch arm_arch_ppc64
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_ppc64
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _riscv32
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_riscv32
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_riscv32
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_riscv32
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_riscv32
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_riscv32
|
||||
#define use_idiv_instructions use_idiv_instructions_riscv32
|
||||
#define arm_arch arm_arch_riscv32
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_riscv32
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _riscv64
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_riscv64
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_riscv64
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_riscv64
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_riscv64
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_riscv64
|
||||
#define use_idiv_instructions use_idiv_instructions_riscv64
|
||||
#define arm_arch arm_arch_riscv64
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_riscv64
|
||||
|
@ -194,23 +194,6 @@ void resume_all_vcpus(struct uc_struct* uc)
|
||||
tb_flush_jmp_cache(cpu, uc->addr_end);
|
||||
}
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = uc->exits;
|
||||
size_t exit_count = uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
TranslationBlock *tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(uc, exits[i])];
|
||||
if (tb) {
|
||||
qht_remove(&uc->tcg_ctx->tb_ctx.htable, tb, tb->hash);
|
||||
tb_flush_jmp_cache(cpu, uc->exits[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
cpu->created = false;
|
||||
}
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _sparc
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_sparc
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_sparc
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_sparc
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_sparc
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_sparc
|
||||
#define use_idiv_instructions use_idiv_instructions_sparc
|
||||
#define arm_arch arm_arch_sparc
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_sparc
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _sparc64
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_sparc64
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_sparc64
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_sparc64
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_sparc64
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_sparc64
|
||||
#define use_idiv_instructions use_idiv_instructions_sparc64
|
||||
#define arm_arch arm_arch_sparc64
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_sparc64
|
||||
|
@ -37,11 +37,6 @@
|
||||
#include "qemu/atomic128.h"
|
||||
#include "kvm-consts.h"
|
||||
|
||||
#if defined(UNICORN_HAS_AFL)
|
||||
#undef ARCH_HAS_COMPCOV
|
||||
#include "afl/afl-cpu-translate-inl.h"
|
||||
#endif
|
||||
|
||||
static const char *regnames[] = {
|
||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
||||
@ -14641,23 +14636,6 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
CPUARMState *env = cpu->env_ptr;
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (dc->uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = dc->uc->exits;
|
||||
size_t exit_count = dc->uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (dcbase->pc_next == exits[i]) {
|
||||
dcbase->is_jmp = DISAS_WFI;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (dcbase->pc_next == dc->uc->addr_end) {
|
||||
// imitate WFI instruction to halt emulation
|
||||
|
@ -11420,23 +11420,6 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (dc->uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = dc->uc->exits;
|
||||
size_t exit_count = dc->uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (dcbase->pc_next == exits[i]) {
|
||||
dcbase->is_jmp = DISAS_WFI;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (dcbase->pc_next == dc->uc->addr_end) {
|
||||
// imitate WFI instruction to halt emulation
|
||||
|
@ -4764,27 +4764,6 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
|
||||
|
||||
s->uc = env->uc;
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (s->uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = s->uc->exits;
|
||||
size_t exit_count = s->uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (s->pc == exits[i]) {
|
||||
// imitate the HLT instruction
|
||||
gen_update_cc_op(s);
|
||||
gen_jmp_im(s, pc_start - s->cs_base);
|
||||
gen_helper_hlt(tcg_ctx, tcg_ctx->cpu_env, tcg_const_i32(tcg_ctx, s->pc - pc_start));
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
return s->pc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (s->pc == s->uc->addr_end) {
|
||||
// imitate the HLT instruction
|
||||
|
@ -6325,23 +6325,6 @@ static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
CPUM68KState *env = cpu->env_ptr;
|
||||
uint16_t insn;
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = uc->exits;
|
||||
size_t exit_count = uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (dc->pc == exits[i]) {
|
||||
gen_exception(dc, dc->pc, EXCP_HLT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (dc->pc == uc->addr_end) {
|
||||
gen_exception(dc, dc->pc, EXCP_HLT);
|
||||
|
@ -30931,24 +30931,6 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
|
||||
|
||||
is_slot = ctx->hflags & MIPS_HFLAG_BMASK;
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = uc->exits;
|
||||
size_t exit_count = uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (ctx->base.pc_next == exits[i]) {// raise a special interrupt to quit
|
||||
gen_helper_wait(tcg_ctx, tcg_ctx->cpu_env);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (ctx->base.pc_next == uc->addr_end) {
|
||||
// raise a special interrupt to quit
|
||||
|
@ -7625,23 +7625,6 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
|
||||
LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n",
|
||||
ctx->base.pc_next, ctx->mem_idx, (int)msr_ir);
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = uc->exits;
|
||||
size_t exit_count = uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (ctx->base.pc_next == exits[i]) {
|
||||
gen_wait(ctx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (ctx->base.pc_next == uc->addr_end) {
|
||||
gen_wait(ctx);
|
||||
|
@ -849,24 +849,6 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
TCGOp *tcg_op, *prev_op = NULL;
|
||||
bool insn_hook = false;
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = ctx->uc->exits;
|
||||
size_t exit_count = ctx->uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (ctx->base.pc_next == exits[i]) {
|
||||
// Unicorn: We have to exit current execution here.
|
||||
dcbase->is_jmp = DISAS_UC_EXIT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (ctx->base.pc_next == ctx->uc->addr_end) {
|
||||
// Unicorn: We have to exit current execution here.
|
||||
|
@ -5950,26 +5950,6 @@ static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
|
||||
CPUSPARCState *env = cs->env_ptr;
|
||||
unsigned int insn;
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
if (uc->afl) {
|
||||
// UNICORN-AFL supports (and needs) multiple exits.
|
||||
uint64_t *exits = uc->exits;
|
||||
size_t exit_count = uc->exit_count;
|
||||
if (exit_count) {
|
||||
size_t i;
|
||||
for (i = 0; i < exit_count; i++) {
|
||||
if (dc->pc == exits[i]) {
|
||||
#ifndef TARGET_SPARC64
|
||||
gen_helper_power_down(tcg_ctx, tcg_ctx->cpu_env);
|
||||
#endif
|
||||
dcbase->is_jmp = DISAS_NORETURN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unicorn: end address tells us to stop emulation
|
||||
if (dc->pc == uc->addr_end) {
|
||||
#ifndef TARGET_SPARC64
|
||||
|
@ -1655,7 +1655,7 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
def = &s->tcg_op_defs[c];
|
||||
if (c == INDEX_op_insn_start) {
|
||||
nb_oargs = 0;
|
||||
UCLOG(" ----");
|
||||
printf(" ----");
|
||||
|
||||
for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
|
||||
target_ulong a;
|
||||
@ -1664,7 +1664,7 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
#else
|
||||
a = op->args[i];
|
||||
#endif
|
||||
UCLOG(" " TARGET_FMT_lx, a);
|
||||
printf(" " TARGET_FMT_lx, a);
|
||||
}
|
||||
} else if (c == INDEX_op_call) {
|
||||
/* variable number of arguments */
|
||||
@ -1673,11 +1673,11 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
nb_cargs = def->nb_cargs;
|
||||
|
||||
/* function name, flags, out args */
|
||||
UCLOG(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
|
||||
printf(" %s %s,$0x%" TCG_PRIlx ",$%d", def->name,
|
||||
tcg_find_helper(s, op->args[nb_oargs + nb_iargs]),
|
||||
op->args[nb_oargs + nb_iargs + 1], nb_oargs);
|
||||
for (i = 0; i < nb_oargs; i++) {
|
||||
UCLOG(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
|
||||
printf(",%s", tcg_get_arg_str(s, buf, sizeof(buf),
|
||||
op->args[i]));
|
||||
}
|
||||
for (i = 0; i < nb_iargs; i++) {
|
||||
@ -1686,33 +1686,33 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
if (arg != TCG_CALL_DUMMY_ARG) {
|
||||
t = tcg_get_arg_str(s, buf, sizeof(buf), arg);
|
||||
}
|
||||
UCLOG(",%s", t);
|
||||
printf(",%s", t);
|
||||
}
|
||||
} else {
|
||||
UCLOG(" %s ", def->name);
|
||||
printf(" %s ", def->name);
|
||||
|
||||
nb_oargs = def->nb_oargs;
|
||||
nb_iargs = def->nb_iargs;
|
||||
nb_cargs = def->nb_cargs;
|
||||
|
||||
if (def->flags & TCG_OPF_VECTOR) {
|
||||
UCLOG("v%d,e%d,", 64 << TCGOP_VECL(op),
|
||||
printf("v%d,e%d,", 64 << TCGOP_VECL(op),
|
||||
8 << TCGOP_VECE(op));
|
||||
}
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < nb_oargs; i++) {
|
||||
if (k != 0) {
|
||||
UCLOG(",");
|
||||
printf(",");
|
||||
}
|
||||
UCLOG("%s", tcg_get_arg_str(s, buf, sizeof(buf),
|
||||
printf("%s", tcg_get_arg_str(s, buf, sizeof(buf),
|
||||
op->args[k++]));
|
||||
}
|
||||
for (i = 0; i < nb_iargs; i++) {
|
||||
if (k != 0) {
|
||||
UCLOG(",");
|
||||
printf(",");
|
||||
}
|
||||
UCLOG("%s", tcg_get_arg_str(s, buf, sizeof(buf),
|
||||
printf("%s", tcg_get_arg_str(s, buf, sizeof(buf),
|
||||
op->args[k++]));
|
||||
}
|
||||
switch (c) {
|
||||
@ -1728,9 +1728,9 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
case INDEX_op_cmpsel_vec:
|
||||
if (op->args[k] < ARRAY_SIZE(cond_name)
|
||||
&& cond_name[op->args[k]]) {
|
||||
UCLOG(",%s", cond_name[op->args[k++]]);
|
||||
printf(",%s", cond_name[op->args[k++]]);
|
||||
} else {
|
||||
UCLOG(",$0x%" TCG_PRIlx, op->args[k++]);
|
||||
printf(",$0x%" TCG_PRIlx, op->args[k++]);
|
||||
}
|
||||
i = 1;
|
||||
break;
|
||||
@ -1744,12 +1744,12 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
unsigned ix = get_mmuidx(oi);
|
||||
|
||||
if (op & ~(MO_AMASK | MO_BSWAP | MO_SSIZE)) {
|
||||
UCLOG(",$0x%x,%u", op, ix);
|
||||
printf(",$0x%x,%u", op, ix);
|
||||
} else {
|
||||
const char *s_al, *s_op;
|
||||
s_al = alignment_name[(op & MO_AMASK) >> MO_ASHIFT];
|
||||
s_op = ldst_name[op & (MO_BSWAP | MO_SSIZE)];
|
||||
UCLOG(",%s%s,%u", s_al, s_op, ix);
|
||||
printf(",%s%s,%u", s_al, s_op, ix);
|
||||
}
|
||||
i = 1;
|
||||
}
|
||||
@ -1764,7 +1764,7 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
case INDEX_op_brcond_i32:
|
||||
case INDEX_op_brcond_i64:
|
||||
case INDEX_op_brcond2_i32:
|
||||
UCLOG("%s$L%d", k ? "," : "",
|
||||
printf("%s$L%d", k ? "," : "",
|
||||
arg_label(op->args[k])->id);
|
||||
i++, k++;
|
||||
break;
|
||||
@ -1772,12 +1772,12 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
break;
|
||||
}
|
||||
for (; i < nb_cargs; i++, k++) {
|
||||
UCLOG("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
|
||||
printf("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
|
||||
}
|
||||
if(c == INDEX_op_mov_i64){
|
||||
struct TCGTemp* tp = arg_temp(op->args[1]);
|
||||
if (tp && tp->val_type == TEMP_VAL_MEM){
|
||||
UCLOG(" mem_base=%p ", tp->mem_base);
|
||||
printf(" mem_base=%p ", tp->mem_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1786,19 +1786,19 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
unsigned life = op->life;
|
||||
|
||||
if (life & (SYNC_ARG * 3)) {
|
||||
UCLOG(" sync:");
|
||||
printf(" sync:");
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (life & (SYNC_ARG << i)) {
|
||||
UCLOG(" %d", i);
|
||||
printf(" %d", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
life /= DEAD_ARG;
|
||||
if (life) {
|
||||
UCLOG(" dead:");
|
||||
printf(" dead:");
|
||||
for (i = 0; life; ++i, life >>= 1) {
|
||||
if (life & 1) {
|
||||
UCLOG(" %d", i);
|
||||
printf(" %d", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1809,28 +1809,28 @@ void tcg_dump_op(TCGContext *s, bool have_prefs, TCGOp* op)
|
||||
TCGRegSet set = op->output_pref[i];
|
||||
|
||||
if (i == 0) {
|
||||
UCLOG(" pref=");
|
||||
printf(" pref=");
|
||||
} else {
|
||||
UCLOG(",");
|
||||
printf(",");
|
||||
}
|
||||
if (set == 0) {
|
||||
UCLOG("none");
|
||||
printf("none");
|
||||
} else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
|
||||
UCLOG("all");
|
||||
printf("all");
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
} else if (tcg_regset_single(set)) {
|
||||
TCGReg reg = tcg_regset_first(set);
|
||||
printf("%s", tcg_target_reg_names[reg]);
|
||||
#endif
|
||||
} else if (TCG_TARGET_NB_REGS <= 32) {
|
||||
UCLOG("%#x", (uint32_t)set);
|
||||
printf("%#x", (uint32_t)set);
|
||||
} else {
|
||||
UCLOG("%#" PRIx64, (uint64_t)set);
|
||||
printf("%#" PRIx64, (uint64_t)set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UCLOG("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -1863,16 +1863,16 @@ void tcg_dump_ops(TCGContext *s, bool have_prefs, const char *headline)
|
||||
int insn_idx = 0;
|
||||
int op_idx = 0;
|
||||
|
||||
UCLOG("\n*** %s\n", headline);
|
||||
printf("\n*** %s\n", headline);
|
||||
// tcg_dump_tbs(s, tcg_dump_tb, NULL);
|
||||
|
||||
QTAILQ_FOREACH(op, &s->ops, link) {
|
||||
if (op->opc == INDEX_op_insn_start) {
|
||||
UCLOG("\n insn_idx=%d", insn_idx);
|
||||
printf("\n insn_idx=%d", insn_idx);
|
||||
insn_idx++;
|
||||
op_idx = 0;
|
||||
} else {
|
||||
UCLOG(" %d: ", op_idx);
|
||||
printf(" %d: ", op_idx);
|
||||
}
|
||||
op_idx++;
|
||||
tcg_dump_op(s, have_prefs, op);
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
void vm_start(struct uc_struct*);
|
||||
void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size);
|
||||
int afl_forkserver_start(struct uc_struct*);
|
||||
|
||||
// return true on success, false on failure
|
||||
static inline bool cpu_physical_mem_read(AddressSpace *as, hwaddr addr,
|
||||
@ -107,9 +106,7 @@ static inline void uc_common_init(struct uc_struct* uc)
|
||||
uc->softfloat_initialize = softfloat_init;
|
||||
uc->tcg_flush_tlb = tcg_flush_softmmu_tlb;
|
||||
uc->memory_map_io = memory_map_io;
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
uc->afl_forkserver_start = afl_forkserver_start;
|
||||
#endif
|
||||
|
||||
if (!uc->release)
|
||||
uc->release = release_common;
|
||||
}
|
||||
|
@ -4,11 +4,6 @@
|
||||
#ifndef UNICORN_ARCH_POSTFIX
|
||||
#define UNICORN_ARCH_POSTFIX _x86_64
|
||||
#endif
|
||||
#define afl_forkserver_start afl_forkserver_start_x86_64
|
||||
#define helper_afl_maybe_log helper_afl_maybe_log_x86_64
|
||||
#define helper_afl_compcov_log_16 helper_afl_compcov_log_16_x86_64
|
||||
#define helper_afl_compcov_log_32 helper_afl_compcov_log_32_x86_64
|
||||
#define helper_afl_compcov_log_64 helper_afl_compcov_log_64_x86_64
|
||||
#define use_idiv_instructions use_idiv_instructions_x86_64
|
||||
#define arm_arch arm_arch_x86_64
|
||||
#define tb_target_set_jmp_target tb_target_set_jmp_target_x86_64
|
||||
|
@ -4,11 +4,6 @@ CMD_PATH=$(realpath $0)
|
||||
SOURCE_DIR=$(dirname ${CMD_PATH})
|
||||
|
||||
COMMON_SYMBOLS="
|
||||
afl_forkserver_start \
|
||||
helper_afl_maybe_log \
|
||||
helper_afl_compcov_log_16 \
|
||||
helper_afl_compcov_log_32 \
|
||||
helper_afl_compcov_log_64 \
|
||||
use_idiv_instructions \
|
||||
arm_arch \
|
||||
tb_target_set_jmp_target \
|
||||
|
338
uc.c
338
uc.c
@ -26,17 +26,6 @@
|
||||
|
||||
#include "qemu/include/qemu/queue.h"
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/shm.h>
|
||||
#include "afl/config.h"
|
||||
#include "afl/types.h"
|
||||
#endif
|
||||
|
||||
UNICORN_EXPORT
|
||||
unsigned int uc_version(unsigned int *major, unsigned int *minor)
|
||||
{
|
||||
@ -104,14 +93,6 @@ const char *uc_strerror(uc_err code)
|
||||
return "Insufficient resource (UC_ERR_RESOURCE)";
|
||||
case UC_ERR_EXCEPTION:
|
||||
return "Unhandled CPU exception (UC_ERR_EXCEPTION)";
|
||||
case UC_ERR_AFL_RET_ERROR:
|
||||
return "Something went horribly wrong in the parent (UC_ERR_AFL_RET_ERROR)";
|
||||
case UC_ERR_AFL_RET_NO_AFL:
|
||||
return "No AFL, no need to fork (UC_ERR_AFL_RET_NO_AFL)";
|
||||
case UC_ERR_AFL_RET_CALLED_TWICE:
|
||||
return "AFL has already been started before (UC_ERR_AFL_RET_CALLED_TWICE)";
|
||||
case UC_ERR_AFL_RET_FINISHED:
|
||||
return "We forked before but now parent is gone (UC_ERR_AFL_RET_FINISHED)";
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,11 +143,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
|
||||
if (mode & UC_MODE_AFL) {
|
||||
uc->afl = true;
|
||||
mode &= (~UC_MODE_AFL);
|
||||
}
|
||||
|
||||
/* qemu/exec.c: phys_map_node_reserve() */
|
||||
uc->alloc_hint = 16;
|
||||
uc->errnum = UC_ERR_OK;
|
||||
@ -771,320 +747,6 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||
return uc->invalid_error;
|
||||
}
|
||||
|
||||
#ifdef UNICORN_HAS_AFL
|
||||
static inline uc_afl_ret uc_afl_forkserver_start(uc_engine *uc, uint64_t *exits, size_t exit_count)
|
||||
{
|
||||
/*
|
||||
Why we need exits as parameter to forkserver:
|
||||
In the original unicorn-afl, Unicorn needed to flush the tb cache for every iteration.
|
||||
This is super slow.
|
||||
Problem was, that the original forked server doesn't know about possible future exits.
|
||||
The cached blocks, in the next child, therefore would have no exit set and run forever.
|
||||
Also it's nice to have multiple exits, so let's just do it right.
|
||||
*/
|
||||
|
||||
if (!uc) {
|
||||
fprintf(stderr, "[!] Unicorn Engine passed to uc_afl_fuzz is NULL!\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
if (!exits) {
|
||||
fprintf(stderr, "[!] Nullptr provided for exits.\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
if (!exit_count) {
|
||||
fprintf(stderr, "[!] No exits provided (exit_count was 0).\n");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
if (unlikely(uc->afl_area_ptr)) {
|
||||
#if defined(AFL_DEBUG)
|
||||
fprintf(stderr, "[!] forkserver_start(...) called twice. Already fuzzing!\n");
|
||||
#endif
|
||||
return UC_AFL_RET_CALLED_TWICE; // AFL has already been started before.
|
||||
}
|
||||
|
||||
/* Copy exits to unicorn env buffer */
|
||||
uc->exits = g_realloc(uc->exits, sizeof(exits[0]) * exit_count);
|
||||
if (uc->exits == NULL) {
|
||||
perror("[!] malloc failed when starting forkserver.");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
memcpy(uc->exits, exits, sizeof(exits[0]) * exit_count);
|
||||
uc->exit_count = exit_count;
|
||||
// Set addr_end to make sure unicorn will not stop at addr 0x0.
|
||||
uc->addr_end = uc->exits[0];
|
||||
|
||||
/* Fork() :) */
|
||||
return uc->afl_forkserver_start(uc);
|
||||
|
||||
}
|
||||
|
||||
/* AFL++ supports testcase forwarding via shared map.
|
||||
If the env variable is set, get the shared map here.
|
||||
returns true if we enabled shmap fuzzing, false otherwise. */
|
||||
static bool uc_afl_enable_shm_testcases(uc_engine *uc) {
|
||||
|
||||
char *id_str = getenv(SHM_FUZZ_ENV_VAR);
|
||||
if (id_str) {
|
||||
int shm_id = atoi(id_str);
|
||||
char *map = (char *)shmat(shm_id, NULL, 0);
|
||||
if (!map || map == (void *)-1) {
|
||||
perror("[!] could not access fuzzing shared memory");
|
||||
exit(1);
|
||||
}
|
||||
uc->afl_testcase_size_p = (u32 *)map;
|
||||
uc->afl_testcase_ptr = (map + sizeof(u32));
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] successfully opened shared memory for testcases with id %d\n", shm_id);
|
||||
#endif
|
||||
return true;
|
||||
|
||||
} else {
|
||||
#if defined(AFL_DEBUG)
|
||||
printf("[d] SHM_FUZZ_ENV_VAR not set - not using shared map fuzzing.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* returns the filesize in bytes, -1 or error. */
|
||||
static inline off_t uc_afl_mmap_file(char *filename, char **buf_ptr) {
|
||||
|
||||
off_t ret = -1;
|
||||
|
||||
int fd = open(filename, O_RDONLY);
|
||||
|
||||
struct stat st = {0};
|
||||
if (fstat(fd, &st)) goto exit;
|
||||
|
||||
off_t in_len = st.st_size;
|
||||
|
||||
*buf_ptr = mmap(0, in_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
|
||||
if (*buf_ptr != MAP_FAILED) ret = in_len;
|
||||
|
||||
exit:
|
||||
close(fd);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* A start with "less features" for our afl use-case */
|
||||
/* this is largely copied from uc_emu_start, just without setting the entry point, counter and timeout. */
|
||||
int uc_afl_emu_start(uc_engine *uc) {
|
||||
|
||||
uc->emu_counter = 0;
|
||||
uc->invalid_error = UC_ERR_OK;
|
||||
uc->emulation_done = false;
|
||||
uc->stop_request = false;
|
||||
|
||||
// remove count hook if counting isn't necessary
|
||||
if (uc->count_hook != 0) {
|
||||
uc_hook_del(uc, uc->count_hook);
|
||||
uc->count_hook = 0;
|
||||
}
|
||||
|
||||
uc->vm_start(uc);
|
||||
|
||||
// emulation is done
|
||||
uc->emulation_done = true;
|
||||
|
||||
return uc->invalid_error;
|
||||
|
||||
}
|
||||
|
||||
/* afl_next that expects you know what you're doing
|
||||
Specifically, it won't check for afl_area_ptr and next to be set. */
|
||||
static inline uc_afl_ret uc_afl_next_inl(uc_engine *uc, bool crash_found)
|
||||
{
|
||||
// Tell the parent we need a new testcase, then stop until testcase is available.
|
||||
if (uc->afl_child_request_next(uc, crash_found) == UC_AFL_RET_ERROR) return UC_AFL_RET_ERROR;
|
||||
return UC_AFL_RET_CHILD;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* similar to __afl_persistent loop */
|
||||
static inline uc_afl_ret uc_afl_next(uc_engine *uc, bool crash_found)
|
||||
{
|
||||
|
||||
if (unlikely(!uc->afl_area_ptr)) {
|
||||
fprintf(stderr, "[!] uc_afl_next(...) called before forkserver_start(...).");
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
// Tell the parent we need a new testcase, then stop until testcase is available.
|
||||
if (uc->afl_child_request_next) {
|
||||
|
||||
return uc_afl_next_inl(uc, crash_found);
|
||||
|
||||
}
|
||||
|
||||
return UC_AFL_RET_NO_AFL;
|
||||
}
|
||||
#endif
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_afl_fuzz(
|
||||
uc_engine *uc,
|
||||
char* input_file,
|
||||
uc_afl_cb_place_input_t place_input_callback,
|
||||
uint64_t *exits,
|
||||
size_t exit_count,
|
||||
uc_afl_cb_validate_crash_t validate_crash_callback,
|
||||
bool always_validate,
|
||||
uint32_t persistent_iters,
|
||||
void *data
|
||||
){
|
||||
#ifndef UNICORN_HAS_AFL
|
||||
return UC_ERR_MODE;
|
||||
#else
|
||||
if (!uc) {
|
||||
UCLOG(stderr, "[!] Unicorn Engine passed to uc_afl_fuzz is NULL!\n");
|
||||
return UC_ERR_AFL_RET_ERROR;
|
||||
}
|
||||
if (!(uc->afl)) {
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
if (!input_file || input_file[0] == 0) {
|
||||
UCLOG(stderr, "[!] No input file provided to uc_afl_fuzz.\n");
|
||||
return UC_ERR_AFL_RET_ERROR;
|
||||
}
|
||||
if (!place_input_callback) {
|
||||
UCLOG(stderr, "[!] no place_input_callback set.\n");
|
||||
return UC_ERR_AFL_RET_ERROR;
|
||||
}
|
||||
if (always_validate && !validate_crash_callback) {
|
||||
UCLOG(stderr, "[!] always_validate set but validate_crash_callback is missing.\n");
|
||||
return UC_ERR_AFL_RET_ERROR;
|
||||
}
|
||||
if (!exit_count) {
|
||||
UCLOG(stderr, "[!] Nullptr provided for exits.\n");
|
||||
return UC_ERR_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
uint32_t mmap_in_len = 0;
|
||||
char *in_buf = NULL;
|
||||
uint32_t *in_len_p = NULL;
|
||||
|
||||
bool use_shmap_input = uc_afl_enable_shm_testcases(uc);
|
||||
if (use_shmap_input) {
|
||||
/* For shared map fuzzing, the ptr stays the same */
|
||||
in_buf = uc->afl_testcase_ptr;
|
||||
in_len_p = uc->afl_testcase_size_p;
|
||||
} else {
|
||||
in_len_p = &mmap_in_len;
|
||||
}
|
||||
|
||||
uc_afl_ret afl_ret = uc_afl_forkserver_start(uc, exits, exit_count);
|
||||
switch(afl_ret) {
|
||||
case UC_AFL_RET_CHILD:
|
||||
break;
|
||||
case UC_AFL_RET_NO_AFL:
|
||||
// Not running in AFL.
|
||||
persistent_iters = 1;
|
||||
break;
|
||||
case UC_AFL_RET_FINISHED:
|
||||
// Nothing more to do
|
||||
return UC_ERR_AFL_RET_FINISHED;
|
||||
case UC_AFL_RET_ERROR:
|
||||
return UC_ERR_AFL_RET_ERROR;
|
||||
case UC_AFL_RET_CALLED_TWICE:
|
||||
// Nothing more we can do
|
||||
return UC_ERR_AFL_RET_CALLED_TWICE;
|
||||
default:
|
||||
// What have we done
|
||||
UCLOG(stderr, "[!] Unexpected forkserver return: %d", afl_ret);
|
||||
return UC_ERR_AFL_RET_ERROR;
|
||||
}
|
||||
|
||||
bool first_round = true;
|
||||
bool crash_found = false;
|
||||
|
||||
#if defined(AFL_DEBUG)
|
||||
if (uc->afl_testcase_ptr) {
|
||||
UCLOG("[d] uc->afl_testcase_ptr = %p, len = %d\n", uc->afl_testcase_ptr, *uc->afl_testcase_size_p);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 0 means never stop child in persistence mode.
|
||||
uint32_t i;
|
||||
for (i = 0; persistent_iters == 0 || i < persistent_iters; i++) {
|
||||
|
||||
// The main fuzz loop starts here :)
|
||||
if (first_round) {
|
||||
first_round = false;
|
||||
} else {
|
||||
if (uc_afl_next_inl(uc, crash_found) == UC_AFL_RET_ERROR) {
|
||||
/* parent is probably gone */
|
||||
exit(1);
|
||||
}
|
||||
crash_found = false;
|
||||
}
|
||||
|
||||
/* get input, call place input callback, emulate, unmap input (if needed) */
|
||||
if (unlikely(!use_shmap_input)) {
|
||||
/* in_buf and the len are not in a shared map (as it would be for sharedmem fuzzing
|
||||
No shmap fuzzing involved - Let's read a "normal" file. */
|
||||
off_t in_len = uc_afl_mmap_file(input_file, &in_buf);
|
||||
if (unlikely(in_len < 0)) {
|
||||
UCLOG(stderr, "[!] Unable to mmap file: %s (return was %ld)\n", input_file, (long int) in_len);
|
||||
perror("mmap");
|
||||
fflush(stderr);
|
||||
return UC_AFL_RET_ERROR;
|
||||
}
|
||||
mmap_in_len = in_len;
|
||||
}
|
||||
bool input_accepted = place_input_callback(uc, in_buf, *in_len_p, i, data);
|
||||
|
||||
if (unlikely(!input_accepted)) {
|
||||
// Apparently the input was not to the users' liking. Let's continue.
|
||||
goto next_iter;
|
||||
}
|
||||
|
||||
uc_err uc_emu_ret = uc_afl_emu_start(uc);
|
||||
|
||||
if (unlikely((uc_emu_ret != UC_ERR_OK) || (always_validate && validate_crash_callback))) {
|
||||
|
||||
if (validate_crash_callback != NULL && validate_crash_callback(
|
||||
uc, uc_emu_ret, in_buf, *in_len_p, i, data) != true) {
|
||||
// The callback thinks this is not a valid crash. Ignore.
|
||||
goto next_iter;
|
||||
}
|
||||
if (persistent_iters != 1) {
|
||||
// We're inpersistent mode and can report the crash via afl_next. No reason to die.
|
||||
crash_found = true;
|
||||
goto next_iter;
|
||||
}
|
||||
|
||||
UCLOG(stderr, "[!] UC returned Error: '%s' - let's abort().\n", uc_strerror(uc_emu_ret));
|
||||
fflush(stderr);
|
||||
|
||||
abort();
|
||||
|
||||
}
|
||||
next_iter:
|
||||
if (!use_shmap_input) munmap(in_buf, mmap_in_len);
|
||||
}
|
||||
// UC_AFL_RET_CHILD -> We looped through all iters.
|
||||
// We are still in the child, nothing good will come after this.
|
||||
// Exit and let the next generation run.
|
||||
if (likely(afl_ret == UC_AFL_RET_CHILD)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (uc->afl_area_ptr) {
|
||||
// Nothing should ever come after this but clean it up still.
|
||||
// shmdt(uc->afl_area_ptr);
|
||||
uc->afl_area_ptr = NULL;
|
||||
uc->afl_testcase_ptr = NULL;
|
||||
|
||||
}
|
||||
|
||||
// UC_AFL_RET_NO_AFL -> Not fuzzing. We ran once.
|
||||
return UC_AFL_RET_NO_AFL;
|
||||
#endif
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_emu_stop(uc_engine *uc)
|
||||
|
Loading…
Reference in New Issue
Block a user