• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * honggfuzz - core structures and macros
4  * -----------------------------------------
5  *
6  * Author: Robert Swiecki <swiecki@google.com>
7  *
8  * Copyright 2010-2018 by Google Inc. All Rights Reserved.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License"); you may
11  * not use this file except in compliance with the License. You may obtain
12  * a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
19  * implied. See the License for the specific language governing
20  * permissions and limitations under the License.
21  *
22  */
23 
24 #ifndef _HF_HONGGFUZZ_H_
25 #define _HF_HONGGFUZZ_H_
26 
27 #include <dirent.h>
28 #include <inttypes.h>
29 #include <limits.h>
30 #include <pthread.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include <sys/param.h>
34 #include <sys/queue.h>
35 #include <sys/types.h>
36 #include <time.h>
37 
38 #include "libhfcommon/util.h"
39 
40 #define PROG_NAME "honggfuzz"
41 #define PROG_VERSION "1.9"
42 
43 /* Name of the template which will be replaced with the proper name of the file */
44 #define _HF_FILE_PLACEHOLDER "___FILE___"
45 
46 /* Default name of the report created with some architectures */
47 #define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT"
48 
49 /* Default stack-size of created threads. */
50 #define _HF_PTHREAD_STACKSIZE (1024ULL * 1024ULL * 2ULL) /* 2MB */
51 
52 /* Name of envvar which indicates sequential number of fuzzer */
53 #define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO"
54 
55 /* Name of envvar which indicates that the netDriver should be used */
56 #define _HF_THREAD_NETDRIVER_ENV "HFUZZ_USE_NETDRIVER"
57 
58 /* Name of envvar which indicates honggfuzz's log level in use */
59 #define _HF_LOG_LEVEL_ENV "HFUZZ_LOG_LEVEL"
60 
61 /* Number of crash verifier iterations before tag crash as stable */
62 #define _HF_VERIFIER_ITER 5
63 
64 /* Size (in bytes) for report data to be stored in stack before written to file */
65 #define _HF_REPORT_SIZE 8192
66 
67 /* Perf bitmap size */
68 #define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U)
69 #define _HF_PERF_BITMAP_BITSZ_MASK 0x7FFFFFFULL
70 /* Maximum number of PC guards (=trace-pc-guard) we support */
71 #define _HF_PC_GUARD_MAX (1024ULL * 1024ULL * 64ULL)
72 
73 /* Maximum size of the input file in bytes (128 MiB) */
74 #define _HF_INPUT_MAX_SIZE (1024ULL * 1024ULL * 128ULL)
75 
76 /* FD used to log inside the child process */
77 #define _HF_LOG_FD 1020
78 /* FD used to represent the input file */
79 #define _HF_INPUT_FD 1021
80 /* FD used to pass feedback bitmap a process */
81 #define _HF_BITMAP_FD 1022
82 /* FD used to pass data to a persistent process */
83 #define _HF_PERSISTENT_FD 1023
84 
85 /* Message indicating that the fuzzed process is ready for new data */
86 static const uint8_t HFReadyTag = 'R';
87 
88 /* Maximum number of active fuzzing threads */
89 #define _HF_THREAD_MAX 1024U
90 
91 /* Persistent-binary signature - if found within file, it means it's a persistent mode binary */
92 #define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF"
93 /* HF NetDriver signature - if found within file, it means it's a NetDriver-based binary */
94 #define _HF_NETDRIVER_SIG "\x01_LIBHFUZZ_NETDRIVER_BINARY_SIGNATURE_\x02\xFF"
95 
96 typedef enum {
97     _HF_DYNFILE_NONE = 0x0,
98     _HF_DYNFILE_INSTR_COUNT = 0x1,
99     _HF_DYNFILE_BRANCH_COUNT = 0x2,
100     _HF_DYNFILE_BTS_EDGE = 0x10,
101     _HF_DYNFILE_IPT_BLOCK = 0x20,
102     _HF_DYNFILE_SOFT = 0x40,
103 } dynFileMethod_t;
104 
105 typedef struct {
106     uint64_t cpuInstrCnt;
107     uint64_t cpuBranchCnt;
108     uint64_t bbCnt;
109     uint64_t newBBCnt;
110     uint64_t softCntPc;
111     uint64_t softCntEdge;
112     uint64_t softCntCmp;
113 } hwcnt_t;
114 
115 typedef struct {
116     uint32_t capacity;
117     uint32_t* pChunks;
118     uint32_t nChunks;
119 } bitmap_t;
120 
121 /* Memory map struct */
122 typedef struct __attribute__((packed)) {
123     uint64_t start;          // region start addr
124     uint64_t end;            // region end addr
125     uint64_t base;           // region base addr
126     char mapName[NAME_MAX];  // bin/DSO name
127     uint64_t bbCnt;
128     uint64_t newBBCnt;
129 } memMap_t;
130 
131 /* Trie node data struct */
132 typedef struct __attribute__((packed)) {
133     bitmap_t* pBM;
134 } trieData_t;
135 
136 /* Trie node struct */
137 typedef struct node {
138     char key;
139     trieData_t data;
140     struct node* next;
141     struct node* prev;
142     struct node* children;
143     struct node* parent;
144 } node_t;
145 
146 /* EOF Sanitizer coverage specific data structures */
147 
148 typedef enum {
149     _HF_STATE_UNSET = 0,
150     _HF_STATE_STATIC = 1,
151     _HF_STATE_DYNAMIC_DRY_RUN = 2,
152     _HF_STATE_DYNAMIC_SWITCH_TO_MAIN = 3,
153     _HF_STATE_DYNAMIC_MAIN = 4,
154 } fuzzState_t;
155 
156 struct dynfile_t {
157     uint8_t* data;
158     size_t size;
159     TAILQ_ENTRY(dynfile_t)
160     pointers;
161 };
162 
163 struct strings_t {
164     char* s;
165     size_t len;
166     TAILQ_ENTRY(strings_t)
167     pointers;
168 };
169 
170 typedef struct {
171     bool pcGuardMap[_HF_PC_GUARD_MAX];
172     uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
173     uint32_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
174     uint64_t pidFeedbackPc[_HF_THREAD_MAX];
175     uint64_t pidFeedbackEdge[_HF_THREAD_MAX];
176     uint64_t pidFeedbackCmp[_HF_THREAD_MAX];
177 } feedback_t;
178 
179 typedef struct {
180     struct {
181         size_t threadsMax;
182         size_t threadsFinished;
183         uint32_t threadsActiveCnt;
184         pthread_t mainThread;
185         pid_t mainPid;
186         pthread_t threads[_HF_THREAD_MAX];
187     } threads;
188     struct {
189         const char* inputDir;
190         DIR* inputDirPtr;
191         size_t fileCnt;
192         const char* fileExtn;
193         bool fileCntDone;
194         const char* workDir;
195         const char* crashDir;
196         const char* covDirAll;
197         const char* covDirNew;
198         bool saveUnique;
199         size_t dynfileqCnt;
200         pthread_rwlock_t dynfileq_mutex;
201         TAILQ_HEAD(dyns_t, dynfile_t) dynfileq;
202     } io;
203     struct {
204         int argc;
205         const char* const* cmdline;
206         bool nullifyStdio;
207         bool fuzzStdin;
208         const char* externalCommand;
209         const char* postExternalCommand;
210         const char* feedbackMutateCommand;
211         bool netDriver;
212         bool persistent;
213         uint64_t asLimit;
214         uint64_t rssLimit;
215         uint64_t dataLimit;
216         uint64_t coreLimit;
217         bool clearEnv;
218         char* envs[128];
219         sigset_t waitSigSet;
220     } exe;
221     struct {
222         time_t timeStart;
223         time_t runEndTime;
224         time_t tmOut;
225         time_t lastCovUpdate;
226         bool tmoutVTALRM;
227     } timing;
228     struct {
229         const char* dictionaryFile;
230         TAILQ_HEAD(strq_t, strings_t) dictq;
231         size_t dictionaryCnt;
232         size_t mutationsMax;
233         unsigned mutationsPerRun;
234         size_t maxFileSz;
235     } mutate;
236     struct {
237         bool useScreen;
238         char cmdline_txt[65];
239         int64_t lastDisplayMillis;
240     } display;
241     struct {
242         bool useVerifier;
243         bool exitUponCrash;
244         const char* reportFile;
245         pthread_mutex_t report_mutex;
246         bool monitorSIGABRT;
247         size_t dynFileIterExpire;
248         bool only_printable;
249     } cfg;
250     struct {
251         bool enable;
252     } sanitizer;
253     struct {
254         fuzzState_t state;
255         feedback_t* feedbackMap;
256         int bbFd;
257         pthread_mutex_t feedback_mutex;
258         const char* blacklistFile;
259         uint64_t* blacklist;
260         size_t blacklistCnt;
261         bool skipFeedbackOnTimeout;
262         dynFileMethod_t dynFileMethod;
263     } feedback;
264     struct {
265         size_t mutationsCnt;
266         size_t crashesCnt;
267         size_t uniqueCrashesCnt;
268         size_t verifiedCrashesCnt;
269         size_t blCrashesCnt;
270         size_t timeoutedCnt;
271     } cnts;
272     struct {
273         bool enabled;
274         int serverSocket;
275         int clientSocket;
276     } socketFuzzer;
277     /* For the Linux code */
278     struct {
279         int exeFd;
280         hwcnt_t hwCnts;
281         uint64_t dynamicCutOffAddr;
282         bool disableRandomization;
283         void* ignoreAddr;
284         size_t numMajorFrames;
285         const char* symsBlFile;
286         char** symsBl;
287         size_t symsBlCnt;
288         const char* symsWlFile;
289         char** symsWl;
290         size_t symsWlCnt;
291         uintptr_t cloneFlags;
292         bool kernelOnly;
293         bool useClone;
294     } linux;
295     /* For the NetBSD code */
296     struct {
297         void* ignoreAddr;
298         size_t numMajorFrames;
299         const char* symsBlFile;
300         char** symsBl;
301         size_t symsBlCnt;
302         const char* symsWlFile;
303         char** symsWl;
304         size_t symsWlCnt;
305     } netbsd;
306 } honggfuzz_t;
307 
308 typedef enum {
309     _HF_RS_UNKNOWN = 0,
310     _HF_RS_WAITING_FOR_INITIAL_READY = 1,
311     _HF_RS_WAITING_FOR_READY = 2,
312     _HF_RS_SEND_DATA = 3,
313 } runState_t;
314 
315 typedef struct {
316     honggfuzz_t* global;
317     pid_t pid;
318     int64_t timeStartedMillis;
319     char origFileName[PATH_MAX];
320     char crashFileName[PATH_MAX];
321     uint64_t pc;
322     uint64_t backtrace;
323     uint64_t access;
324     int exception;
325     char report[_HF_REPORT_SIZE];
326     bool mainWorker;
327     unsigned mutationsPerRun;
328     struct dynfile_t* dynfileqCurrent;
329     uint8_t* dynamicFile;
330     size_t dynamicFileSz;
331     int dynamicFileFd;
332     int dynamicFileCopyFd;
333     uint32_t fuzzNo;
334     int persistentSock;
335     bool waitingForReady;
336     runState_t runState;
337     bool tmOutSignaled;
338 #if !defined(_HF_ARCH_DARWIN)
339     timer_t timerId;
340 #endif  // !defined(_HF_ARCH_DARWIN)
341 
342     struct {
343         /* For Linux code */
344         uint8_t* perfMmapBuf;
345         uint8_t* perfMmapAux;
346         hwcnt_t hwCnts;
347         int cpuInstrFd;
348         int cpuBranchFd;
349         int cpuIptBtsFd;
350     } linux;
351 
352     struct {
353         /* For NetBSD code */
354         uint8_t* perfMmapBuf;
355         uint8_t* perfMmapAux;
356         hwcnt_t hwCnts;
357         int cpuInstrFd;
358         int cpuBranchFd;
359         int cpuIptBtsFd;
360     } netbsd;
361 } run_t;
362 
363 /*
364  * Go-style defer scoped implementation
365  *
366  * When compiled with clang, use: -fblocks -lBlocksRuntime
367  *
368  * Example of use:
369  *
370  * {
371  *   int fd = open(fname, O_RDONLY);
372  *   if (fd == -1) {
373  *     error(....);
374  *     return;
375  *   }
376  *   defer { close(fd); };
377  *   ssize_t sz = read(fd, buf, sizeof(buf));
378  *   ...
379  *   ...
380  * }
381  *
382  */
383 
384 #define __STRMERGE(a, b) a##b
385 #define _STRMERGE(a, b) __STRMERGE(a, b)
386 #ifdef __clang__
387 #if __has_extension(blocks)
388 static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) {
389     (*dfunc)();
390 }
391 
392 #define defer                                        \
393     void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \
394         __attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
395 
396 #else /* __has_extension(blocks) */
397 #define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
398 #endif /*  __has_extension(blocks) */
399 #else  /* !__clang__, e.g.: gcc */
400 
401 #define __block
402 #define _DEFER(a, count)                                                                      \
403     auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)));         \
404     int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
405         __attribute__((unused));                                                              \
406     void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
407 #define defer _DEFER(a, __COUNTER__)
408 #endif /* ifdef __clang__ */
409 
410 /* Block scoped mutexes */
411 #define MX_SCOPED_LOCK(m) \
412     MX_LOCK(m);           \
413     defer {               \
414         MX_UNLOCK(m);     \
415     }
416 
417 #define MX_SCOPED_RWLOCK_READ(m) \
418     MX_RWLOCK_READ(m);           \
419     defer {                      \
420         MX_RWLOCK_UNLOCK(m);     \
421     }
422 #define MX_SCOPED_RWLOCK_WRITE(m) \
423     MX_RWLOCK_WRITE(m);           \
424     defer {                       \
425         MX_RWLOCK_UNLOCK(m);      \
426     }
427 
428 #endif
429