blob: 564357a4beac56f4c10f531a38f2b9465dca94b3 [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 Swiecki46288f72018-02-27 17:28:47 +01006 * Authors: Robert Swiecki <swiecki@google.com>
7 * Felix Gröbert <groebert@google.com>
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00008 *
Robert Swiecki46288f72018-02-27 17:28:47 +01009 * Copyright 2010-2018 by Google Inc. All Rights Reserved.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000010 *
11 * Licensed under the Apache License, Version 2.0 (the "License"); you may
12 * not use this file except in compliance with the License. You may obtain
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000013 * a copy of the License at
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000014 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000015 * http://www.apache.org/licenses/LICENSE-2.0
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000016 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000017 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
20 * implied. See the License for the specific language governing
21 * permissions and limitations under the License.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000022 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000023 */
robert.swiecki3bb518c2010-10-14 00:48:24 +000024
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000025#include "fuzz.h"
26
27#include <errno.h>
28#include <fcntl.h>
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +000029#include <inttypes.h>
Robert Swiecki2af83ec2017-06-05 23:54:22 +020030#include <libgen.h>
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +000031#include <pthread.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000032#include <signal.h>
33#include <stddef.h>
34#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
Robert Swiecki10eeb0a2017-09-28 15:42:52 +020038#include <sys/mman.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000039#include <sys/param.h>
40#include <sys/stat.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000041#include <sys/time.h>
42#include <sys/types.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000043#include <time.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000044#include <unistd.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000045
Robert Swieckid0fa62c2017-09-28 18:11:05 +020046#include "arch.h"
47#include "honggfuzz.h"
48#include "input.h"
Robert Swiecki246af3e2018-01-05 14:56:32 +010049#include "libhfcommon/common.h"
50#include "libhfcommon/files.h"
51#include "libhfcommon/log.h"
52#include "libhfcommon/util.h"
robert.swiecki@gmail.com36700b52015-02-22 05:03:16 +000053#include "mangle.h"
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +000054#include "report.h"
Robert Swieckiec7b8452017-06-01 13:25:56 +020055#include "sanitizers.h"
dobinedf9f8d2018-01-21 13:57:02 +010056#include "socketfuzzer.h"
Robert Swiecki56276192018-01-21 15:43:02 +010057#include "subproc.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000058
Robert Swiecki0dde76d2017-11-16 19:25:44 +010059static time_t termTimeStamp = 0;
60
61bool fuzz_isTerminating(void) {
62 if (ATOMIC_GET(termTimeStamp) != 0) {
Robert Swiecki35978ac2017-11-16 18:00:53 +010063 return true;
64 }
65 return false;
66}
67
Robert Swiecki0dde76d2017-11-16 19:25:44 +010068void fuzz_setTerminating(void) {
69 if (ATOMIC_GET(termTimeStamp) != 0) {
Robert Swiecki35978ac2017-11-16 18:00:53 +010070 return;
71 }
Robert Swiecki0dde76d2017-11-16 19:25:44 +010072 ATOMIC_SET(termTimeStamp, time(NULL));
73}
74
75bool fuzz_shouldTerminate() {
76 if (ATOMIC_GET(termTimeStamp) == 0) {
77 return false;
78 }
79 if ((time(NULL) - ATOMIC_GET(termTimeStamp)) > 5) {
80 return true;
81 }
82 return false;
Robert Swiecki35978ac2017-11-16 18:00:53 +010083}
84
Robert Swieckifb8a5b62018-01-14 05:16:59 +010085static fuzzState_t fuzz_getState(honggfuzz_t* hfuzz) {
Robert Swiecki363510f2018-03-09 02:00:30 +010086 return ATOMIC_GET(hfuzz->feedback.state);
Robert Swieckia7841da2017-02-24 17:27:06 +010087}
88
Robert Swieckiced3eba2017-12-15 15:33:03 +010089static bool fuzz_writeCovFile(const char* dir, const uint8_t* data, size_t len) {
90 char fname[PATH_MAX];
91
92 uint64_t crc64f = util_CRC64(data, len);
93 uint64_t crc64r = util_CRC64Rev(data, len);
94 snprintf(fname, sizeof(fname), "%s/%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 ".honggfuzz.cov",
95 dir, crc64f, crc64r, (uint32_t)len);
96
Robert Swieckifff99812018-01-12 02:23:42 +010097 if (files_exists(fname)) {
Robert Swieckiced3eba2017-12-15 15:33:03 +010098 LOG_D("File '%s' already exists in the output corpus directory '%s'", fname, dir);
99 return true;
100 }
101
102 LOG_D("Adding file '%s' to the corpus directory '%s'", fname, dir);
103
Robert Swieckifff99812018-01-12 02:23:42 +0100104 if (!files_writeBufToFile(fname, data, len, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC)) {
Robert Swieckiced3eba2017-12-15 15:33:03 +0100105 LOG_W("Couldn't write buffer to file '%s'", fname);
106 return false;
107 }
108
109 return true;
110}
111
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100112static void fuzz_addFileToFileQ(honggfuzz_t* hfuzz, const uint8_t* data, size_t len) {
Robert Swiecki36f7e512018-01-16 03:46:41 +0100113 ATOMIC_SET(hfuzz->timing.lastCovUpdate, time(NULL));
114
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200115 struct dynfile_t* dynfile = (struct dynfile_t*)util_Malloc(sizeof(struct dynfile_t));
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100116 dynfile->size = len;
117 dynfile->data = (uint8_t*)util_Malloc(len);
118 memcpy(dynfile->data, data, len);
Robert Swiecki37498fd2017-03-12 21:12:54 +0100119
Robert Swiecki363510f2018-03-09 02:00:30 +0100120 MX_SCOPED_RWLOCK_WRITE(&hfuzz->io.dynfileq_mutex);
121 TAILQ_INSERT_TAIL(&hfuzz->io.dynfileq, dynfile, pointers);
122 hfuzz->io.dynfileqCnt++;
Robert Swieckif3534bb2016-03-14 18:55:10 +0100123
Robert Swiecki5e26bd92018-03-02 12:09:34 +0100124 if (hfuzz->socketFuzzer.enabled) {
Robert Swiecki5eeb29b2018-01-21 16:07:06 +0100125 /* Don't add coverage data to files in socketFuzzer mode */
dobinedf9f8d2018-01-21 13:57:02 +0100126 return;
127 }
128
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100129 if (!fuzz_writeCovFile(hfuzz->io.covDirAll, data, len)) {
130 LOG_E("Couldn't save the coverage data to '%s'", hfuzz->io.covDirAll);
Robert Swieckiced3eba2017-12-15 15:33:03 +0100131 }
132
133 /* 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 +0100134 if (fuzz_getState(hfuzz) == _HF_STATE_DYNAMIC_DRY_RUN || hfuzz->io.covDirNew == NULL) {
Jagger3c7e7ce2016-09-25 16:05:19 +0200135 return;
136 }
137
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100138 if (!fuzz_writeCovFile(hfuzz->io.covDirNew, data, len)) {
139 LOG_E("Couldn't save the new coverage data to '%s'", hfuzz->io.covDirNew);
140 }
141}
142
143static void fuzz_setDynamicMainState(run_t* run) {
144 /* All threads need to indicate willingness to switch to the DYNAMIC_MAIN state. Count them! */
145 static uint32_t cnt = 0;
146 ATOMIC_PRE_INC(cnt);
147
148 static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
149 MX_SCOPED_LOCK(&state_mutex);
150
151 if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_MAIN) {
152 return;
153 }
154
155 for (;;) {
156 /* Check if all threads have already reported in for changing state */
157 if (ATOMIC_GET(cnt) == run->global->threads.threadsMax) {
158 break;
159 }
160 if (fuzz_isTerminating()) {
161 return;
162 }
163 usleep(1000 * 10); /* Check every 10ms */
164 }
165
166 LOG_I("Entering phase 2/2: Dynamic Main");
Robert Swiecki94d314c2018-02-07 21:23:00 +0100167 snprintf(run->origFileName, sizeof(run->origFileName), "[DYNAMIC]");
Robert Swiecki363510f2018-03-09 02:00:30 +0100168 ATOMIC_SET(run->global->feedback.state, _HF_STATE_DYNAMIC_MAIN);
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100169
170 /*
171 * If the initial fuzzing yielded no useful coverage, just add a single 1-byte file to the
172 * dynamic corpus, so the dynamic phase doesn't fail because of lack of useful inputs
173 */
Robert Swiecki363510f2018-03-09 02:00:30 +0100174 if (run->global->io.dynfileqCnt == 0) {
Robert Swieckicc6b9292018-08-15 01:32:50 +0200175 const char* single_byte = run->global->cfg.only_printable ? " " : "\0";
plusune2635e52018-08-06 07:06:46 +0000176 fuzz_addFileToFileQ(run->global, (const uint8_t*)single_byte, 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 Swieckia5b918a2018-03-07 23:59:53 +0100181 if (run->global->feedback.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 Swieckia5b918a2018-03-07 23:59:53 +0100191 MX_SCOPED_LOCK(&run->global->feedback.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 Swieckia5b918a2018-03-07 23:59:53 +0100196 if (run->global->feedback.bbFd != -1) {
197 softCntPc = ATOMIC_GET(run->global->feedback.feedbackMap->pidFeedbackPc[run->fuzzNo]);
198 ATOMIC_CLEAR(run->global->feedback.feedbackMap->pidFeedbackPc[run->fuzzNo]);
199 softCntEdge = ATOMIC_GET(run->global->feedback.feedbackMap->pidFeedbackEdge[run->fuzzNo]);
200 ATOMIC_CLEAR(run->global->feedback.feedbackMap->pidFeedbackEdge[run->fuzzNo]);
201 softCntCmp = ATOMIC_GET(run->global->feedback.feedbackMap->pidFeedbackCmp[run->fuzzNo]);
202 ATOMIC_CLEAR(run->global->feedback.feedbackMap->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 Swiecki5e26bd92018-03-02 12:09:34 +0100233 if (run->global->socketFuzzer.enabled) {
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 Swiecki28cc4cb2018-01-12 02:18:29 +0100240/* Return value indicates whether report file should be updated with the current verified crash */
Robert Swiecki9badb552018-01-12 01:42:08 +0100241static bool fuzz_runVerifier(run_t* run) {
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100242 if (!run->crashFileName[0] || !run->backtrace) {
243 return false;
244 }
245
Robert Swiecki9badb552018-01-12 01:42:08 +0100246 uint64_t backtrace = run->backtrace;
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100247
Robert Swiecki9badb552018-01-12 01:42:08 +0100248 char origCrashPath[PATH_MAX];
249 snprintf(origCrashPath, sizeof(origCrashPath), "%s", run->crashFileName);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100250 /* Workspace is inherited, just append a extra suffix */
251 char verFile[PATH_MAX];
252 snprintf(verFile, sizeof(verFile), "%s.verified", origCrashPath);
253
254 if (files_exists(verFile)) {
Robert Swiecki965af7f2018-01-12 02:30:14 +0100255 LOG_D("Crash file to verify '%s' is already verified as '%s'", origCrashPath, verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100256 return false;
257 }
Robert Swiecki9badb552018-01-12 01:42:08 +0100258
259 for (int i = 0; i < _HF_VERIFIER_ITER; i++) {
Robert Swieckic4b573f2018-01-12 19:48:24 +0100260 LOG_I("Launching verifier for HASH: %" PRIx64 " (iteration: %d out of %d)", run->backtrace,
261 i + 1, _HF_VERIFIER_ITER);
Robert Swieckif2da05a2018-01-12 03:01:09 +0100262 run->timeStartedMillis = 0;
263 run->backtrace = 0;
264 run->access = 0;
Robert Swiecki9badb552018-01-12 01:42:08 +0100265 run->exception = 0;
Robert Swiecki9badb552018-01-12 01:42:08 +0100266 run->mainWorker = false;
Robert Swiecki9badb552018-01-12 01:42:08 +0100267
268 if (!subproc_Run(run)) {
269 LOG_F("subproc_Run()");
270 }
271
272 /* If stack hash doesn't match skip name tag and exit */
273 if (run->backtrace != backtrace) {
274 LOG_E("Verifier stack mismatch: (original) %" PRIx64 " != (new) %" PRIx64, backtrace,
275 run->backtrace);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100276 run->backtrace = backtrace;
277 return true;
Robert Swiecki9badb552018-01-12 01:42:08 +0100278 }
Robert Swiecki17b37eb2018-01-12 13:47:12 +0100279
Robert Swieckic4b573f2018-01-12 19:48:24 +0100280 LOG_I("Verifier for HASH: %" PRIx64 " (iteration: %d, left: %d). MATCH!", run->backtrace,
281 i + 1, _HF_VERIFIER_ITER - i - 1);
Robert Swiecki9badb552018-01-12 01:42:08 +0100282 }
283
Robert Swiecki9badb552018-01-12 01:42:08 +0100284 /* Copy file with new suffix & remove original copy */
285 int fd = TEMP_FAILURE_RETRY(open(verFile, O_CREAT | O_EXCL | O_WRONLY, 0600));
286 if (fd == -1 && errno == EEXIST) {
287 LOG_I("It seems that '%s' already exists, skipping", verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100288 return false;
Robert Swiecki9badb552018-01-12 01:42:08 +0100289 }
290 if (fd == -1) {
291 PLOG_E("Couldn't create '%s'", verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100292 return true;
Robert Swiecki9badb552018-01-12 01:42:08 +0100293 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100294 defer {
295 close(fd);
296 };
Robert Swiecki965af7f2018-01-12 02:30:14 +0100297 if (!files_writeToFd(fd, run->dynamicFile, run->dynamicFileSz)) {
298 LOG_E("Couldn't save verified file as '%s'", verFile);
299 unlink(verFile);
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100300 return true;
Robert Swiecki9badb552018-01-12 01:42:08 +0100301 }
302
303 LOG_I("Verified crash for HASH: %" PRIx64 " and saved it as '%s'", backtrace, verFile);
Robert Swieckiacdf0bd2019-02-17 02:42:04 +0100304 ATOMIC_PRE_INC(run->global->cnts.verifiedCrashesCnt);
Robert Swiecki9badb552018-01-12 01:42:08 +0100305
306 return true;
307}
308
Robert Swiecki3ab16642018-01-12 18:08:37 +0100309static bool fuzz_fetchInput(run_t* run) {
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100310 if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_DRY_RUN) {
Robert Swiecki2bad0b42018-01-13 04:00:18 +0100311 run->mutationsPerRun = 0U;
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100312 if (input_prepareStaticFile(run, /* rewind= */ false)) {
Robert Swiecki3ab16642018-01-12 18:08:37 +0100313 return true;
314 }
Robert Swiecki308ebac2018-01-13 03:59:22 +0100315 fuzz_setDynamicMainState(run);
Robert Swiecki04dcac32018-03-02 03:05:26 +0100316 run->mutationsPerRun = run->global->mutate.mutationsPerRun;
Robert Swiecki3ab16642018-01-12 18:08:37 +0100317 }
318
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100319 if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_MAIN) {
Robert Swieckia9e34ed2018-01-17 00:31:56 +0100320 if (run->global->exe.externalCommand) {
321 if (!input_prepareExternalFile(run)) {
322 LOG_E("input_prepareFileExternally() failed");
323 return false;
324 }
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100325 } else if (!input_prepareDynamicInput(run)) {
326 LOG_E("input_prepareFileDynamically() failed");
Robert Swiecki3ab16642018-01-12 18:08:37 +0100327 return false;
328 }
329 }
330
Robert Swieckifb8a5b62018-01-14 05:16:59 +0100331 if (fuzz_getState(run->global) == _HF_STATE_STATIC) {
Robert Swieckia9e34ed2018-01-17 00:31:56 +0100332 if (run->global->exe.externalCommand) {
333 if (!input_prepareExternalFile(run)) {
334 LOG_E("input_prepareFileExternally() failed");
335 return false;
336 }
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100337 } else if (!input_prepareStaticFile(run, true /* rewind */)) {
338 LOG_E("input_prepareFile() failed");
Robert Swiecki3ab16642018-01-12 18:08:37 +0100339 return false;
340 }
341 }
342
Robert Swiecki0f2c30a2018-01-13 14:03:39 +0100343 if (run->global->exe.postExternalCommand && !input_postProcessFile(run)) {
344 LOG_E("input_postProcessFile() failed");
Robert Swiecki3ab16642018-01-12 18:08:37 +0100345 return false;
346 }
347
348 return true;
349}
350
Robert Swieckid50ed422017-11-13 23:32:26 +0100351static void fuzz_fuzzLoop(run_t* run) {
Robert Swieckif2da05a2018-01-12 03:01:09 +0100352 run->timeStartedMillis = 0;
Robert Swieckie7294ca2017-11-11 02:46:32 +0100353 run->crashFileName[0] = '\0';
Robert Swieckif2da05a2018-01-12 03:01:09 +0100354 run->pc = 0;
355 run->backtrace = 0;
356 run->access = 0;
Robert Swieckie7294ca2017-11-11 02:46:32 +0100357 run->exception = 0;
358 run->report[0] = '\0';
359 run->mainWorker = true;
Robert Swiecki04dcac32018-03-02 03:05:26 +0100360 run->mutationsPerRun = run->global->mutate.mutationsPerRun;
Robert Swieckie7294ca2017-11-11 02:46:32 +0100361 run->dynamicFileSz = 0;
Robert Swiecki98e23372019-01-30 11:50:18 +0100362 run->dynamicFileCopyFd = -1;
363 run->tmOutSignaled = false;
Robert Swieckia96d78d2016-03-14 16:50:50 +0100364
Robert Swieckif2da05a2018-01-12 03:01:09 +0100365 run->linux.hwCnts.cpuInstrCnt = 0;
366 run->linux.hwCnts.cpuBranchCnt = 0;
367 run->linux.hwCnts.bbCnt = 0;
368 run->linux.hwCnts.newBBCnt = 0;
Jagger190f0dc2015-09-05 16:41:22 +0200369
Robert Swiecki3ab16642018-01-12 18:08:37 +0100370 if (!fuzz_fetchInput(run)) {
371 LOG_F("Cound't prepare input for fuzzing");
Robert Swiecki92a31362017-02-24 16:21:40 +0100372 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100373 if (!subproc_Run(run)) {
374 LOG_F("Couldn't run fuzzed command");
Jagger190f0dc2015-09-05 16:41:22 +0200375 }
376
Robert Swieckia5b918a2018-03-07 23:59:53 +0100377 if (run->global->feedback.dynFileMethod != _HF_DYNFILE_NONE) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100378 fuzz_perfFeedback(run);
Robert Swiecki53ec9e42017-02-15 20:34:27 +0100379 }
Robert Swieckia5b918a2018-03-07 23:59:53 +0100380 if (run->global->cfg.useVerifier && !fuzz_runVerifier(run)) {
Robert Swiecki28cc4cb2018-01-12 02:18:29 +0100381 return;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300382 }
Robert Swiecki78633d12017-11-13 23:24:55 +0100383 report_Report(run);
Jagger190f0dc2015-09-05 16:41:22 +0200384}
385
Robert Swiecki56276192018-01-21 15:43:02 +0100386static void fuzz_fuzzLoopSocket(run_t* run) {
dobinedf9f8d2018-01-21 13:57:02 +0100387 run->pid = 0;
388 run->timeStartedMillis = 0;
389 run->crashFileName[0] = '\0';
390 run->pc = 0;
391 run->backtrace = 0;
392 run->access = 0;
393 run->exception = 0;
394 run->report[0] = '\0';
395 run->mainWorker = true;
Robert Swiecki04dcac32018-03-02 03:05:26 +0100396 run->mutationsPerRun = run->global->mutate.mutationsPerRun;
dobinedf9f8d2018-01-21 13:57:02 +0100397 run->dynamicFileSz = 0;
Robert Swiecki98e23372019-01-30 11:50:18 +0100398 run->dynamicFileCopyFd = -1;
399 run->tmOutSignaled = false;
dobinedf9f8d2018-01-21 13:57:02 +0100400
dobinedf9f8d2018-01-21 13:57:02 +0100401 run->linux.hwCnts.cpuInstrCnt = 0;
402 run->linux.hwCnts.cpuBranchCnt = 0;
403 run->linux.hwCnts.bbCnt = 0;
404 run->linux.hwCnts.newBBCnt = 0;
405
406 LOG_I("------------------------------------------------------");
407
408 /* First iteration: Start target
409 Other iterations: re-start target, if necessary
410 subproc_Run() will decide by itself if a restart is necessary, via
411 subproc_New()
412 */
413 LOG_D("------[ 1: subproc_run");
414 if (!subproc_Run(run)) {
415 LOG_W("Couldn't run server");
416 }
417
418 /* Tell the external fuzzer to send data to target
419 The fuzzer will notify us when finished; block until then.
420 */
421 LOG_D("------[ 2: fetch input");
422 if (!fuzz_waitForExternalInput(run)) {
423 /* Fuzzer could not connect to target, and told us to
424 restart it. Do it on the next iteration. */
Robert Swiecki56276192018-01-21 15:43:02 +0100425 LOG_D("------[ 2.1: Target down, will restart it");
dobinedf9f8d2018-01-21 13:57:02 +0100426 return;
427 }
428
429 LOG_D("------[ 3: feedback");
Robert Swieckia5b918a2018-03-07 23:59:53 +0100430 if (run->global->feedback.dynFileMethod != _HF_DYNFILE_NONE) {
dobinedf9f8d2018-01-21 13:57:02 +0100431 fuzz_perfFeedback(run);
432 }
Robert Swieckia5b918a2018-03-07 23:59:53 +0100433 if (run->global->cfg.useVerifier && !fuzz_runVerifier(run)) {
dobinedf9f8d2018-01-21 13:57:02 +0100434 return;
435 }
436
437 report_Report(run);
dobinedf9f8d2018-01-21 13:57:02 +0100438}
439
Robert Swieckid50ed422017-11-13 23:32:26 +0100440static void* fuzz_threadNew(void* arg) {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200441 honggfuzz_t* hfuzz = (honggfuzz_t*)arg;
Robert Swiecki66b65122017-11-11 02:55:55 +0100442 unsigned int fuzzNo = ATOMIC_POST_INC(hfuzz->threads.threadsActiveCnt);
Robert Swiecki0ec98112017-02-03 02:08:14 +0100443 LOG_I("Launched new fuzzing thread, no. #%" PRId32, fuzzNo);
Anestis Bechtsoudis02b99be2015-12-27 11:53:01 +0200444
Robert Swieckie7294ca2017-11-11 02:46:32 +0100445 run_t run = {
Robert Swiecki78633d12017-11-13 23:24:55 +0100446 .global = hfuzz,
Robert Swieckidecf14b2016-03-31 15:09:28 +0200447 .pid = 0,
Robert Swieckibf8f8cc2017-11-09 00:42:50 +0100448 .dynfileqCurrent = NULL,
Robert Swiecki599dee12018-01-10 02:21:58 +0100449 .dynamicFile = NULL,
450 .dynamicFileFd = -1,
Jaggerfa3544a2016-08-30 02:55:55 +0200451 .fuzzNo = fuzzNo,
Jagger93253f72016-09-01 22:40:12 +0200452 .persistentSock = -1,
Robert Swiecki013bc9c2016-12-12 17:31:06 +0100453 .tmOutSignaled = false,
Robert Swiecki94d314c2018-02-07 21:23:00 +0100454 .origFileName = "[DYNAMIC]",
Robert Swieckidecf14b2016-03-31 15:09:28 +0200455 };
dobinedf9f8d2018-01-21 13:57:02 +0100456
Robert Swiecki5eeb29b2018-01-21 16:07:06 +0100457 /* Do not try to handle input files with socketfuzzer */
Robert Swiecki5e26bd92018-03-02 12:09:34 +0100458 if (!hfuzz->socketFuzzer.enabled) {
Robert Swieckie9231d62018-03-02 03:35:11 +0100459 if (!(run.dynamicFile = files_mapSharedMem(hfuzz->mutate.maxFileSz, &run.dynamicFileFd,
460 "hfuzz-input", run.global->io.workDir))) {
461 LOG_F("Couldn't create an input file of size: %zu", hfuzz->mutate.maxFileSz);
dobinedf9f8d2018-01-21 13:57:02 +0100462 }
Robert Swiecki599dee12018-01-10 02:21:58 +0100463 }
Robert Swiecki41033812018-01-21 16:02:45 +0100464 defer {
465 if (run.dynamicFileFd != -1) {
466 close(run.dynamicFileFd);
467 }
468 };
Robert Swieckidecf14b2016-03-31 15:09:28 +0200469
Robert Swieckifc7520e2018-03-10 04:37:59 +0100470 if (!arch_archThreadInit(&run)) {
Robert Swiecki0f937af2016-03-30 18:19:16 +0200471 LOG_F("Could not initialize the thread");
472 }
473
Robert Swieckia96d78d2016-03-14 16:50:50 +0100474 for (;;) {
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200475 /* Check if dry run mode with verifier enabled */
Robert Swieckia5b918a2018-03-07 23:59:53 +0100476 if (run.global->mutate.mutationsPerRun == 0U && run.global->cfg.useVerifier &&
Robert Swiecki5e26bd92018-03-02 12:09:34 +0100477 !hfuzz->socketFuzzer.enabled) {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100478 if (ATOMIC_POST_INC(run.global->cnts.mutationsCnt) >= run.global->io.fileCnt) {
Robert Swiecki069b48f2017-05-31 01:00:08 +0200479 break;
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200480 }
481 }
482 /* Check for max iterations limit if set */
Robert Swiecki04dcac32018-03-02 03:05:26 +0100483 else if ((ATOMIC_POST_INC(run.global->cnts.mutationsCnt) >=
484 run.global->mutate.mutationsMax) &&
485 run.global->mutate.mutationsMax) {
Robert Swiecki069b48f2017-05-31 01:00:08 +0200486 break;
Robert Swiecki8d01b012017-02-19 15:48:11 +0100487 }
488
Robert Swieckie9231d62018-03-02 03:35:11 +0100489 input_setSize(&run, run.global->mutate.maxFileSz);
Robert Swiecki5e26bd92018-03-02 12:09:34 +0100490 if (hfuzz->socketFuzzer.enabled) {
dobinedf9f8d2018-01-21 13:57:02 +0100491 fuzz_fuzzLoopSocket(&run);
492 } else {
493 fuzz_fuzzLoop(&run);
494 }
495
Robert Swiecki0dde76d2017-11-16 19:25:44 +0100496 if (fuzz_isTerminating()) {
Robert Swiecki069b48f2017-05-31 01:00:08 +0200497 break;
498 }
499
Robert Swieckia5b918a2018-03-07 23:59:53 +0100500 if (run.global->cfg.exitUponCrash && ATOMIC_GET(run.global->cnts.crashesCnt) > 0) {
Robert Swiecki069b48f2017-05-31 01:00:08 +0200501 LOG_I("Seen a crash. Terminating all fuzzing threads");
Robert Swiecki0dde76d2017-11-16 19:25:44 +0100502 fuzz_setTerminating();
Robert Swiecki069b48f2017-05-31 01:00:08 +0200503 break;
504 }
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000505 }
Robert Swiecki069b48f2017-05-31 01:00:08 +0200506
Robert Swiecki98e23372019-01-30 11:50:18 +0100507 if (run.pid) {
508 kill(run.pid, SIGKILL);
509 }
510
Robert Swiecki20fc98f2018-11-19 00:08:09 +0100511 LOG_I("Terminating thread no. #%" PRId32 ", left: %zu", fuzzNo,
Robert Swieckiacdf0bd2019-02-17 02:42:04 +0100512 hfuzz->threads.threadsMax - ATOMIC_GET(run.global->threads.threadsFinished));
Robert Swiecki78633d12017-11-13 23:24:55 +0100513 ATOMIC_POST_INC(run.global->threads.threadsFinished);
Robert Swiecki069b48f2017-05-31 01:00:08 +0200514 return NULL;
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000515}
516
Robert Swiecki64d52432019-02-14 23:02:13 +0100517void fuzz_threadsStart(honggfuzz_t* hfuzz) {
robert.swiecki@gmail.com956276a2015-04-16 16:51:52 +0000518 if (!arch_archInit(hfuzz)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200519 LOG_F("Couldn't prepare arch for fuzzing");
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000520 }
Anestis Bechtsoudise5f09f82016-12-27 16:06:05 +0200521 if (!sanitizers_Init(hfuzz)) {
522 LOG_F("Couldn't prepare sanitizer options");
523 }
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000524
Robert Swiecki5e26bd92018-03-02 12:09:34 +0100525 if (hfuzz->socketFuzzer.enabled) {
Robert Swiecki5eeb29b2018-01-21 16:07:06 +0100526 /* Don't do dry run with socketFuzzer */
Robert Swiecki41033812018-01-21 16:02:45 +0100527 LOG_I("Entering phase - Feedback Driven Mode (SocketFuzzer)");
Robert Swiecki363510f2018-03-09 02:00:30 +0100528 hfuzz->feedback.state = _HF_STATE_DYNAMIC_MAIN;
Robert Swieckia5b918a2018-03-07 23:59:53 +0100529 } else if (hfuzz->feedback.dynFileMethod != _HF_DYNFILE_NONE) {
Robert Swiecki41033812018-01-21 16:02:45 +0100530 LOG_I("Entering phase 1/2: Dry Run");
Robert Swiecki363510f2018-03-09 02:00:30 +0100531 hfuzz->feedback.state = _HF_STATE_DYNAMIC_DRY_RUN;
Robert Swieckia96d78d2016-03-14 16:50:50 +0100532 } else {
Robert Swiecki41033812018-01-21 16:02:45 +0100533 LOG_I("Entering phase: Static");
Robert Swiecki363510f2018-03-09 02:00:30 +0100534 hfuzz->feedback.state = _HF_STATE_STATIC;
Robert Swieckia96d78d2016-03-14 16:50:50 +0100535 }
536
Robert Swiecki66b65122017-11-11 02:55:55 +0100537 for (size_t i = 0; i < hfuzz->threads.threadsMax; i++) {
Robert Swiecki64d52432019-02-14 23:02:13 +0100538 if (!subproc_runThread(hfuzz, &hfuzz->threads.threads[i], fuzz_threadNew)) {
539 PLOG_F("Couldn't run a thread #%zu", i);
540 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000541 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000542}