blob: 02e35b40e217b291b5252fafb5d72527499da17e [file] [log] [blame]
/*
*
* honggfuzz - core structures and macros
* -----------------------------------------
*
* Author: Robert Swiecki <swiecki@google.com>
*
* Copyright 2010-2017 by Google Inc. 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
#ifndef _HF_HONGGFUZZ_H_
#define _HF_HONGGFUZZ_H_
#include <dirent.h>
#include <inttypes.h>
#include <limits.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <time.h>
#include "libhfcommon/util.h"
#define PROG_NAME "honggfuzz"
#define PROG_VERSION "1.3"
/* Name of the template which will be replaced with the proper name of the file */
#define _HF_FILE_PLACEHOLDER "___FILE___"
/* Default name of the report created with some architectures */
#define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT"
/* Default stack-size of created threads. */
#define _HF_PTHREAD_STACKSIZE (1024 * 1024 * 2) /* 2MB */
/* Name of envvar which indicates sequential number of fuzzer */
#define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO"
/* Number of crash verifier iterations before tag crash as stable */
#define _HF_VERIFIER_ITER 5
/* Size (in bytes) for report data to be stored in stack before written to file */
#define _HF_REPORT_SIZE 8192
/* Perf bitmap size */
#define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U)
#define _HF_PERF_BITMAP_BITSZ_MASK 0x7ffffff
/* Maximum number of PC guards (=trace-pc-guard) we support */
#define _HF_PC_GUARD_MAX (1024U * 1024U * 16U)
/* Maximum size of the input file in bytes (128 MiB) */
#define _HF_INPUT_MAX_SIZE (1024 * 1024 * 128)
/* FD used to represent the input file */
#define _HF_INPUT_FD 1021
/* FD used to pass feedback bitmap a process */
#define _HF_BITMAP_FD 1022
/* FD used to pass data to a persistent process */
#define _HF_PERSISTENT_FD 1023
/* Message indicating that the fuzz process has finished processing data (fuzzed->fuzzer) */
static const uint8_t HFdoneTag = 'D';
/* Maximum number of active fuzzing threads */
#define _HF_THREAD_MAX 1024U
/* Persistent-binary signature - if found within file, it means it's a persistent mode binary */
#define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF"
typedef enum {
_HF_DYNFILE_NONE = 0x0,
_HF_DYNFILE_INSTR_COUNT = 0x1,
_HF_DYNFILE_BRANCH_COUNT = 0x2,
_HF_DYNFILE_BTS_EDGE = 0x10,
_HF_DYNFILE_IPT_BLOCK = 0x20,
_HF_DYNFILE_SOFT = 0x40,
} dynFileMethod_t;
typedef struct {
uint64_t cpuInstrCnt;
uint64_t cpuBranchCnt;
uint64_t bbCnt;
uint64_t newBBCnt;
uint64_t softCntPc;
uint64_t softCntEdge;
uint64_t softCntCmp;
} hwcnt_t;
/* Sanitizer coverage specific data structures */
typedef struct {
uint64_t hitBBCnt;
uint64_t totalBBCnt;
uint64_t dsoCnt;
uint64_t iDsoCnt;
uint64_t newBBCnt;
uint64_t crashesCnt;
} sancovcnt_t;
typedef struct {
uint32_t capacity;
uint32_t* pChunks;
uint32_t nChunks;
} bitmap_t;
/* Memory map struct */
typedef struct __attribute__((packed)) {
uint64_t start; // region start addr
uint64_t end; // region end addr
uint64_t base; // region base addr
char mapName[NAME_MAX]; // bin/DSO name
uint64_t bbCnt;
uint64_t newBBCnt;
} memMap_t;
/* Trie node data struct */
typedef struct __attribute__((packed)) {
bitmap_t* pBM;
} trieData_t;
/* Trie node struct */
typedef struct node {
char key;
trieData_t data;
struct node* next;
struct node* prev;
struct node* children;
struct node* parent;
} node_t;
/* EOF Sanitizer coverage specific data structures */
typedef enum {
_HF_STATE_UNSET = 0,
_HF_STATE_STATIC = 1,
_HF_STATE_DYNAMIC_PRE = 2,
_HF_STATE_DYNAMIC_MAIN = 3,
} fuzzState_t;
struct dynfile_t {
uint8_t* data;
size_t size;
TAILQ_ENTRY(dynfile_t)
pointers;
};
struct strings_t {
char* s;
size_t len;
TAILQ_ENTRY(strings_t)
pointers;
};
typedef struct {
bool pcGuardMap[_HF_PC_GUARD_MAX];
uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
uint8_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
uint64_t pidFeedbackPc[_HF_THREAD_MAX];
uint64_t pidFeedbackEdge[_HF_THREAD_MAX];
uint64_t pidFeedbackCmp[_HF_THREAD_MAX];
} feedback_t;
typedef struct {
struct {
const char* inputDir;
DIR* inputDirPtr;
size_t fileCnt;
const char* fileExtn;
bool fileCntDone;
const char* workDir;
const char* crashDir;
const char* covDirAll;
const char* covDirNew;
bool saveUnique;
} io;
struct {
int argc;
const char* const* cmdline;
bool nullifyStdio;
bool fuzzStdin;
char* externalCommand;
char* postExternalCommand;
uint64_t asLimit;
uint64_t rssLimit;
uint64_t dataLimit;
bool clearEnv;
char* envs[128];
} exe;
struct {
size_t threadsMax;
size_t threadsFinished;
uint32_t threadsActiveCnt;
pthread_t mainThread;
pid_t mainPid;
} threads;
struct {
time_t timeStart;
time_t runEndTime;
time_t tmOut;
bool tmoutVTALRM;
} timing;
bool useScreen;
bool useVerifier;
char cmdline_txt[61];
unsigned mutationsPerRun;
const char* blacklistFile;
uint64_t* blacklist;
size_t blacklistCnt;
size_t mutationsMax;
size_t maxFileSz;
char* reportFile;
bool persistent;
bool skipFeedbackOnTimeout;
bool enableSanitizers;
bool monitorSIGABRT;
bool exitUponCrash;
const char* dictionaryFile;
TAILQ_HEAD(strq_t, strings_t) dictq;
size_t dictionaryCnt;
struct strings_t* dictqCurrent;
fuzzState_t state;
feedback_t* feedback;
int bbFd;
size_t dynfileqCnt;
TAILQ_HEAD(dyns_t, dynfile_t) dynfileq;
pthread_rwlock_t dynfileq_mutex;
pthread_mutex_t feedback_mutex;
struct {
size_t mutationsCnt;
size_t crashesCnt;
size_t uniqueCrashesCnt;
size_t verifiedCrashesCnt;
size_t blCrashesCnt;
size_t timeoutedCnt;
} cnts;
dynFileMethod_t dynFileMethod;
sancovcnt_t sanCovCnts;
pthread_mutex_t sanCov_mutex;
const char* extSanOpts;
size_t dynFileIterExpire;
bool useSanCov;
node_t* covMetadata;
pthread_mutex_t report_mutex;
/* For the Linux code */
struct {
int exeFd;
hwcnt_t hwCnts;
uint64_t dynamicCutOffAddr;
bool disableRandomization;
void* ignoreAddr;
size_t numMajorFrames;
pid_t pid;
const char* pidFile;
char pidCmd[55];
const char* symsBlFile;
char** symsBl;
size_t symsBlCnt;
const char* symsWlFile;
char** symsWl;
size_t symsWlCnt;
uintptr_t cloneFlags;
bool kernelOnly;
bool useClone;
sigset_t waitSigSet;
} linux;
} honggfuzz_t;
typedef struct {
honggfuzz_t* global;
pid_t pid;
pid_t persistentPid;
fuzzState_t state;
int64_t timeStartedMillis;
const char* origFileName;
char crashFileName[PATH_MAX];
uint64_t pc;
uint64_t backtrace;
uint64_t access;
int exception;
char report[_HF_REPORT_SIZE];
bool mainWorker;
unsigned mutationsPerRun;
struct dynfile_t* dynfileqCurrent;
uint8_t* dynamicFile;
size_t dynamicFileSz;
int dynamicFileFd;
uint32_t fuzzNo;
int persistentSock;
bool tmOutSignaled;
#if !defined(_HF_ARCH_DARWIN)
timer_t timerId;
#endif // !defined(_HF_ARCH_DARWIN)
sancovcnt_t sanCovCnts;
struct {
/* For Linux code */
uint8_t* perfMmapBuf;
uint8_t* perfMmapAux;
hwcnt_t hwCnts;
pid_t attachedPid;
int cpuInstrFd;
int cpuBranchFd;
int cpuIptBtsFd;
} linux;
} run_t;
/* Go-style defer implementation */
#define __STRMERGE(a, b) a##b
#define _STRMERGE(a, b) __STRMERGE(a, b)
#ifdef __clang__
#if __has_extension(blocks)
static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) { (*dfunc)(); }
#define defer \
void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \
__attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
#else /* __has_extension(blocks) */
#define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
#endif /* __has_extension(blocks) */
#else /* __clang */
#define __block
#define _DEFER(a, count) \
auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))); \
int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
__attribute__((unused)); \
void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
#define defer _DEFER(a, __COUNTER__)
#endif /* __clang */
#define MX_SCOPED_LOCK(m) \
MX_LOCK(m); \
defer { MX_UNLOCK(m); }
#define MX_SCOPED_RWLOCK_READ(m) \
MX_RWLOCK_READ(m); \
defer { MX_RWLOCK_UNLOCK(m); }
#define MX_SCOPED_RWLOCK_WRITE(m) \
MX_RWLOCK_WRITE(m); \
defer { MX_RWLOCK_UNLOCK(m); }
#endif