blob: 690fe566d79133fc1e9408049e82a91d10f7dde1 [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 "fuzz.h"
27
28#include <errno.h>
29#include <fcntl.h>
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +000030#include <inttypes.h>
Robert Swiecki2af83ec2017-06-05 23:54:22 +020031#include <libgen.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 Swiecki10eeb0a2017-09-28 15:42:52 +020039#include <sys/mman.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000040#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>
robert.swiecki3bb518c2010-10-14 00:48:24 +000044#include <time.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000045#include <unistd.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000046
Robert Swieckid0fa62c2017-09-28 18:11:05 +020047#include "arch.h"
48#include "honggfuzz.h"
49#include "input.h"
Robert Swiecki246af3e2018-01-05 14:56:32 +010050#include "libhfcommon/common.h"
51#include "libhfcommon/files.h"
52#include "libhfcommon/log.h"
53#include "libhfcommon/util.h"
robert.swiecki@gmail.com36700b52015-02-22 05:03:16 +000054#include "mangle.h"
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +000055#include "report.h"
Robert Swieckiec7b8452017-06-01 13:25:56 +020056#include "sancov.h"
57#include "sanitizers.h"
dobinedf9f8d2018-01-21 13:57:02 +010058#include "socketfuzzer.h"
Robert Swiecki56276192018-01-21 15:43:02 +010059#include "subproc.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000060
Robert Swiecki0dde76d2017-11-16 19:25:44 +010061static time_t termTimeStamp = 0;
62
63bool fuzz_isTerminating(void) {
64 if (ATOMIC_GET(termTimeStamp) != 0) {
Robert Swiecki35978ac2017-11-16 18:00:53 +010065 return true;
66 }
67 return false;
68}
69
Robert Swiecki0dde76d2017-11-16 19:25:44 +010070void fuzz_setTerminating(void) {
71 if (ATOMIC_GET(termTimeStamp) != 0) {
Robert Swiecki35978ac2017-11-16 18:00:53 +010072 return;
73 }
Robert Swiecki0dde76d2017-11-16 19:25:44 +010074 ATOMIC_SET(termTimeStamp, time(NULL));
75}
76
77bool fuzz_shouldTerminate() {
78 if (ATOMIC_GET(termTimeStamp) == 0) {
79 return false;
80 }
81 if ((time(NULL) - ATOMIC_GET(termTimeStamp)) > 5) {
82 return true;
83 }
84 return false;
Robert Swiecki35978ac2017-11-16 18:00:53 +010085}
86
Robert Swieckifb8a5b62018-01-14 05:16:59 +010087static fuzzState_t fuzz_getState(honggfuzz_t* hfuzz) {
88 return ATOMIC_GET(hfuzz->state);
Robert Swieckia7841da2017-02-24 17:27:06 +010089}
90
Robert Swieckiced3eba2017-12-15 15:33:03 +010091static bool fuzz_writeCovFile(const char* dir, const uint8_t* data, size_t len) {
92 char fname[PATH_MAX];
93
94 uint64_t crc64f = util_CRC64(data, len);
95 uint64_t crc64r = util_CRC64Rev(data, len);
96 snprintf(fname, sizeof(fname), "%s/%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 ".honggfuzz.cov",
97 dir, crc64f, crc64r, (uint32_t)len);
98
Robert Swieckifff99812018-01-12 02:23:42 +010099 if (files_exists(fname)) {
Robert Swieckiced3eba2017-12-15 15:33:03 +0100100 LOG_D("File '%s' already exists in the output corpus directory '%s'", fname, dir);
101 return true;
102 }
103
104 LOG_D("Adding file '%s' to the corpus directory '%s'", fname, dir);
105
Robert Swieckifff99812018-01-12 02:23:42 +0100106 if (!files_writeBufToFile(fname, data, len, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC)) {
Robert Swieckiced3eba2017-12-15 15:33:03 +0100107 LOG_W("Couldn't write buffer to file '%s'", fname);
108 return false;
109 }
110
111 return true;
112}
113
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100114static void fuzz_addFileToFileQ(honggfuzz_t* hfuzz, const uint8_t* data, size_t len) {
Robert Swiecki36f7e512018-01-16 03:46:41 +0100115 ATOMIC_SET(hfuzz->timing.lastCovUpdate, time(NULL));
116
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200117 struct dynfile_t* dynfile = (struct dynfile_t*)util_Malloc(sizeof(struct dynfile_t));
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100118 dynfile->size = len;
119 dynfile->data = (uint8_t*)util_Malloc(len);
120 memcpy(dynfile->data, data, len);
Robert Swiecki37498fd2017-03-12 21:12:54 +0100121
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100122 MX_SCOPED_RWLOCK_WRITE(&hfuzz->dynfileq_mutex);
123 TAILQ_INSERT_TAIL(&hfuzz->dynfileq, dynfile, pointers);
124 hfuzz->dynfileqCnt++;
Robert Swieckif3534bb2016-03-14 18:55:10 +0100125
dobinedf9f8d2018-01-21 13:57:02 +0100126 if (hfuzz->socketFuzzer) {
127 /* Dont add coverage data to files in socketFuzzer mode */
128 return;
129 }
130
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100131 if (!fuzz_writeCovFile(hfuzz->io.covDirAll, data, len)) {
132 LOG_E("Couldn't save the coverage data to '%s'", hfuzz->io.covDirAll);
Robert Swieckiced3eba2017-12-15 15:33:03 +0100133 }
134
135 /* No need to add files to the new coverage dir, if this is just the dry-run phase */
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100136 if (fuzz_getState(hfuzz) == _HF_STATE_DYNAMIC_DRY_RUN || hfuzz->io.covDirNew == NULL) {
Jagger3c7e7ce2016-09-25 16:05:19 +0200137 return;
138 }
139
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100140 if (!fuzz_writeCovFile(hfuzz->io.covDirNew, data, len)) {
141 LOG_E("Couldn't save the new coverage data to '%s'", hfuzz->io.covDirNew);
142 }
143}
144
145static void fuzz_setDynamicMainState(run_t* run) {
146 /* All threads need to indicate willingness to switch to the DYNAMIC_MAIN state. Count them! */
147 static uint32_t cnt = 0;
148 ATOMIC_PRE_INC(cnt);
149
150 static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
151 MX_SCOPED_LOCK(&state_mutex);
152
153 if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_MAIN) {
154 return;
155 }
156
157 for (;;) {
158 /* Check if all threads have already reported in for changing state */
159 if (ATOMIC_GET(cnt) == run->global->threads.threadsMax) {
160 break;
161 }
162 if (fuzz_isTerminating()) {
163 return;
164 }
165 usleep(1000 * 10); /* Check every 10ms */
166 }
167
168 LOG_I("Entering phase 2/2: Dynamic Main");
169 ATOMIC_SET(run->global->state, _HF_STATE_DYNAMIC_MAIN);
170
171 /*
172 * If the initial fuzzing yielded no useful coverage, just add a single 1-byte file to the
173 * dynamic corpus, so the dynamic phase doesn't fail because of lack of useful inputs
174 */
175 if (run->global->dynfileqCnt == 0) {
176 fuzz_addFileToFileQ(run->global, (const uint8_t*)"\0", 1U);
Robert Swieckif3534bb2016-03-14 18:55:10 +0100177 }
178}
179
Robert Swieckid50ed422017-11-13 23:32:26 +0100180static void fuzz_perfFeedback(run_t* run) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100181 if (run->global->skipFeedbackOnTimeout && run->tmOutSignaled) {
Robert Swiecki53ec9e42017-02-15 20:34:27 +0100182 return;
183 }
184
Robert Swiecki0b566112017-10-17 17:39:07 +0200185 LOG_D("New file size: %zu, Perf feedback new/cur (instr,branch): %" PRIu64 "/%" PRIu64
186 "/%" PRIu64 "/%" PRIu64 ", BBcnt new/total: %" PRIu64 "/%" PRIu64,
Robert Swiecki78633d12017-11-13 23:24:55 +0100187 run->dynamicFileSz, run->linux.hwCnts.cpuInstrCnt, run->global->linux.hwCnts.cpuInstrCnt,
188 run->linux.hwCnts.cpuBranchCnt, run->global->linux.hwCnts.cpuBranchCnt,
189 run->linux.hwCnts.newBBCnt, run->global->linux.hwCnts.bbCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200190
Robert Swiecki78633d12017-11-13 23:24:55 +0100191 MX_SCOPED_LOCK(&run->global->feedback_mutex);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200192
Robert Swieckif2da05a2018-01-12 03:01:09 +0100193 uint64_t softCntPc = 0;
194 uint64_t softCntEdge = 0;
195 uint64_t softCntCmp = 0;
Robert Swiecki78633d12017-11-13 23:24:55 +0100196 if (run->global->bbFd != -1) {
197 softCntPc = ATOMIC_GET(run->global->feedback->pidFeedbackPc[run->fuzzNo]);
198 ATOMIC_CLEAR(run->global->feedback->pidFeedbackPc[run->fuzzNo]);
199 softCntEdge = ATOMIC_GET(run->global->feedback->pidFeedbackEdge[run->fuzzNo]);
200 ATOMIC_CLEAR(run->global->feedback->pidFeedbackEdge[run->fuzzNo]);
201 softCntCmp = ATOMIC_GET(run->global->feedback->pidFeedbackCmp[run->fuzzNo]);
202 ATOMIC_CLEAR(run->global->feedback->pidFeedbackCmp[run->fuzzNo]);
Jagger251d0192016-08-24 00:54:04 +0200203 }
Jaggerb01aaae2016-08-20 03:35:38 +0200204
Robert Swiecki78633d12017-11-13 23:24:55 +0100205 int64_t diff0 = run->global->linux.hwCnts.cpuInstrCnt - run->linux.hwCnts.cpuInstrCnt;
206 int64_t diff1 = run->global->linux.hwCnts.cpuBranchCnt - run->linux.hwCnts.cpuBranchCnt;
Jagger302c2ea2016-09-07 03:54:43 +0200207
Robert Swiecki7b19fe52018-01-12 03:56:42 +0100208 /* Any increase in coverage (edge, pc, cmp, hw) counters forces adding input to the corpus */
Robert Swieckid50ed422017-11-13 23:32:26 +0100209 if (run->linux.hwCnts.newBBCnt > 0 || softCntPc > 0 || softCntEdge > 0 || softCntCmp > 0 ||
210 diff0 < 0 || diff1 < 0) {
Robert Swiecki92ec8d22016-11-21 01:10:18 +0100211 if (diff0 < 0) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100212 run->global->linux.hwCnts.cpuInstrCnt = run->linux.hwCnts.cpuInstrCnt;
Robert Swiecki92ec8d22016-11-21 01:10:18 +0100213 }
214 if (diff1 < 0) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100215 run->global->linux.hwCnts.cpuBranchCnt = run->linux.hwCnts.cpuBranchCnt;
Robert Swiecki92ec8d22016-11-21 01:10:18 +0100216 }
Robert Swiecki78633d12017-11-13 23:24:55 +0100217 run->global->linux.hwCnts.bbCnt += run->linux.hwCnts.newBBCnt;
218 run->global->linux.hwCnts.softCntPc += softCntPc;
219 run->global->linux.hwCnts.softCntEdge += softCntEdge;
220 run->global->linux.hwCnts.softCntCmp += softCntCmp;
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200221
Robert Swieckie60f3532017-12-17 20:25:20 +0100222 LOG_I("Size:%zu (i,b,hw,edge,ip,cmp): %" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64
Robert Swiecki0b566112017-10-17 17:39:07 +0200223 "/%" PRIu64 "/%" PRIu64 ", Tot:%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64
224 "/%" PRIu64 "/%" PRIu64,
Robert Swieckie7294ca2017-11-11 02:46:32 +0100225 run->dynamicFileSz, run->linux.hwCnts.cpuInstrCnt, run->linux.hwCnts.cpuBranchCnt,
Robert Swieckie60f3532017-12-17 20:25:20 +0100226 run->linux.hwCnts.newBBCnt, softCntEdge, softCntPc, softCntCmp,
Robert Swiecki78633d12017-11-13 23:24:55 +0100227 run->global->linux.hwCnts.cpuInstrCnt, run->global->linux.hwCnts.cpuBranchCnt,
Robert Swieckie60f3532017-12-17 20:25:20 +0100228 run->global->linux.hwCnts.bbCnt, run->global->linux.hwCnts.softCntEdge,
229 run->global->linux.hwCnts.softCntPc, run->global->linux.hwCnts.softCntCmp);
Jagger395df022016-08-21 01:13:25 +0200230
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100231 fuzz_addFileToFileQ(run->global, run->dynamicFile, run->dynamicFileSz);
dobinedf9f8d2018-01-21 13:57:02 +0100232
Robert Swiecki56276192018-01-21 15:43:02 +0100233 if (run->global->socketFuzzer) {
dobinedf9f8d2018-01-21 13:57:02 +0100234 LOG_D("SocketFuzzer: fuzz: new BB (perf)");
235 fuzz_notifySocketFuzzerNewCov(run->global);
236 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200237 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200238}
239
Robert Swieckid50ed422017-11-13 23:32:26 +0100240static void fuzz_sanCovFeedback(run_t* run) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100241 if (run->global->skipFeedbackOnTimeout && run->tmOutSignaled) {
Robert Swiecki53ec9e42017-02-15 20:34:27 +0100242 return;
243 }
244
Robert Swiecki0b566112017-10-17 17:39:07 +0200245 LOG_D("File size (Best/New): %zu, SanCov feedback (bb,dso): Best: [%" PRIu64 ",%" PRIu64
246 "] / New: [%" PRIu64 ",%" PRIu64 "], newBBs:%" PRIu64,
Robert Swiecki78633d12017-11-13 23:24:55 +0100247 run->dynamicFileSz, run->global->sanCovCnts.hitBBCnt, run->global->sanCovCnts.iDsoCnt,
Robert Swieckie7294ca2017-11-11 02:46:32 +0100248 run->sanCovCnts.hitBBCnt, run->sanCovCnts.iDsoCnt, run->sanCovCnts.newBBCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200249
Robert Swiecki78633d12017-11-13 23:24:55 +0100250 MX_SCOPED_LOCK(&run->global->feedback_mutex);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200251
Robert Swiecki78633d12017-11-13 23:24:55 +0100252 int64_t diff0 = run->global->linux.hwCnts.cpuInstrCnt - run->linux.hwCnts.cpuInstrCnt;
253 int64_t diff1 = run->global->linux.hwCnts.cpuBranchCnt - run->linux.hwCnts.cpuBranchCnt;
Jaggerd5738372016-08-17 20:12:15 +0200254
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200255 /*
256 * Keep mutated seed if:
Robert Swiecki142f9412016-03-14 19:22:01 +0100257 * a) Newly discovered (not met before) BBs
258 * b) More instrumented DSOs loaded
Robert Swiecki23ec02a2016-01-19 18:47:45 +0100259 *
Anestis Bechtsoudisb78cf602016-01-07 13:10:50 +0200260 * TODO: (a) method can significantly assist to further improvements in interesting areas
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200261 * discovery if combined with seeds pool/queue support. If a runtime queue is maintained
262 * more interesting seeds can be saved between runs instead of instantly discarded
263 * based on current absolute elitism (only one mutated seed is promoted).
264 */
Jaggerd5738372016-08-17 20:12:15 +0200265
Robert Swieckid50ed422017-11-13 23:32:26 +0100266 bool newCov =
267 (run->sanCovCnts.newBBCnt > 0 || run->global->sanCovCnts.iDsoCnt < run->sanCovCnts.iDsoCnt);
Jaggerd5738372016-08-17 20:12:15 +0200268
Robert Swieckid158aac2016-11-01 23:14:12 +0100269 if (newCov || (diff0 < 0 || diff1 < 0)) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200270 LOG_I("SanCov Update: fsize:%zu, newBBs:%" PRIu64 ", (Cur,New): %" PRIu64 "/%" PRIu64
271 ",%" PRIu64 "/%" PRIu64,
Robert Swiecki78633d12017-11-13 23:24:55 +0100272 run->dynamicFileSz, run->sanCovCnts.newBBCnt, run->global->sanCovCnts.hitBBCnt,
273 run->global->sanCovCnts.iDsoCnt, run->sanCovCnts.hitBBCnt, run->sanCovCnts.iDsoCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200274
Robert Swiecki78633d12017-11-13 23:24:55 +0100275 run->global->sanCovCnts.hitBBCnt += run->sanCovCnts.newBBCnt;
276 run->global->sanCovCnts.dsoCnt = run->sanCovCnts.dsoCnt;
277 run->global->sanCovCnts.iDsoCnt = run->sanCovCnts.iDsoCnt;
278 run->global->sanCovCnts.crashesCnt += run->sanCovCnts.crashesCnt;
279 run->global->sanCovCnts.newBBCnt = run->sanCovCnts.newBBCnt;
Anestis Bechtsoudisb78cf602016-01-07 13:10:50 +0200280
Robert Swiecki78633d12017-11-13 23:24:55 +0100281 if (run->global->sanCovCnts.totalBBCnt < run->sanCovCnts.totalBBCnt) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200282 /* Keep only the max value (for dlopen cases) to measure total target coverage */
Robert Swiecki78633d12017-11-13 23:24:55 +0100283 run->global->sanCovCnts.totalBBCnt = run->sanCovCnts.totalBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200284 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200285
Robert Swiecki78633d12017-11-13 23:24:55 +0100286 run->global->linux.hwCnts.cpuInstrCnt = run->linux.hwCnts.cpuInstrCnt;
287 run->global->linux.hwCnts.cpuBranchCnt = run->linux.hwCnts.cpuBranchCnt;
Jaggerd5738372016-08-17 20:12:15 +0200288
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100289 fuzz_addFileToFileQ(run->global, run->dynamicFile, run->dynamicFileSz);
dobinedf9f8d2018-01-21 13:57:02 +0100290
Robert Swiecki56276192018-01-21 15:43:02 +0100291 if (run->global->socketFuzzer) {
dobinedf9f8d2018-01-21 13:57:02 +0100292 LOG_D("SocketFuzzer: fuzz: new BB (cov)");
293 fuzz_notifySocketFuzzerNewCov(run->global);
294 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200295 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200296}
297
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100298/* Return value indicates whether report file should be updated with the current verified crash */
Robert Swiecki9badb552018-01-12 01:42:08 +0100299static bool fuzz_runVerifier(run_t* run) {
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100300 if (!run->crashFileName[0] || !run->backtrace) {
301 return false;
302 }
303
Robert Swiecki9badb552018-01-12 01:42:08 +0100304 uint64_t backtrace = run->backtrace;
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100305
Robert Swiecki9badb552018-01-12 01:42:08 +0100306 char origCrashPath[PATH_MAX];
307 snprintf(origCrashPath, sizeof(origCrashPath), "%s", run->crashFileName);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100308 /* Workspace is inherited, just append a extra suffix */
309 char verFile[PATH_MAX];
310 snprintf(verFile, sizeof(verFile), "%s.verified", origCrashPath);
311
312 if (files_exists(verFile)) {
Robert Swiecki965af7f2018-01-12 02:30:14 +0100313 LOG_D("Crash file to verify '%s' is already verified as '%s'", origCrashPath, verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100314 return false;
315 }
Robert Swiecki9badb552018-01-12 01:42:08 +0100316
317 for (int i = 0; i < _HF_VERIFIER_ITER; i++) {
Robert Swieckic4b573f2018-01-12 19:48:24 +0100318 LOG_I("Launching verifier for HASH: %" PRIx64 " (iteration: %d out of %d)", run->backtrace,
319 i + 1, _HF_VERIFIER_ITER);
Robert Swieckif2da05a2018-01-12 03:01:09 +0100320 run->timeStartedMillis = 0;
321 run->backtrace = 0;
322 run->access = 0;
Robert Swiecki9badb552018-01-12 01:42:08 +0100323 run->exception = 0;
Robert Swiecki9badb552018-01-12 01:42:08 +0100324 run->mainWorker = false;
Robert Swiecki9badb552018-01-12 01:42:08 +0100325
326 if (!subproc_Run(run)) {
327 LOG_F("subproc_Run()");
328 }
329
330 /* If stack hash doesn't match skip name tag and exit */
331 if (run->backtrace != backtrace) {
332 LOG_E("Verifier stack mismatch: (original) %" PRIx64 " != (new) %" PRIx64, backtrace,
333 run->backtrace);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100334 run->backtrace = backtrace;
335 return true;
Robert Swiecki9badb552018-01-12 01:42:08 +0100336 }
Robert Swiecki17b37eb2018-01-12 13:47:12 +0100337
Robert Swieckic4b573f2018-01-12 19:48:24 +0100338 LOG_I("Verifier for HASH: %" PRIx64 " (iteration: %d, left: %d). MATCH!", run->backtrace,
339 i + 1, _HF_VERIFIER_ITER - i - 1);
Robert Swiecki9badb552018-01-12 01:42:08 +0100340 }
341
Robert Swiecki9badb552018-01-12 01:42:08 +0100342 /* Copy file with new suffix & remove original copy */
343 int fd = TEMP_FAILURE_RETRY(open(verFile, O_CREAT | O_EXCL | O_WRONLY, 0600));
344 if (fd == -1 && errno == EEXIST) {
345 LOG_I("It seems that '%s' already exists, skipping", verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100346 return false;
Robert Swiecki9badb552018-01-12 01:42:08 +0100347 }
348 if (fd == -1) {
349 PLOG_E("Couldn't create '%s'", verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100350 return true;
Robert Swiecki9badb552018-01-12 01:42:08 +0100351 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100352 defer {
353 close(fd);
354 };
Robert Swiecki965af7f2018-01-12 02:30:14 +0100355 if (!files_writeToFd(fd, run->dynamicFile, run->dynamicFileSz)) {
356 LOG_E("Couldn't save verified file as '%s'", verFile);
357 unlink(verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100358 return true;
Robert Swiecki9badb552018-01-12 01:42:08 +0100359 }
360
361 LOG_I("Verified crash for HASH: %" PRIx64 " and saved it as '%s'", backtrace, verFile);
362 ATOMIC_POST_INC(run->global->cnts.verifiedCrashesCnt);
Robert Swiecki9badb552018-01-12 01:42:08 +0100363
364 return true;
365}
366
Robert Swiecki3ab16642018-01-12 18:08:37 +0100367static bool fuzz_fetchInput(run_t* run) {
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100368 if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_DRY_RUN) {
Robert Swiecki2bad0b42018-01-13 04:00:18 +0100369 run->mutationsPerRun = 0U;
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100370 if (input_prepareStaticFile(run, /* rewind= */ false)) {
Robert Swiecki3ab16642018-01-12 18:08:37 +0100371 return true;
372 }
Robert Swiecki308ebac2018-01-13 03:59:22 +0100373 fuzz_setDynamicMainState(run);
Robert Swiecki2bad0b42018-01-13 04:00:18 +0100374 run->mutationsPerRun = run->global->mutationsPerRun;
Robert Swiecki3ab16642018-01-12 18:08:37 +0100375 }
376
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100377 if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_MAIN) {
Robert Swieckia9e34ed2018-01-17 00:31:56 +0100378 if (run->global->exe.externalCommand) {
379 if (!input_prepareExternalFile(run)) {
380 LOG_E("input_prepareFileExternally() failed");
381 return false;
382 }
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100383 } else if (!input_prepareDynamicInput(run)) {
384 LOG_E("input_prepareFileDynamically() failed");
Robert Swiecki3ab16642018-01-12 18:08:37 +0100385 return false;
386 }
387 }
388
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100389 if (fuzz_getState(run->global) == _HF_STATE_STATIC) {
Robert Swieckia9e34ed2018-01-17 00:31:56 +0100390 if (run->global->exe.externalCommand) {
391 if (!input_prepareExternalFile(run)) {
392 LOG_E("input_prepareFileExternally() failed");
393 return false;
394 }
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100395 } else if (!input_prepareStaticFile(run, true /* rewind */)) {
396 LOG_E("input_prepareFile() failed");
Robert Swiecki3ab16642018-01-12 18:08:37 +0100397 return false;
398 }
399 }
400
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100401 if (run->global->exe.postExternalCommand && !input_postProcessFile(run)) {
402 LOG_E("input_postProcessFile() failed");
Robert Swiecki3ab16642018-01-12 18:08:37 +0100403 return false;
404 }
405
406 return true;
407}
408
Robert Swieckid50ed422017-11-13 23:32:26 +0100409static void fuzz_fuzzLoop(run_t* run) {
Robert Swieckie7294ca2017-11-11 02:46:32 +0100410 run->pid = 0;
Robert Swieckif2da05a2018-01-12 03:01:09 +0100411 run->timeStartedMillis = 0;
Robert Swieckie7294ca2017-11-11 02:46:32 +0100412 run->crashFileName[0] = '\0';
Robert Swieckif2da05a2018-01-12 03:01:09 +0100413 run->pc = 0;
414 run->backtrace = 0;
415 run->access = 0;
Robert Swieckie7294ca2017-11-11 02:46:32 +0100416 run->exception = 0;
417 run->report[0] = '\0';
418 run->mainWorker = true;
419 run->origFileName = "DYNAMIC";
Robert Swiecki78633d12017-11-13 23:24:55 +0100420 run->mutationsPerRun = run->global->mutationsPerRun;
Robert Swieckie7294ca2017-11-11 02:46:32 +0100421 run->dynamicFileSz = 0;
Robert Swiecki1f1a2f92018-01-15 15:26:37 +0100422 run->dynamicFileCopyFd = -1,
Robert Swieckia96d78d2016-03-14 16:50:50 +0100423
Robert Swieckif2da05a2018-01-12 03:01:09 +0100424 run->sanCovCnts.hitBBCnt = 0;
425 run->sanCovCnts.totalBBCnt = 0;
426 run->sanCovCnts.dsoCnt = 0;
427 run->sanCovCnts.newBBCnt = 0;
428 run->sanCovCnts.crashesCnt = 0;
Robert Swieckia96d78d2016-03-14 16:50:50 +0100429
Robert Swieckif2da05a2018-01-12 03:01:09 +0100430 run->linux.hwCnts.cpuInstrCnt = 0;
431 run->linux.hwCnts.cpuBranchCnt = 0;
432 run->linux.hwCnts.bbCnt = 0;
433 run->linux.hwCnts.newBBCnt = 0;
Jagger190f0dc2015-09-05 16:41:22 +0200434
Robert Swiecki3ab16642018-01-12 18:08:37 +0100435 if (!fuzz_fetchInput(run)) {
436 LOG_F("Cound't prepare input for fuzzing");
Robert Swiecki92a31362017-02-24 16:21:40 +0100437 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100438 if (!subproc_Run(run)) {
439 LOG_F("Couldn't run fuzzed command");
Jagger190f0dc2015-09-05 16:41:22 +0200440 }
441
Robert Swiecki78633d12017-11-13 23:24:55 +0100442 if (run->global->dynFileMethod != _HF_DYNFILE_NONE) {
443 fuzz_perfFeedback(run);
Robert Swiecki53ec9e42017-02-15 20:34:27 +0100444 }
Robert Swiecki78633d12017-11-13 23:24:55 +0100445 if (run->global->useSanCov) {
446 fuzz_sanCovFeedback(run);
Robert Swiecki0f937af2016-03-30 18:19:16 +0200447 }
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100448 if (run->global->useVerifier && !fuzz_runVerifier(run)) {
449 return;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300450 }
Robert Swiecki78633d12017-11-13 23:24:55 +0100451 report_Report(run);
Jagger190f0dc2015-09-05 16:41:22 +0200452}
453
Robert Swiecki56276192018-01-21 15:43:02 +0100454static void fuzz_fuzzLoopSocket(run_t* run) {
dobinedf9f8d2018-01-21 13:57:02 +0100455 run->pid = 0;
456 run->timeStartedMillis = 0;
457 run->crashFileName[0] = '\0';
458 run->pc = 0;
459 run->backtrace = 0;
460 run->access = 0;
461 run->exception = 0;
462 run->report[0] = '\0';
463 run->mainWorker = true;
464 run->origFileName = "DYNAMIC";
465 run->mutationsPerRun = run->global->mutationsPerRun;
466 run->dynamicFileSz = 0;
467 run->dynamicFileCopyFd = -1,
468
469 run->sanCovCnts.hitBBCnt = 0;
470 run->sanCovCnts.totalBBCnt = 0;
471 run->sanCovCnts.dsoCnt = 0;
472 run->sanCovCnts.newBBCnt = 0;
473 run->sanCovCnts.crashesCnt = 0;
474
475 run->linux.hwCnts.cpuInstrCnt = 0;
476 run->linux.hwCnts.cpuBranchCnt = 0;
477 run->linux.hwCnts.bbCnt = 0;
478 run->linux.hwCnts.newBBCnt = 0;
479
480 LOG_I("------------------------------------------------------");
481
482 /* First iteration: Start target
483 Other iterations: re-start target, if necessary
484 subproc_Run() will decide by itself if a restart is necessary, via
485 subproc_New()
486 */
487 LOG_D("------[ 1: subproc_run");
488 if (!subproc_Run(run)) {
489 LOG_W("Couldn't run server");
490 }
491
492 /* Tell the external fuzzer to send data to target
493 The fuzzer will notify us when finished; block until then.
494 */
495 LOG_D("------[ 2: fetch input");
496 if (!fuzz_waitForExternalInput(run)) {
497 /* Fuzzer could not connect to target, and told us to
498 restart it. Do it on the next iteration. */
Robert Swiecki56276192018-01-21 15:43:02 +0100499 LOG_D("------[ 2.1: Target down, will restart it");
dobinedf9f8d2018-01-21 13:57:02 +0100500 run->hasCrashed = true;
501 return;
502 }
503
504 LOG_D("------[ 3: feedback");
505 if (run->global->dynFileMethod != _HF_DYNFILE_NONE) {
506 fuzz_perfFeedback(run);
507 }
508 if (run->global->useSanCov) {
509 fuzz_sanCovFeedback(run);
510 }
511 if (run->global->useVerifier && !fuzz_runVerifier(run)) {
512 return;
513 }
514
515 report_Report(run);
516
517 /* Try to identify if the target crashed.
518 This information will be used in the next iteration of
519 this loop, to restart the target if necessary.
520 The fuzzer will be also notified.
521
522 Crash identification does not need to work 100%, as the external fuzzer
523 can also detect timeouts on the target server, and will
524 notify us. */
525 LOG_D("------[ 4: reap child");
526 arch_reapChild(run);
527}
528
Robert Swieckid50ed422017-11-13 23:32:26 +0100529static void* fuzz_threadNew(void* arg) {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200530 honggfuzz_t* hfuzz = (honggfuzz_t*)arg;
Robert Swiecki66b65122017-11-11 02:55:55 +0100531 unsigned int fuzzNo = ATOMIC_POST_INC(hfuzz->threads.threadsActiveCnt);
Robert Swiecki0ec98112017-02-03 02:08:14 +0100532 LOG_I("Launched new fuzzing thread, no. #%" PRId32, fuzzNo);
Anestis Bechtsoudis02b99be2015-12-27 11:53:01 +0200533
Robert Swieckie7294ca2017-11-11 02:46:32 +0100534 run_t run = {
Robert Swiecki78633d12017-11-13 23:24:55 +0100535 .global = hfuzz,
Robert Swieckidecf14b2016-03-31 15:09:28 +0200536 .pid = 0,
537 .persistentPid = 0,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100538 .dynfileqCurrent = NULL,
Robert Swiecki599dee12018-01-10 02:21:58 +0100539 .dynamicFile = NULL,
540 .dynamicFileFd = -1,
Jaggerfa3544a2016-08-30 02:55:55 +0200541 .fuzzNo = fuzzNo,
Jagger93253f72016-09-01 22:40:12 +0200542 .persistentSock = -1,
Robert Swiecki013bc9c2016-12-12 17:31:06 +0100543 .tmOutSignaled = false,
Robert Swiecki12800cd2016-03-31 15:38:10 +0200544
Robert Swieckib692f282016-08-25 16:21:08 +0200545 .linux.attachedPid = 0,
Robert Swieckidecf14b2016-03-31 15:09:28 +0200546 };
dobinedf9f8d2018-01-21 13:57:02 +0100547
548 // Do not try to handle input files with socketfuzzer
Robert Swiecki56276192018-01-21 15:43:02 +0100549 if (!hfuzz->socketFuzzer) {
550 if (!(run.dynamicFile = files_mapSharedMem(
551 hfuzz->maxFileSz, &run.dynamicFileFd, run.global->io.workDir))) {
dobinedf9f8d2018-01-21 13:57:02 +0100552 LOG_F("Couldn't create an input file of size: %zu", hfuzz->maxFileSz);
553 }
554 defer {
555 close(run.dynamicFileFd);
556 };
Robert Swiecki599dee12018-01-10 02:21:58 +0100557 }
Robert Swieckidecf14b2016-03-31 15:09:28 +0200558
Robert Swiecki78633d12017-11-13 23:24:55 +0100559 if (arch_archThreadInit(&run) == false) {
Robert Swiecki0f937af2016-03-30 18:19:16 +0200560 LOG_F("Could not initialize the thread");
561 }
562
Robert Swieckia96d78d2016-03-14 16:50:50 +0100563 for (;;) {
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200564 /* Check if dry run mode with verifier enabled */
Robert Swiecki56276192018-01-21 15:43:02 +0100565 if (run.global->mutationsPerRun == 0U && run.global->useVerifier && !hfuzz->socketFuzzer) {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100566 if (ATOMIC_POST_INC(run.global->cnts.mutationsCnt) >= run.global->io.fileCnt) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100567 ATOMIC_POST_INC(run.global->threads.threadsFinished);
Robert Swiecki069b48f2017-05-31 01:00:08 +0200568 break;
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200569 }
570 }
571 /* Check for max iterations limit if set */
Robert Swiecki2542dc02017-11-14 03:35:59 +0100572 else if ((ATOMIC_POST_INC(run.global->cnts.mutationsCnt) >= run.global->mutationsMax) &&
Robert Swieckid50ed422017-11-13 23:32:26 +0100573 run.global->mutationsMax) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100574 ATOMIC_POST_INC(run.global->threads.threadsFinished);
Robert Swiecki069b48f2017-05-31 01:00:08 +0200575 break;
Robert Swiecki8d01b012017-02-19 15:48:11 +0100576 }
577
Robert Swieckicfa81142018-01-15 02:19:26 +0100578 input_setSize(&run, run.global->maxFileSz);
dobinedf9f8d2018-01-21 13:57:02 +0100579 if (hfuzz->socketFuzzer) {
580 fuzz_fuzzLoopSocket(&run);
581 } else {
582 fuzz_fuzzLoop(&run);
583 }
584
Robert Swiecki0dde76d2017-11-16 19:25:44 +0100585 if (fuzz_isTerminating()) {
Robert Swiecki069b48f2017-05-31 01:00:08 +0200586 break;
587 }
588
Robert Swiecki2542dc02017-11-14 03:35:59 +0100589 if (run.global->exitUponCrash && ATOMIC_GET(run.global->cnts.crashesCnt) > 0) {
Robert Swiecki069b48f2017-05-31 01:00:08 +0200590 LOG_I("Seen a crash. Terminating all fuzzing threads");
Robert Swiecki0dde76d2017-11-16 19:25:44 +0100591 fuzz_setTerminating();
Robert Swiecki069b48f2017-05-31 01:00:08 +0200592 break;
593 }
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000594 }
Robert Swiecki069b48f2017-05-31 01:00:08 +0200595
596 LOG_I("Terminating thread no. #%" PRId32, fuzzNo);
Robert Swiecki78633d12017-11-13 23:24:55 +0100597 ATOMIC_POST_INC(run.global->threads.threadsFinished);
Robert Swiecki82c707c2017-11-14 16:36:23 +0100598 pthread_kill(run.global->threads.mainThread, SIGALRM);
Robert Swiecki069b48f2017-05-31 01:00:08 +0200599 return NULL;
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000600}
601
Robert Swieckid50ed422017-11-13 23:32:26 +0100602static void fuzz_runThread(honggfuzz_t* hfuzz, pthread_t* thread, void* (*thread_func)(void*)) {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000603 pthread_attr_t attr;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000604
robert.swiecki@gmail.com6f5c2392015-02-16 18:13:09 +0000605 pthread_attr_init(&attr);
Robert Swiecki33fb2842017-02-19 05:39:50 +0100606 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000607 pthread_attr_setstacksize(&attr, _HF_PTHREAD_STACKSIZE);
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200608 pthread_attr_setguardsize(&attr, (size_t)sysconf(_SC_PAGESIZE));
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000609
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200610 if (pthread_create(thread, &attr, thread_func, (void*)hfuzz) < 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200611 PLOG_F("Couldn't create a new thread");
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000612 }
613
Robert Swiecki33fb2842017-02-19 05:39:50 +0100614 pthread_attr_destroy(&attr);
615
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000616 return;
617}
618
Robert Swieckid50ed422017-11-13 23:32:26 +0100619void fuzz_threadsStart(honggfuzz_t* hfuzz, pthread_t* threads) {
robert.swiecki@gmail.com956276a2015-04-16 16:51:52 +0000620 if (!arch_archInit(hfuzz)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200621 LOG_F("Couldn't prepare arch for fuzzing");
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000622 }
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200623 if (!sanitizers_Init(hfuzz)) {
624 LOG_F("Couldn't prepare sanitizer options");
625 }
Jagger00265602016-03-10 02:36:27 +0100626 if (!sancov_Init(hfuzz)) {
627 LOG_F("Couldn't prepare sancov options");
628 }
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000629
dobinedf9f8d2018-01-21 13:57:02 +0100630 if (!hfuzz->socketFuzzer) {
631 // Dont do dry run
632 hfuzz->state = _HF_STATE_DYNAMIC_MAIN;
Robert Swieckia96d78d2016-03-14 16:50:50 +0100633 } else {
dobinedf9f8d2018-01-21 13:57:02 +0100634 if (hfuzz->useSanCov || hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
635 LOG_I("Entering phase 1/2: Dry Run");
636 hfuzz->state = _HF_STATE_DYNAMIC_DRY_RUN;
637 } else {
638 LOG_I("Entering phase: Static");
639 hfuzz->state = _HF_STATE_STATIC;
640 }
Robert Swieckia96d78d2016-03-14 16:50:50 +0100641 }
642
Robert Swiecki66b65122017-11-11 02:55:55 +0100643 for (size_t i = 0; i < hfuzz->threads.threadsMax; i++) {
Robert Swiecki33fb2842017-02-19 05:39:50 +0100644 fuzz_runThread(hfuzz, &threads[i], fuzz_threadNew);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000645 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000646}
Robert Swiecki33fb2842017-02-19 05:39:50 +0100647
Robert Swieckid50ed422017-11-13 23:32:26 +0100648void fuzz_threadsStop(honggfuzz_t* hfuzz, pthread_t* threads) {
Robert Swiecki66b65122017-11-11 02:55:55 +0100649 for (size_t i = 0; i < hfuzz->threads.threadsMax; i++) {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200650 void* retval;
Robert Swiecki33fb2842017-02-19 05:39:50 +0100651 if (pthread_join(threads[i], &retval) != 0) {
652 PLOG_F("Couldn't pthread_join() thread: %zu", i);
653 }
654 }
655 LOG_I("All threads done");
656}