• 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.8"
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_MAIN = 3,
153 } fuzzState_t;
154 
155 struct dynfile_t {
156     uint8_t* data;
157     size_t size;
158     TAILQ_ENTRY(dynfile_t)
159     pointers;
160 };
161 
162 struct strings_t {
163     char* s;
164     size_t len;
165     TAILQ_ENTRY(strings_t)
166     pointers;
167 };
168 
169 typedef struct {
170     bool pcGuardMap[_HF_PC_GUARD_MAX];
171     uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M];
172     uint32_t bbMapCmp[_HF_PERF_BITMAP_SIZE_16M];
173     uint64_t pidFeedbackPc[_HF_THREAD_MAX];
174     uint64_t pidFeedbackEdge[_HF_THREAD_MAX];
175     uint64_t pidFeedbackCmp[_HF_THREAD_MAX];
176 } feedback_t;
177 
178 typedef struct {
179     struct {
180         size_t threadsMax;
181         size_t threadsFinished;
182         uint32_t threadsActiveCnt;
183         pthread_t mainThread;
184         pid_t mainPid;
185         pthread_t threads[_HF_THREAD_MAX];
186     } threads;
187     struct {
188         const char* inputDir;
189         DIR* inputDirPtr;
190         size_t fileCnt;
191         const char* fileExtn;
192         bool fileCntDone;
193         const char* workDir;
194         const char* crashDir;
195         const char* covDirAll;
196         const char* covDirNew;
197         bool saveUnique;
198         size_t dynfileqCnt;
199         pthread_rwlock_t dynfileq_mutex;
200         TAILQ_HEAD(dyns_t, dynfile_t) dynfileq;
201     } io;
202     struct {
203         int argc;
204         const char* const* cmdline;
205         bool nullifyStdio;
206         bool fuzzStdin;
207         const char* externalCommand;
208         const char* postExternalCommand;
209         bool netDriver;
210         bool persistent;
211         uint64_t asLimit;
212         uint64_t rssLimit;
213         uint64_t dataLimit;
214         uint64_t coreLimit;
215         bool clearEnv;
216         char* envs[128];
217         sigset_t waitSigSet;
218     } exe;
219     struct {
220         time_t timeStart;
221         time_t runEndTime;
222         time_t tmOut;
223         time_t lastCovUpdate;
224         bool tmoutVTALRM;
225     } timing;
226     struct {
227         const char* dictionaryFile;
228         TAILQ_HEAD(strq_t, strings_t) dictq;
229         size_t dictionaryCnt;
230         size_t mutationsMax;
231         unsigned mutationsPerRun;
232         size_t maxFileSz;
233     } mutate;
234     struct {
235         bool useScreen;
236         char cmdline_txt[65];
237         int64_t lastDisplayMillis;
238     } display;
239     struct {
240         bool useVerifier;
241         bool exitUponCrash;
242         const char* reportFile;
243         pthread_mutex_t report_mutex;
244         bool monitorSIGABRT;
245         size_t dynFileIterExpire;
246         bool only_printable;
247     } cfg;
248     struct {
249         bool enable;
250     } sanitizer;
251     struct {
252         fuzzState_t state;
253         feedback_t* feedbackMap;
254         int bbFd;
255         pthread_mutex_t feedback_mutex;
256         const char* blacklistFile;
257         uint64_t* blacklist;
258         size_t blacklistCnt;
259         bool skipFeedbackOnTimeout;
260         dynFileMethod_t dynFileMethod;
261     } feedback;
262     struct {
263         size_t mutationsCnt;
264         size_t crashesCnt;
265         size_t uniqueCrashesCnt;
266         size_t verifiedCrashesCnt;
267         size_t blCrashesCnt;
268         size_t timeoutedCnt;
269     } cnts;
270     struct {
271         bool enabled;
272         int serverSocket;
273         int clientSocket;
274     } socketFuzzer;
275     /* For the Linux code */
276     struct {
277         int exeFd;
278         hwcnt_t hwCnts;
279         uint64_t dynamicCutOffAddr;
280         bool disableRandomization;
281         void* ignoreAddr;
282         size_t numMajorFrames;
283         const char* symsBlFile;
284         char** symsBl;
285         size_t symsBlCnt;
286         const char* symsWlFile;
287         char** symsWl;
288         size_t symsWlCnt;
289         uintptr_t cloneFlags;
290         bool kernelOnly;
291         bool useClone;
292     } linux;
293     /* For the NetBSD code */
294     struct {
295         void* ignoreAddr;
296         size_t numMajorFrames;
297         const char* symsBlFile;
298         char** symsBl;
299         size_t symsBlCnt;
300         const char* symsWlFile;
301         char** symsWl;
302         size_t symsWlCnt;
303     } netbsd;
304 } honggfuzz_t;
305 
306 typedef enum {
307     _HF_RS_UNKNOWN = 0,
308     _HF_RS_WAITING_FOR_INITIAL_READY = 1,
309     _HF_RS_WAITING_FOR_READY = 2,
310     _HF_RS_SEND_DATA = 3,
311 } runState_t;
312 
313 typedef struct {
314     honggfuzz_t* global;
315     pid_t pid;
316     int64_t timeStartedMillis;
317     char origFileName[PATH_MAX];
318     char crashFileName[PATH_MAX];
319     uint64_t pc;
320     uint64_t backtrace;
321     uint64_t access;
322     int exception;
323     char report[_HF_REPORT_SIZE];
324     bool mainWorker;
325     unsigned mutationsPerRun;
326     struct dynfile_t* dynfileqCurrent;
327     uint8_t* dynamicFile;
328     size_t dynamicFileSz;
329     int dynamicFileFd;
330     int dynamicFileCopyFd;
331     uint32_t fuzzNo;
332     int persistentSock;
333     bool waitingForReady;
334     runState_t runState;
335     bool tmOutSignaled;
336 #if !defined(_HF_ARCH_DARWIN)
337     timer_t timerId;
338 #endif  // !defined(_HF_ARCH_DARWIN)
339 
340     struct {
341         /* For Linux code */
342         uint8_t* perfMmapBuf;
343         uint8_t* perfMmapAux;
344         hwcnt_t hwCnts;
345         int cpuInstrFd;
346         int cpuBranchFd;
347         int cpuIptBtsFd;
348     } linux;
349 
350     struct {
351         /* For NetBSD code */
352         uint8_t* perfMmapBuf;
353         uint8_t* perfMmapAux;
354         hwcnt_t hwCnts;
355         int cpuInstrFd;
356         int cpuBranchFd;
357         int cpuIptBtsFd;
358     } netbsd;
359 } run_t;
360 
361 /*
362  * Go-style defer scoped implementation
363  *
364  * When compiled with clang, use: -fblocks -lBlocksRuntime
365  *
366  * Example of use:
367  *
368  * {
369  *   int fd = open(fname, O_RDONLY);
370  *   if (fd == -1) {
371  *     error(....);
372  *     return;
373  *   }
374  *   defer { close(fd); };
375  *   ssize_t sz = read(fd, buf, sizeof(buf));
376  *   ...
377  *   ...
378  * }
379  *
380  */
381 
382 #define __STRMERGE(a, b) a##b
383 #define _STRMERGE(a, b) __STRMERGE(a, b)
384 #ifdef __clang__
385 #if __has_extension(blocks)
386 static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) {
387     (*dfunc)();
388 }
389 
390 #define defer                                        \
391     void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \
392         __attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^
393 
394 #else /* __has_extension(blocks) */
395 #define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED
396 #endif /*  __has_extension(blocks) */
397 #else  /* !__clang__, e.g.: gcc */
398 
399 #define __block
400 #define _DEFER(a, count)                                                                      \
401     auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)));         \
402     int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \
403         __attribute__((unused));                                                              \
404     void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
405 #define defer _DEFER(a, __COUNTER__)
406 #endif /* ifdef __clang__ */
407 
408 /* Block scoped mutexes */
409 #define MX_SCOPED_LOCK(m) \
410     MX_LOCK(m);           \
411     defer {               \
412         MX_UNLOCK(m);     \
413     }
414 
415 #define MX_SCOPED_RWLOCK_READ(m) \
416     MX_RWLOCK_READ(m);           \
417     defer {                      \
418         MX_RWLOCK_UNLOCK(m);     \
419     }
420 #define MX_SCOPED_RWLOCK_WRITE(m) \
421     MX_RWLOCK_WRITE(m);           \
422     defer {                       \
423         MX_RWLOCK_UNLOCK(m);      \
424     }
425 
426 #endif
427