blob: d9aab8b3345beaacb8e1c325a9089277f9bee370 [file] [log] [blame]
robert.swiecki3bb518c2010-10-14 00:48:24 +00001/*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00002 *
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +00003 * honggfuzz - fuzzing routines
4 * -----------------------------------------
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00005 *
robert.swiecki@gmail.com8531f692015-02-17 12:25:36 +00006 * Author:
7 * Robert Swiecki <swiecki@google.com>
8 * Felix Gröbert <groebert@google.com>
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00009 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000010 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000011 *
12 * Licensed under the Apache License, Version 2.0 (the "License"); you may
13 * not use this file except in compliance with the License. You may obtain
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000014 * a copy of the License at
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000015 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000016 * http://www.apache.org/licenses/LICENSE-2.0
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000017 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000018 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
21 * implied. See the License for the specific language governing
22 * permissions and limitations under the License.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000023 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000024 */
robert.swiecki3bb518c2010-10-14 00:48:24 +000025
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000026#include "common.h"
27#include "fuzz.h"
28
29#include <errno.h>
30#include <fcntl.h>
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +000031#include <inttypes.h>
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +000032#include <pthread.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000033#include <signal.h>
34#include <stddef.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000039#include <sys/mman.h>
40#include <sys/param.h>
41#include <sys/stat.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000042#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/wait.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000045#include <time.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000046#include <unistd.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000047
robert.swiecki3bb518c2010-10-14 00:48:24 +000048#include "arch.h"
Jagger0764ad72015-09-06 01:11:08 +020049#include "display.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000050#include "files.h"
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +000051#include "log.h"
robert.swiecki@gmail.com36700b52015-02-22 05:03:16 +000052#include "mangle.h"
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +000053#include "report.h"
54#include "util.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000055
robert.swiecki@gmail.comcf4e8d02015-04-23 15:53:39 +000056static int fuzz_sigReceived = 0;
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +000057
Jagger6113c432015-09-24 05:00:28 +020058static pthread_t fuzz_mainThread;
59
Anestis Bechtsoudis1dd19232015-12-30 13:11:06 +020060static inline bool fuzz_isPerfCntsSet(honggfuzz_t * hfuzz)
Anestis Bechtsoudis914787a2015-12-26 18:24:03 +020061{
Anestis Bechtsoudisf2a5bc62015-12-26 18:41:48 +020062 if (hfuzz->hwCnts.cpuInstrCnt > 0ULL || hfuzz->hwCnts.cpuBranchCnt > 0ULL
Jagger39bd2b02016-02-04 01:16:15 +010063 || hfuzz->hwCnts.cpuBtsBlockCnt > 0ULL || hfuzz->hwCnts.cpuBtsEdgeCnt > 0ULL
Anestis Bechtsoudisf2a5bc62015-12-26 18:41:48 +020064 || hfuzz->hwCnts.customCnt > 0ULL) {
Anestis Bechtsoudis914787a2015-12-26 18:24:03 +020065 return true;
66 } else {
67 return false;
68 }
69}
70
Anestis Bechtsoudis1dd19232015-12-30 13:11:06 +020071static inline void fuzz_resetFeedbackCnts(honggfuzz_t * hfuzz)
72{
73 /* HW perf counters */
74 __sync_fetch_and_and(&hfuzz->hwCnts.cpuInstrCnt, 0UL);
75 __sync_fetch_and_and(&hfuzz->hwCnts.cpuBranchCnt, 0UL);
Jagger39bd2b02016-02-04 01:16:15 +010076 __sync_fetch_and_and(&hfuzz->hwCnts.cpuBtsBlockCnt, 0UL);
77 __sync_fetch_and_and(&hfuzz->hwCnts.cpuBtsEdgeCnt, 0UL);
Anestis Bechtsoudis1dd19232015-12-30 13:11:06 +020078 __sync_fetch_and_and(&hfuzz->hwCnts.customCnt, 0UL);
79
80 /* Sanitizer coverage counter */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +020081 __sync_fetch_and_and(&hfuzz->sanCovCnts.hitBBCnt, 0UL);
82 __sync_fetch_and_and(&hfuzz->sanCovCnts.totalBBCnt, 0UL);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020083 __sync_fetch_and_and(&hfuzz->sanCovCnts.dsoCnt, 0UL);
84 __sync_fetch_and_and(&hfuzz->sanCovCnts.iDsoCnt, 0UL);
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +020085 __sync_fetch_and_and(&hfuzz->sanCovCnts.newBBCnt, 0UL);
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +020086 __sync_fetch_and_and(&hfuzz->sanCovCnts.crashesCnt, 0UL);
Anestis Bechtsoudisb78cf602016-01-07 13:10:50 +020087
Robert Swiecki23ec02a2016-01-19 18:47:45 +010088 /*
Anestis Bechtsoudis1fd10c72016-01-07 12:38:45 +020089 * For performance reasons Trie & Bitmap methods are not exposed in arch.h
90 * Thus maintain a status flag to destroy runtime data internally at sancov.c
91 * when dynFile input seed is replaced.
92 */
93 hfuzz->clearCovMetadata = true;
Anestis Bechtsoudis1dd19232015-12-30 13:11:06 +020094}
95
Robert Swiecki6e08d462015-09-08 17:23:03 +020096static void fuzz_sigHandler(int sig)
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +000097{
Robert Swiecki81c6a0d2015-09-08 15:43:20 +020098 /* We should not terminate upon SIGALRM delivery */
99 if (sig == SIGALRM) {
100 return;
101 }
102
robert.swiecki@gmail.comcf4e8d02015-04-23 15:53:39 +0000103 fuzz_sigReceived = sig;
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +0000104}
105
robert.swiecki3bb518c2010-10-14 00:48:24 +0000106static void fuzz_getFileName(honggfuzz_t * hfuzz, char *fileName)
107{
robert.swieckiba512632011-01-28 11:57:26 +0000108 struct timeval tv;
109 gettimeofday(&tv, NULL);
110
Anestis Bechtsoudisd9680532015-09-06 17:37:05 +0300111 snprintf(fileName, PATH_MAX, "%s/.honggfuzz.%d.%lu.%llx.%s", hfuzz->workDir, (int)getpid(),
robert.swiecki@gmail.com6f319912015-02-28 05:01:37 +0000112 (unsigned long int)tv.tv_sec, (unsigned long long int)util_rndGet(0, 1ULL << 62),
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000113 hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000114}
115
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000116static bool fuzz_prepareFileDynamically(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000117{
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100118 {
119 MX_LOCK(&hfuzz->dynamicFile_mutex);
120 defer(MX_UNLOCK(&hfuzz->dynamicFile_mutex));
robert.swiecki@gmail.com41d8e052015-02-19 01:10:41 +0000121
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100122 /* If max dynamicFile iterations counter, pick new seed file when working with input file corpus */
123 if (hfuzz->inputFile &&
124 __sync_fetch_and_add(&hfuzz->dynFileIterExpire, 0UL) >= _HF_MAX_DYNFILE_ITER) {
125 size_t fileSz = files_readFileToBufMax(hfuzz->files[rnd_index], hfuzz->dynamicFileBest,
126 hfuzz->maxFileSz);
127 if (fileSz == 0) {
128 MX_UNLOCK(&hfuzz->dynamicFile_mutex);
129 LOG_E("Couldn't read '%s'", hfuzz->files[rnd_index]);
130 return false;
131 }
132 hfuzz->dynamicFileBestSz = fileSz;
133
134 /* Reset counter since new seed pick */
135 __sync_fetch_and_and(&hfuzz->dynFileIterExpire, 0UL);
136 fuzz_resetFeedbackCnts(hfuzz);
137
138 /*
139 * In order to have accurate comparison base for coverage, first iteration
140 * of a new seed is executed without mangling. Also workersBlock_mutex mutex
141 * is maintain until execution is finished to ensure that other threads will
142 * work against the same coverage data vs. original seed.
143 */
144 hfuzz->isDynFileLocked = true;
145 } else if (hfuzz->inputFile == NULL && (fuzz_isPerfCntsSet(hfuzz) == false)) {
146 /*
147 * When working with an empty input file corpus (allowed if perf feedback enabled for Linux archs),
148 * first iteration is executed without mangling. First iteration need to be executed by one thread
149 * blocking other workers from continuing until finished.
150 */
151 hfuzz->isDynFileLocked = true;
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000152 }
Anestis Bechtsoudis02b99be2015-12-27 11:53:01 +0200153
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100154 if (hfuzz->dynamicFileBestSz > hfuzz->maxFileSz) {
155 LOG_F("Current BEST file Sz > maxFileSz (%zu > %zu)", hfuzz->dynamicFileBestSz,
156 hfuzz->maxFileSz);
157 }
Anestis Bechtsoudisac054802016-01-07 23:48:06 +0200158
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100159 fuzzer->dynamicFileSz = hfuzz->dynamicFileBestSz;
160 memcpy(fuzzer->dynamicFile, hfuzz->dynamicFileBest, hfuzz->dynamicFileBestSz);
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000161 }
162
Robert Swiecki23ec02a2016-01-19 18:47:45 +0100163 /*
164 * true isDynFileLocked indicates first run for a new seed, so skip mangling
Anestis Bechtsoudis6ef24e42016-01-13 13:05:53 +0200165 * without unlocking threads block mutex.
166 */
Anestis Bechtsoudisac054802016-01-07 23:48:06 +0200167 MX_LOCK(&hfuzz->workersBlock_mutex);
Anestis Bechtsoudisa1f8a032016-01-14 16:45:30 +0200168 if (hfuzz->isDynFileLocked) {
Anestis Bechtsoudisac054802016-01-07 23:48:06 +0200169 goto skipMangling;
170 }
171 MX_UNLOCK(&hfuzz->workersBlock_mutex);
172
Robert Swiecki23ec02a2016-01-19 18:47:45 +0100173 /*
Anestis Bechtsoudis25262b32015-11-07 22:39:47 +0200174 * if flip rate is 0.0, early abort file mangling. This will leave perf counters
175 * with values equal to dry runs against input corpus.
176 */
Anestis Bechtsoudis4e35c672015-12-28 15:00:42 +0200177 if (hfuzz->flipRate == 0.0L) {
Anestis Bechtsoudis25262b32015-11-07 22:39:47 +0200178 goto skipMangling;
179 }
Anestis Bechtsoudisac054802016-01-07 23:48:06 +0200180
Anestis Bechtsoudis6ef24e42016-01-13 13:05:53 +0200181 mangle_Resize(hfuzz, fuzzer->dynamicFile, &fuzzer->dynamicFileSz);
182 mangle_mangleContent(hfuzz, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000183
Anestis Bechtsoudis25262b32015-11-07 22:39:47 +0200184 skipMangling:
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +0000185 if (files_writeBufToFile
robert.swiecki@gmail.com62e34ae2015-03-05 03:39:32 +0000186 (fuzzer->fileName, fuzzer->dynamicFile, fuzzer->dynamicFileSz,
187 O_WRONLY | O_CREAT | O_EXCL | O_TRUNC) == false) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200188 LOG_E("Couldn't write buffer to file '%s'", fuzzer->fileName);
robert.swiecki@gmail.com3b6c6292015-02-26 11:48:46 +0000189 return false;
190 }
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000191
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000192 return true;
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000193}
194
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +0000195static bool fuzz_prepareFile(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000196{
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +0000197 size_t fileSz =
198 files_readFileToBufMax(hfuzz->files[rnd_index], fuzzer->dynamicFile, hfuzz->maxFileSz);
199 if (fileSz == 0UL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200200 LOG_E("Couldn't read contents of '%s'", hfuzz->files[rnd_index]);
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000201 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000202 }
203
Anestis Bechtsoudis25262b32015-11-07 22:39:47 +0200204 /* If flip rate is 0.0, early abort file mangling */
205 if (hfuzz->flipRate != 0.0L) {
206 mangle_Resize(hfuzz, fuzzer->dynamicFile, &fileSz);
207 mangle_mangleContent(hfuzz, fuzzer->dynamicFile, fileSz);
208 }
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000209
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +0000210 if (files_writeBufToFile
robert.swiecki@gmail.com62e34ae2015-03-05 03:39:32 +0000211 (fuzzer->fileName, fuzzer->dynamicFile, fileSz, O_WRONLY | O_CREAT | O_EXCL) == false) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200212 LOG_E("Couldn't write buffer to file '%s'", fuzzer->fileName);
robert.swiecki@gmail.come7680522015-02-22 22:22:37 +0000213 return false;
214 }
215
robert.swiecki3bb518c2010-10-14 00:48:24 +0000216 return true;
217}
218
robert.swiecki@gmail.com20851202015-03-01 01:48:15 +0000219static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000220{
Robert Swieckie48811e2016-03-09 18:31:19 +0100221 {
222 int dstfd = open(fuzzer->fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
223 if (dstfd == -1) {
224 PLOG_E("Couldn't create a temporary file '%s'", fuzzer->fileName);
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000225 return false;
226 }
Robert Swieckie48811e2016-03-09 18:31:19 +0100227 defer(close(dstfd));
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000228
Robert Swieckie48811e2016-03-09 18:31:19 +0100229 LOG_D("Created '%s' as an input file", fuzzer->fileName);
230
231 if (hfuzz->inputFile) {
232 size_t fileSz = files_readFileToBufMax(hfuzz->files[rnd_index], fuzzer->dynamicFile,
233 hfuzz->maxFileSz);
234 if (fileSz == 0UL) {
235 LOG_E("Couldn't read '%s'", hfuzz->files[rnd_index]);
236 unlink(fuzzer->fileName);
237 return false;
238 }
239
240 if (files_writeToFd(dstfd, fuzzer->dynamicFile, fileSz) == false) {
241 unlink(fuzzer->fileName);
242 return false;
243 }
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000244 }
robert.swiecki3d505e22010-10-14 01:17:17 +0000245
Robert Swieckie48811e2016-03-09 18:31:19 +0100246 }
robert.swiecki3d505e22010-10-14 01:17:17 +0000247
Anestis Bechtsoudis3541b472015-10-08 09:52:44 -0700248 pid_t pid = arch_fork(hfuzz);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000249 if (pid == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200250 PLOG_E("Couldn't fork");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000251 return false;
252 }
253
254 if (!pid) {
255 /*
robert.swiecki@gmail.comcdf18f92015-02-11 22:22:18 +0000256 * child performs the external file modifications
robert.swiecki3bb518c2010-10-14 00:48:24 +0000257 */
robert.swiecki@gmail.com20851202015-03-01 01:48:15 +0000258 execl(hfuzz->externalCommand, hfuzz->externalCommand, fuzzer->fileName, NULL);
Robert Swieckic8c32db2015-10-09 18:06:22 +0200259 PLOG_F("Couldn't execute '%s %s'", hfuzz->externalCommand, fuzzer->fileName);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000260 return false;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000261 }
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000262
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000263 /*
264 * parent waits until child is done fuzzing the input file
265 */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000266 int childStatus;
267 int flags = 0;
robert.swiecki@gmail.coma2291182015-02-13 16:56:27 +0000268#if defined(__WNOTHREAD)
269 flags |= __WNOTHREAD;
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000270#endif /* defined(__WNOTHREAD) */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000271 while (wait4(pid, &childStatus, flags, NULL) != pid) ;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000272 if (WIFEXITED(childStatus)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200273 LOG_D("External command exited with status %d", WEXITSTATUS(childStatus));
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000274 return true;
275 }
276 if (WIFSIGNALED(childStatus)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200277 LOG_E("External command terminated with signal %d", WTERMSIG(childStatus));
robert.swiecki3d505e22010-10-14 01:17:17 +0000278 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000279 }
Robert Swieckic8c32db2015-10-09 18:06:22 +0200280 LOG_F("External command terminated abnormally, status: %d", childStatus);
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000281 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000282
283 abort(); /* NOTREACHED */
284}
285
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300286static bool fuzz_runVerifier(honggfuzz_t * hfuzz, fuzzer_t * crashedFuzzer)
287{
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300288 int crashFd = -1;
289 uint8_t *crashBuf = NULL;
290 off_t crashFileSz = 0;
291
292 crashBuf = files_mapFile(crashedFuzzer->crashFileName, &crashFileSz, &crashFd, false);
293 if (crashBuf == NULL) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700294 LOG_E("Couldn't open and map '%s' in R/O mode", crashedFuzzer->crashFileName);
Robert Swieckie48811e2016-03-09 18:31:19 +0100295 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300296 }
Robert Swieckie48811e2016-03-09 18:31:19 +0100297 defer(munmap(crashBuf, crashFileSz));
298 defer(close(crashFd));
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300299
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700300 LOG_I("Launching verifier for %" PRIx64 " hash", crashedFuzzer->backtrace);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300301 for (int i = 0; i < _HF_VERIFIER_ITER; i++) {
302 fuzzer_t vFuzzer = {
303 .pid = 0,
304 .timeStartedMillis = util_timeNowMillis(),
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300305 .crashFileName = {0},
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300306 .pc = 0ULL,
307 .backtrace = 0ULL,
308 .access = 0ULL,
309 .exception = 0,
310 .dynamicFileSz = 0,
311 .dynamicFile = NULL,
312 .hwCnts = {
313 .cpuInstrCnt = 0ULL,
314 .cpuBranchCnt = 0ULL,
Jagger39bd2b02016-02-04 01:16:15 +0100315 .cpuBtsBlockCnt = 0ULL,
316 .cpuBtsEdgeCnt = 0ULL,
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300317 .customCnt = 0ULL,
318 },
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200319 .sanCovCnts = {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200320 .hitBBCnt = 0ULL,
321 .totalBBCnt = 0ULL,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200322 .dsoCnt = 0ULL,
323 .iDsoCnt = 0ULL,
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200324 .newBBCnt = 0ULL,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200325 .crashesCnt = 0ULL,
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200326 },
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300327 .report = {'\0'},
Anestis Bechtsoudis6b9e83d2015-10-02 11:10:50 -0700328 .mainWorker = false
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300329 };
330
331 fuzz_getFileName(hfuzz, vFuzzer.fileName);
332 if (files_writeBufToFile
333 (vFuzzer.fileName, crashBuf, crashFileSz, O_WRONLY | O_CREAT | O_EXCL) == false) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700334 LOG_E("Couldn't write buffer to file '%s'", vFuzzer.fileName);
Robert Swieckie48811e2016-03-09 18:31:19 +0100335 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300336 }
337
Anestis Bechtsoudis3541b472015-10-08 09:52:44 -0700338 vFuzzer.pid = arch_fork(hfuzz);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300339 if (vFuzzer.pid == -1) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700340 PLOG_F("Couldn't fork");
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300341 return false;
342 }
343
344 if (!vFuzzer.pid) {
345 if (!arch_launchChild(hfuzz, crashedFuzzer->crashFileName)) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700346 LOG_E("Error launching verifier child process");
Robert Swieckie48811e2016-03-09 18:31:19 +0100347 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300348 }
349 }
350
351 arch_reapChild(hfuzz, &vFuzzer);
352 unlink(vFuzzer.fileName);
353
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300354 /* If stack hash doesn't match skip name tag and exit */
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300355 if (crashedFuzzer->backtrace != vFuzzer.backtrace) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700356 LOG_D("Verifier stack hash mismatch");
Robert Swieckie48811e2016-03-09 18:31:19 +0100357 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300358 }
359 }
360
361 /* Workspace is inherited, just append a extra suffix */
362 char verFile[PATH_MAX] = { 0 };
363 snprintf(verFile, sizeof(verFile), "%s.verified", crashedFuzzer->crashFileName);
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300364
Anestis Bechtsoudisd86e6602015-11-07 18:34:06 +0200365 /* Copy file with new suffix & remove original copy */
366 bool dstFileExists = false;
367 if (files_copyFile(crashedFuzzer->crashFileName, verFile, &dstFileExists)) {
368 LOG_I("Successfully verified, saving as (%s)", verFile);
369 __sync_fetch_and_add(&hfuzz->verifiedCrashesCnt, 1UL);
370 unlink(crashedFuzzer->crashFileName);
371 } else {
372 if (dstFileExists) {
373 LOG_I("It seems that '%s' already exists, skipping", verFile);
374 } else {
375 LOG_E("Couldn't copy '%s' to '%s'", crashedFuzzer->crashFileName, verFile);
Robert Swieckie48811e2016-03-09 18:31:19 +0100376 return false;
Anestis Bechtsoudisd86e6602015-11-07 18:34:06 +0200377 }
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300378 }
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300379
Robert Swieckie48811e2016-03-09 18:31:19 +0100380 return true;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300381}
382
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200383static void fuzz_perfFeedback(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
384{
385 LOG_D
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200386 ("File size (New/Best): %zu/%zu, Perf feedback (instr,branch,block,block-edge,custom): Best: [%"
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200387 PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 "] / New: [%" PRIu64 ",%" PRIu64
388 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 "]", fuzzer->dynamicFileSz,
389 hfuzz->dynamicFileBestSz, hfuzz->hwCnts.cpuInstrCnt, hfuzz->hwCnts.cpuBranchCnt,
Jagger39bd2b02016-02-04 01:16:15 +0100390 hfuzz->hwCnts.cpuBtsBlockCnt, hfuzz->hwCnts.cpuBtsEdgeCnt, hfuzz->hwCnts.customCnt,
391 fuzzer->hwCnts.cpuInstrCnt, fuzzer->hwCnts.cpuBranchCnt, fuzzer->hwCnts.cpuBtsBlockCnt,
392 fuzzer->hwCnts.cpuBtsEdgeCnt, fuzzer->hwCnts.customCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200393
394 MX_LOCK(&hfuzz->dynamicFile_mutex);
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100395 defer(MX_UNLOCK(&hfuzz->dynamicFile_mutex));
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200396
397 int64_t diff0 = hfuzz->hwCnts.cpuInstrCnt - fuzzer->hwCnts.cpuInstrCnt;
398 int64_t diff1 = hfuzz->hwCnts.cpuBranchCnt - fuzzer->hwCnts.cpuBranchCnt;
Jagger39bd2b02016-02-04 01:16:15 +0100399 int64_t diff2 = hfuzz->hwCnts.cpuBtsBlockCnt - fuzzer->hwCnts.cpuBtsBlockCnt;
400 int64_t diff3 = hfuzz->hwCnts.cpuBtsEdgeCnt - fuzzer->hwCnts.cpuBtsEdgeCnt;
Jaggerd7c6ae62016-02-05 03:24:10 +0100401 int64_t diff4 = hfuzz->hwCnts.cpuIptBlockCnt - fuzzer->hwCnts.cpuIptBlockCnt;
Jagger0d2727a2016-02-08 02:08:42 +0100402 int64_t diff5 = hfuzz->hwCnts.customCnt - fuzzer->hwCnts.customCnt;
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200403
Jagger0d2727a2016-02-08 02:08:42 +0100404 if (diff0 < 0 || diff1 < 0 || diff2 < 0 || diff3 < 0 || diff4 < 0 || diff5 < 0) {
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200405
Jagger39bd2b02016-02-04 01:16:15 +0100406 LOG_I("New: (Size New,Old): %zu,%zu, Perf (Cur,New): "
Jagger0d2727a2016-02-08 02:08:42 +0100407 "%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64
408 ",%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64,
Jagger39bd2b02016-02-04 01:16:15 +0100409 fuzzer->dynamicFileSz, hfuzz->dynamicFileBestSz,
410 hfuzz->hwCnts.cpuInstrCnt, hfuzz->hwCnts.cpuBranchCnt,
411 hfuzz->hwCnts.cpuBtsBlockCnt, hfuzz->hwCnts.cpuBtsEdgeCnt,
Jagger0d2727a2016-02-08 02:08:42 +0100412 hfuzz->hwCnts.cpuIptBlockCnt, hfuzz->hwCnts.customCnt,
Jagger39bd2b02016-02-04 01:16:15 +0100413 fuzzer->hwCnts.cpuInstrCnt, fuzzer->hwCnts.cpuBranchCnt,
414 fuzzer->hwCnts.cpuBtsBlockCnt, fuzzer->hwCnts.cpuBtsEdgeCnt,
Jagger0d2727a2016-02-08 02:08:42 +0100415 fuzzer->hwCnts.cpuIptBlockCnt, fuzzer->hwCnts.customCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200416
417 memcpy(hfuzz->dynamicFileBest, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
418
419 hfuzz->dynamicFileBestSz = fuzzer->dynamicFileSz;
420 hfuzz->hwCnts.cpuInstrCnt = fuzzer->hwCnts.cpuInstrCnt;
421 hfuzz->hwCnts.cpuBranchCnt = fuzzer->hwCnts.cpuBranchCnt;
Jagger39bd2b02016-02-04 01:16:15 +0100422 hfuzz->hwCnts.cpuBtsBlockCnt = fuzzer->hwCnts.cpuBtsBlockCnt;
423 hfuzz->hwCnts.cpuBtsEdgeCnt = fuzzer->hwCnts.cpuBtsEdgeCnt;
Jaggerd7c6ae62016-02-05 03:24:10 +0100424 hfuzz->hwCnts.cpuIptBlockCnt = fuzzer->hwCnts.cpuIptBlockCnt;
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200425 hfuzz->hwCnts.customCnt = fuzzer->hwCnts.customCnt;
426
Anestis Bechtsoudise84d2362015-12-27 12:43:08 +0200427 /* Reset counter if better coverage achieved */
428 __sync_fetch_and_and(&hfuzz->dynFileIterExpire, 0UL);
429
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200430 char currentBest[PATH_MAX], currentBestTmp[PATH_MAX];
431 snprintf(currentBest, PATH_MAX, "%s/CURRENT_BEST", hfuzz->workDir);
432 snprintf(currentBestTmp, PATH_MAX, "%s/.tmp.CURRENT_BEST", hfuzz->workDir);
433
434 if (files_writeBufToFile
435 (currentBestTmp, fuzzer->dynamicFile, fuzzer->dynamicFileSz,
436 O_WRONLY | O_CREAT | O_TRUNC)) {
437 rename(currentBestTmp, currentBest);
438 }
439 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200440}
441
442static void fuzz_sanCovFeedback(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
443{
444 LOG_D
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200445 ("File size (Best/New): %zu/%zu, SanCov feedback (bb,dso): Best: [%" PRIu64
446 ",%" PRIu64 "] / New: [%" PRIu64 ",%" PRIu64 "], newBBs:%" PRIu64,
447 hfuzz->dynamicFileBestSz, fuzzer->dynamicFileSz, hfuzz->sanCovCnts.hitBBCnt,
448 hfuzz->sanCovCnts.iDsoCnt, fuzzer->sanCovCnts.hitBBCnt, fuzzer->sanCovCnts.iDsoCnt,
449 fuzzer->sanCovCnts.newBBCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200450
451 MX_LOCK(&hfuzz->dynamicFile_mutex);
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100452 defer(MX_UNLOCK(&hfuzz->dynamicFile_mutex));
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200453
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200454 /* abs diff of total BBs between global counter for chosen seed & current run */
455 uint64_t totalBBsDiff;
456 if (hfuzz->sanCovCnts.hitBBCnt > fuzzer->sanCovCnts.hitBBCnt) {
457 totalBBsDiff = hfuzz->sanCovCnts.hitBBCnt - fuzzer->sanCovCnts.hitBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200458 } else {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200459 totalBBsDiff = fuzzer->sanCovCnts.hitBBCnt - hfuzz->sanCovCnts.hitBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200460 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200461
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200462 /*
463 * Keep mutated seed if:
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200464 * a) Newly discovered (not met before) BBs && total hit BBs not significantly dropped
465 * b) More instrumented code accessed (BB hit counter bigger)
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200466 * c) More instrumented DSOs loaded
Robert Swiecki23ec02a2016-01-19 18:47:45 +0100467 *
Anestis Bechtsoudisb78cf602016-01-07 13:10:50 +0200468 * TODO: (a) method can significantly assist to further improvements in interesting areas
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200469 * discovery if combined with seeds pool/queue support. If a runtime queue is maintained
470 * more interesting seeds can be saved between runs instead of instantly discarded
471 * based on current absolute elitism (only one mutated seed is promoted).
472 */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200473 if ((fuzzer->sanCovCnts.newBBCnt > 0 && fuzzer->sanCovCnts.newBBCnt >= totalBBsDiff) ||
474 hfuzz->sanCovCnts.hitBBCnt < fuzzer->sanCovCnts.hitBBCnt ||
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200475 hfuzz->sanCovCnts.iDsoCnt < fuzzer->sanCovCnts.iDsoCnt) {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200476 LOG_I("SanCov Update: file size (Cur,New): %zu,%zu, newBBs:%" PRIu64
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200477 ", counters (Cur,New): %" PRIu64 "/%" PRIu64 ",%" PRIu64 "/%" PRIu64,
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200478 hfuzz->dynamicFileBestSz, fuzzer->dynamicFileSz, fuzzer->sanCovCnts.newBBCnt,
479 hfuzz->sanCovCnts.hitBBCnt, hfuzz->sanCovCnts.iDsoCnt, fuzzer->sanCovCnts.hitBBCnt,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200480 fuzzer->sanCovCnts.iDsoCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200481
482 memcpy(hfuzz->dynamicFileBest, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
483
Anestis Bechtsoudis1fc7cd42015-12-26 17:54:15 +0200484 hfuzz->dynamicFileBestSz = fuzzer->dynamicFileSz;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200485 hfuzz->sanCovCnts.hitBBCnt = fuzzer->sanCovCnts.hitBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200486 hfuzz->sanCovCnts.dsoCnt = fuzzer->sanCovCnts.dsoCnt;
487 hfuzz->sanCovCnts.iDsoCnt = fuzzer->sanCovCnts.iDsoCnt;
488 hfuzz->sanCovCnts.crashesCnt += fuzzer->sanCovCnts.crashesCnt;
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200489 hfuzz->sanCovCnts.newBBCnt += fuzzer->sanCovCnts.newBBCnt;
Anestis Bechtsoudisb78cf602016-01-07 13:10:50 +0200490
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200491 if (hfuzz->sanCovCnts.totalBBCnt < fuzzer->sanCovCnts.totalBBCnt) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200492 /* Keep only the max value (for dlopen cases) to measure total target coverage */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200493 hfuzz->sanCovCnts.totalBBCnt = fuzzer->sanCovCnts.totalBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200494 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200495
Anestis Bechtsoudise84d2362015-12-27 12:43:08 +0200496 /* Reset counter if better coverage achieved */
497 __sync_fetch_and_and(&hfuzz->dynFileIterExpire, 0UL);
498
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200499 char currentBest[PATH_MAX], currentBestTmp[PATH_MAX];
500 snprintf(currentBest, PATH_MAX, "%s/CURRENT_BEST", hfuzz->workDir);
501 snprintf(currentBestTmp, PATH_MAX, "%s/.tmp.CURRENT_BEST", hfuzz->workDir);
502
503 if (files_writeBufToFile
504 (currentBestTmp, fuzzer->dynamicFile, fuzzer->dynamicFileSz,
505 O_WRONLY | O_CREAT | O_TRUNC)) {
506 rename(currentBestTmp, currentBest);
507 }
508 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200509}
510
Jagger190f0dc2015-09-05 16:41:22 +0200511static void fuzz_fuzzLoop(honggfuzz_t * hfuzz)
512{
513 fuzzer_t fuzzer = {
514 .pid = 0,
515 .timeStartedMillis = util_timeNowMillis(),
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300516 .crashFileName = {0},
Jagger190f0dc2015-09-05 16:41:22 +0200517 .pc = 0ULL,
518 .backtrace = 0ULL,
519 .access = 0ULL,
520 .exception = 0,
521 .dynamicFileSz = 0,
522 .dynamicFile = malloc(hfuzz->maxFileSz),
Jaggerb409ee12015-09-09 02:02:32 +0200523 .hwCnts = {
524 .cpuInstrCnt = 0ULL,
525 .cpuBranchCnt = 0ULL,
Jagger39bd2b02016-02-04 01:16:15 +0100526 .cpuBtsBlockCnt = 0ULL,
527 .cpuBtsEdgeCnt = 0ULL,
Jaggerb409ee12015-09-09 02:02:32 +0200528 .customCnt = 0ULL,
529 },
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200530 .sanCovCnts = {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200531 .hitBBCnt = 0ULL,
532 .totalBBCnt = 0ULL,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200533 .dsoCnt = 0ULL,
534 .iDsoCnt = 0ULL,
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200535 .newBBCnt = 0ULL,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200536 .crashesCnt = 0ULL,
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200537 },
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300538 .report = {'\0'},
Anestis Bechtsoudisa1f8a032016-01-14 16:45:30 +0200539 .mainWorker = true
Jagger190f0dc2015-09-05 16:41:22 +0200540 };
541 if (fuzzer.dynamicFile == NULL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200542 LOG_F("malloc(%zu) failed", hfuzz->maxFileSz);
Jagger190f0dc2015-09-05 16:41:22 +0200543 }
Robert Swieckifc35c5e2016-03-09 17:18:48 +0100544 defer(free(fuzzer.dynamicFile));
Jagger190f0dc2015-09-05 16:41:22 +0200545
Anestis Bechtsoudis2013f252015-11-07 22:03:31 +0200546 size_t rnd_index = util_rndGet(0, hfuzz->fileCnt - 1);
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200547
548 /* If dry run mode, pick the next file and not a random one */
549 if (hfuzz->flipRate == 0.0L && hfuzz->useVerifier) {
550 rnd_index = __sync_fetch_and_add(&hfuzz->lastCheckedFileIndex, 1UL);
551 }
552
Jagger190f0dc2015-09-05 16:41:22 +0200553 strncpy(fuzzer.origFileName, files_basename(hfuzz->files[rnd_index]), PATH_MAX);
554 fuzz_getFileName(hfuzz, fuzzer.fileName);
555
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200556 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE || hfuzz->useSanCov) {
Jagger190f0dc2015-09-05 16:41:22 +0200557 if (!fuzz_prepareFileDynamically(hfuzz, &fuzzer, rnd_index)) {
558 exit(EXIT_FAILURE);
559 }
560 } else if (hfuzz->externalCommand != NULL) {
561 if (!fuzz_prepareFileExternally(hfuzz, &fuzzer, rnd_index)) {
562 exit(EXIT_FAILURE);
563 }
564 } else {
565 if (!fuzz_prepareFile(hfuzz, &fuzzer, rnd_index)) {
566 exit(EXIT_FAILURE);
567 }
568 }
569
Robert Swiecki1df61a92015-10-08 17:26:06 +0200570 fuzzer.pid = arch_fork(hfuzz);
Jagger190f0dc2015-09-05 16:41:22 +0200571 if (fuzzer.pid == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200572 PLOG_F("Couldn't fork");
Jagger190f0dc2015-09-05 16:41:22 +0200573 exit(EXIT_FAILURE);
574 }
575
576 if (!fuzzer.pid) {
577 /*
578 * Ok, kill the parent if this fails
579 */
580 if (!arch_launchChild(hfuzz, fuzzer.fileName)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200581 LOG_E("Error launching child process, killing parent");
Jagger190f0dc2015-09-05 16:41:22 +0200582 exit(EXIT_FAILURE);
583 }
584 }
585
Robert Swieckic8c32db2015-10-09 18:06:22 +0200586 LOG_D("Launched new process, pid: %d, (concurrency: %zd)", fuzzer.pid, hfuzz->threadsMax);
Jagger190f0dc2015-09-05 16:41:22 +0200587
588 arch_reapChild(hfuzz, &fuzzer);
589 unlink(fuzzer.fileName);
590
591 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200592 fuzz_perfFeedback(hfuzz, &fuzzer);
593 } else if (hfuzz->useSanCov) {
594 fuzz_sanCovFeedback(hfuzz, &fuzzer);
Jagger190f0dc2015-09-05 16:41:22 +0200595 }
596
Robert Swiecki23ec02a2016-01-19 18:47:45 +0100597 /*
Anestis Bechtsoudisac054802016-01-07 23:48:06 +0200598 * If worker picked first iteration of new seed for dynFile, unlock the mutex
599 * so other threads can continue.
600 */
Anestis Bechtsoudisa1f8a032016-01-14 16:45:30 +0200601 if (hfuzz->isDynFileLocked) {
602 hfuzz->isDynFileLocked = false;
Anestis Bechtsoudisac054802016-01-07 23:48:06 +0200603 MX_UNLOCK(&hfuzz->workersBlock_mutex);
604 }
605
Anestis Bechtsoudisc45db7f2015-11-30 16:44:58 +0200606 if (hfuzz->useVerifier && (fuzzer.crashFileName[0] != 0) && fuzzer.backtrace) {
Anestis Bechtsoudis3085f222015-09-27 18:35:26 +0300607 if (!fuzz_runVerifier(hfuzz, &fuzzer)) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700608 LOG_I("Failed to verify %s", fuzzer.crashFileName);
Anestis Bechtsoudis3085f222015-09-27 18:35:26 +0300609 }
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300610 }
611
Jagger190f0dc2015-09-05 16:41:22 +0200612 report_Report(hfuzz, fuzzer.report);
Jagger190f0dc2015-09-05 16:41:22 +0200613}
614
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000615static void *fuzz_threadNew(void *arg)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000616{
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000617 honggfuzz_t *hfuzz = (honggfuzz_t *) arg;
Jaggerea39a8f2015-09-05 00:57:22 +0200618 for (;;) {
Anestis Bechtsoudis02b99be2015-12-27 11:53:01 +0200619 /* Dynamic file iteration counter for same seed */
620 __sync_fetch_and_add(&hfuzz->dynFileIterExpire, 1UL);
621
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200622 /* Check if dry run mode with verifier enabled */
623 if (hfuzz->flipRate == 0.0L && hfuzz->useVerifier) {
624 if (__sync_fetch_and_add(&hfuzz->mutationsCnt, 1UL) >= hfuzz->fileCnt) {
625 __sync_fetch_and_add(&hfuzz->threadsFinished, 1UL);
626 // All files checked, weak-up the main process
627 pthread_kill(fuzz_mainThread, SIGALRM);
628 return NULL;
629 }
630 }
631 /* Check for max iterations limit if set */
632 else if ((__sync_fetch_and_add(&hfuzz->mutationsCnt, 1UL) >= hfuzz->mutationsMax)
633 && hfuzz->mutationsMax) {
Jagger6aa6e712015-09-06 20:52:04 +0200634 __sync_fetch_and_add(&hfuzz->threadsFinished, 1UL);
Robert Swiecki81c6a0d2015-09-08 15:43:20 +0200635 // Wake-up the main process
Jagger6113c432015-09-24 05:00:28 +0200636 pthread_kill(fuzz_mainThread, SIGALRM);
Jaggerea39a8f2015-09-05 00:57:22 +0200637 return NULL;
638 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000639
Jagger190f0dc2015-09-05 16:41:22 +0200640 fuzz_fuzzLoop(hfuzz);
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000641 }
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000642}
643
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000644static void fuzz_runThread(honggfuzz_t * hfuzz, void *(*thread) (void *))
645{
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000646 pthread_attr_t attr;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000647
robert.swiecki@gmail.com6f5c2392015-02-16 18:13:09 +0000648 pthread_attr_init(&attr);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000649 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000650 pthread_attr_setstacksize(&attr, _HF_PTHREAD_STACKSIZE);
robert.swiecki@gmail.com011981f2015-02-17 19:06:44 +0000651 pthread_attr_setguardsize(&attr, (size_t) sysconf(_SC_PAGESIZE));
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000652
robert.swiecki@gmail.com01b6dd42015-02-16 18:11:28 +0000653 pthread_t t;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000654 if (pthread_create(&t, &attr, thread, (void *)hfuzz) < 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200655 PLOG_F("Couldn't create a new thread");
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000656 }
657
658 return;
659}
660
Jagger0764ad72015-09-06 01:11:08 +0200661bool fuzz_setupTimer(void)
662{
663 struct itimerval it = {
Robert Swiecki6e08d462015-09-08 17:23:03 +0200664 .it_value = {.tv_sec = 0,.tv_usec = 1},
Jagger0764ad72015-09-06 01:11:08 +0200665 .it_interval = {.tv_sec = 1,.tv_usec = 0},
666 };
667 if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200668 PLOG_E("setitimer(ITIMER_REAL)");
Jagger0764ad72015-09-06 01:11:08 +0200669 return false;
670 }
Jagger0764ad72015-09-06 01:11:08 +0200671 return true;
672}
673
robert.swiecki3bb518c2010-10-14 00:48:24 +0000674void fuzz_main(honggfuzz_t * hfuzz)
675{
Jagger6113c432015-09-24 05:00:28 +0200676 fuzz_mainThread = pthread_self();
677
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +0000678 struct sigaction sa = {
Robert Swiecki6e08d462015-09-08 17:23:03 +0200679 .sa_handler = fuzz_sigHandler,
680 .sa_flags = 0,
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +0000681 };
682 sigemptyset(&sa.sa_mask);
683 if (sigaction(SIGTERM, &sa, NULL) == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200684 PLOG_F("sigaction(SIGTERM) failed");
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +0000685 }
686 if (sigaction(SIGINT, &sa, NULL) == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200687 PLOG_F("sigaction(SIGINT) failed");
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +0000688 }
689 if (sigaction(SIGQUIT, &sa, NULL) == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200690 PLOG_F("sigaction(SIGQUIT) failed");
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +0000691 }
Robert Swiecki81c6a0d2015-09-08 15:43:20 +0200692 if (sigaction(SIGALRM, &sa, NULL) == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200693 PLOG_F("sigaction(SIGALRM) failed");
Robert Swiecki81c6a0d2015-09-08 15:43:20 +0200694 }
Jagger0764ad72015-09-06 01:11:08 +0200695 if (fuzz_setupTimer() == false) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200696 LOG_F("fuzz_setupTimer()");
Jagger0764ad72015-09-06 01:11:08 +0200697 }
robert.swiecki@gmail.come4683202015-04-02 00:10:52 +0000698
robert.swiecki@gmail.com956276a2015-04-16 16:51:52 +0000699 if (!arch_archInit(hfuzz)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200700 LOG_F("Couldn't prepare arch for fuzzing");
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000701 }
702
Jaggerea39a8f2015-09-05 00:57:22 +0200703 for (size_t i = 0; i < hfuzz->threadsMax; i++) {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000704 fuzz_runThread(hfuzz, fuzz_threadNew);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000705 }
robert.swiecki@gmail.com9c77bb12015-04-23 15:35:28 +0000706
Jaggerea39a8f2015-09-05 00:57:22 +0200707 for (;;) {
Jagger7acbf2e2015-09-06 20:02:32 +0200708 if (hfuzz->useScreen) {
709 display_display(hfuzz);
710 }
Jaggerea39a8f2015-09-05 00:57:22 +0200711 if (fuzz_sigReceived > 0) {
712 break;
713 }
Jagger6aa6e712015-09-06 20:52:04 +0200714 if (__sync_fetch_and_add(&hfuzz->threadsFinished, 0UL) >= hfuzz->threadsMax) {
Jaggerea39a8f2015-09-05 00:57:22 +0200715 break;
716 }
Robert Swiecki6e08d462015-09-08 17:23:03 +0200717 pause();
Jaggerea39a8f2015-09-05 00:57:22 +0200718 }
719
robert.swiecki@gmail.comcf4e8d02015-04-23 15:53:39 +0000720 if (fuzz_sigReceived > 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200721 LOG_I("Signal %d (%s) received, terminating", fuzz_sigReceived,
722 strsignal(fuzz_sigReceived));
robert.swiecki@gmail.comcf4e8d02015-04-23 15:53:39 +0000723 }
Jagger3e1f54a2015-09-06 21:15:52 +0200724
Anestis Bechtsoudis61b5ab12016-01-08 16:07:02 +0200725 /* Clean-up global buffers */
Anestis Bechtsoudis8d191002015-09-10 17:36:10 +0300726 free(hfuzz->files);
727 free(hfuzz->dynamicFileBest);
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300728 if (hfuzz->dictionary) {
Anestis Bechtsoudis70f2fbd2016-01-14 13:15:19 +0200729 for (size_t i = 0; i < hfuzz->dictionaryCnt; i++) {
730 free(hfuzz->dictionary[i]);
731 }
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300732 free(hfuzz->dictionary);
733 }
734 if (hfuzz->blacklist) {
735 free(hfuzz->blacklist);
736 }
Anestis Bechtsoudis61b5ab12016-01-08 16:07:02 +0200737 if (hfuzz->sanOpts.asanOpts) {
738 free(hfuzz->sanOpts.asanOpts);
739 }
740 if (hfuzz->sanOpts.ubsanOpts) {
741 free(hfuzz->sanOpts.ubsanOpts);
742 }
743 if (hfuzz->sanOpts.msanOpts) {
744 free(hfuzz->sanOpts.msanOpts);
745 }
Anestis Bechtsoudis7c88d7a2016-02-09 17:55:38 +0200746 if (hfuzz->pidCmd) {
747 free(hfuzz->pidCmd);
748 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000749}