blob: c6257d384ab47fc37081b7ea9fd7daa8b7f027a0 [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/param.h>
Robert Swiecki1e1b3532016-03-10 18:43:28 +010040#include <sys/resource.h>
Jagger08816fd2016-03-11 01:32:38 +010041#include <sys/mman.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000042#include <sys/stat.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000043#include <sys/time.h>
44#include <sys/types.h>
45#include <sys/wait.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000046#include <time.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000047#include <unistd.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000048
robert.swiecki3bb518c2010-10-14 00:48:24 +000049#include "arch.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"
Jagger00265602016-03-10 02:36:27 +010054#include "sancov.h"
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +000055#include "util.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000056
Jagger1e05f742016-03-10 21:36:27 +010057extern char **environ;
58
Jagger6113c432015-09-24 05:00:28 +020059static pthread_t fuzz_mainThread;
60
robert.swiecki3bb518c2010-10-14 00:48:24 +000061static void fuzz_getFileName(honggfuzz_t * hfuzz, char *fileName)
62{
robert.swieckiba512632011-01-28 11:57:26 +000063 struct timeval tv;
64 gettimeofday(&tv, NULL);
65
Anestis Bechtsoudisd9680532015-09-06 17:37:05 +030066 snprintf(fileName, PATH_MAX, "%s/.honggfuzz.%d.%lu.%llx.%s", hfuzz->workDir, (int)getpid(),
robert.swiecki@gmail.com6f319912015-02-28 05:01:37 +000067 (unsigned long int)tv.tv_sec, (unsigned long long int)util_rndGet(0, 1ULL << 62),
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +000068 hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +000069}
70
Robert Swiecki1e1b3532016-03-10 18:43:28 +010071static bool fuzz_prepareExecve(honggfuzz_t * hfuzz, const char *fileName)
72{
73 /*
74 * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
75 */
Robert Swiecki4038c9b2016-03-31 18:58:52 +020076 if (hfuzz->persistent == false && hfuzz->tmOut) {
Robert Swiecki1e1b3532016-03-10 18:43:28 +010077 struct itimerval it;
78
79 /*
80 * The hfuzz->tmOut is real CPU usage time...
81 */
82 it.it_value.tv_sec = hfuzz->tmOut;
83 it.it_value.tv_usec = 0;
84 it.it_interval.tv_sec = 0;
85 it.it_interval.tv_usec = 0;
86 if (setitimer(ITIMER_PROF, &it, NULL) == -1) {
Robert Swieckic6a48b12016-03-11 17:41:57 +010087 PLOG_D("Couldn't set the ITIMER_PROF timer");
Robert Swiecki1e1b3532016-03-10 18:43:28 +010088 }
89
90 /*
91 * ...so, if a process sleeps, this one should
92 * trigger a signal...
93 */
94 it.it_value.tv_sec = hfuzz->tmOut;
95 it.it_value.tv_usec = 0;
96 it.it_interval.tv_sec = 0;
97 it.it_interval.tv_usec = 0;
98 if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
99 PLOG_E("Couldn't set the ITIMER_REAL timer");
100 return false;
101 }
102
103 /*
104 * ..if a process sleeps and catches SIGPROF/SIGALRM
105 * rlimits won't help either. However, arch_checkTimeLimit
106 * will send a SIGKILL at tmOut + 2 seconds. That should
107 * do it :)
108 */
109 struct rlimit rl;
110
111 rl.rlim_cur = hfuzz->tmOut + 1;
112 rl.rlim_max = hfuzz->tmOut + 1;
113 if (setrlimit(RLIMIT_CPU, &rl) == -1) {
Robert Swieckic6a48b12016-03-11 17:41:57 +0100114 PLOG_D("Couldn't enforce the RLIMIT_CPU resource limit");
Robert Swiecki1e1b3532016-03-10 18:43:28 +0100115 }
116 }
117
118 /*
119 * The address space limit. If big enough - roughly the size of RAM used
120 */
121 if (hfuzz->asLimit) {
Jagger06a4bbc2016-03-10 21:19:23 +0100122 struct rlimit rl = {
Robert Swiecki1e1b3532016-03-10 18:43:28 +0100123 .rlim_cur = hfuzz->asLimit * 1024ULL * 1024ULL,
124 .rlim_max = hfuzz->asLimit * 1024ULL * 1024ULL,
125 };
Jagger06a4bbc2016-03-10 21:19:23 +0100126 if (setrlimit(RLIMIT_AS, &rl) == -1) {
Robert Swiecki1e1b3532016-03-10 18:43:28 +0100127 PLOG_D("Couldn't enforce the RLIMIT_AS resource limit, ignoring");
128 }
129 }
130
131 if (hfuzz->nullifyStdio) {
132 util_nullifyStdio();
133 }
134
135 if (hfuzz->fuzzStdin) {
136 /*
137 * Uglyyyyyy ;)
138 */
139 if (!util_redirectStdin(fileName)) {
140 return false;
141 }
142 }
143
Jagger80041fe2016-03-10 21:32:35 +0100144 if (hfuzz->clearEnv) {
Jagger1e05f742016-03-10 21:36:27 +0100145 environ = NULL;
Jagger80041fe2016-03-10 21:32:35 +0100146 }
Robert Swiecki1e1b3532016-03-10 18:43:28 +0100147 if (sancov_prepareExecve(hfuzz) == false) {
148 LOG_E("sancov_prepareExecve() failed");
149 return false;
150 }
151 for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs) && hfuzz->envs[i]; i++) {
152 putenv(hfuzz->envs[i]);
153 }
154 setsid();
155
Jagger5719eb72016-08-28 17:43:35 +0200156 if (hfuzz->bbFd != -1) {
157 if (dup2(hfuzz->bbFd, _HF_BITMAP_FD) == -1) {
158 PLOG_F("dup2('%d', %d)", hfuzz->bbFd, _HF_BITMAP_FD);
159 }
160 }
161
Robert Swiecki1e1b3532016-03-10 18:43:28 +0100162 return true;
163}
164
Robert Swieckia96d78d2016-03-14 16:50:50 +0100165static bool fuzz_prepareFileDynamically(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000166{
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100167 struct dynfile_t *dynfile;
Robert Swieckia08ab1c2016-03-14 18:29:21 +0100168
169 {
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100170 MX_SCOPED_LOCK(&hfuzz->dynfileq_mutex);
Robert Swiecki4b0390a2016-03-14 18:44:05 +0100171
Jaggerb070b812016-03-15 05:31:30 +0100172 if (hfuzz->dynfileqCnt == 0) {
Jaggere4496512016-03-16 01:55:46 +0100173 LOG_F("The dynamic file corpus is empty. Apparently, the initial fuzzing of the "
174 "provided file corpus (-f) has not produced any follow-up files with positive "
175 "coverage and/or CPU counters");
Jaggerb070b812016-03-15 05:31:30 +0100176 }
177
Robert Swiecki4b0390a2016-03-14 18:44:05 +0100178 size_t i = 0U;
Robert Swieckia08ab1c2016-03-14 18:29:21 +0100179 size_t dynFilePos = util_rndGet(0, hfuzz->dynfileqCnt - 1);
180 TAILQ_FOREACH(dynfile, &hfuzz->dynfileq, pointers) {
181 if (i++ == dynFilePos) {
182 break;
183 }
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100184 }
185 }
186
187 memcpy(fuzzer->dynamicFile, dynfile->data, dynfile->size);
Robert Swieckia08ab1c2016-03-14 18:29:21 +0100188 fuzzer->dynamicFileSz = dynfile->size;
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100189
Anestis Bechtsoudis6ef24e42016-01-13 13:05:53 +0200190 mangle_Resize(hfuzz, fuzzer->dynamicFile, &fuzzer->dynamicFileSz);
Robert Swieckia96d78d2016-03-14 16:50:50 +0100191 mangle_mangleContent(hfuzz, fuzzer);
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000192
Jagger1d743382016-04-02 02:09:41 +0200193 if (hfuzz->persistent == false && files_writeBufToFile
robert.swiecki@gmail.com62e34ae2015-03-05 03:39:32 +0000194 (fuzzer->fileName, fuzzer->dynamicFile, fuzzer->dynamicFileSz,
Jagger5a3c4c32016-04-16 19:27:47 +0200195 O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_CLOEXEC) == false) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200196 LOG_E("Couldn't write buffer to file '%s'", fuzzer->fileName);
robert.swiecki@gmail.com3b6c6292015-02-26 11:48:46 +0000197 return false;
198 }
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000199
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000200 return true;
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000201}
202
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +0000203static bool fuzz_prepareFile(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000204{
Jagger1aa94d72016-04-02 02:37:35 +0200205 ssize_t fileSz =
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +0000206 files_readFileToBufMax(hfuzz->files[rnd_index], fuzzer->dynamicFile, hfuzz->maxFileSz);
Jagger1aa94d72016-04-02 02:37:35 +0200207 if (fileSz < 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200208 LOG_E("Couldn't read contents of '%s'", hfuzz->files[rnd_index]);
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000209 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000210 }
Robert Swieckia96d78d2016-03-14 16:50:50 +0100211 fuzzer->dynamicFileSz = fileSz;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000212
Anestis Bechtsoudis25262b32015-11-07 22:39:47 +0200213 /* If flip rate is 0.0, early abort file mangling */
Robert Swieckia96d78d2016-03-14 16:50:50 +0100214 if (fuzzer->flipRate != 0.0L) {
215 mangle_Resize(hfuzz, fuzzer->dynamicFile, &fuzzer->dynamicFileSz);
216 mangle_mangleContent(hfuzz, fuzzer);
Anestis Bechtsoudis25262b32015-11-07 22:39:47 +0200217 }
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000218
Jagger1d743382016-04-02 02:09:41 +0200219 if (hfuzz->persistent == false && files_writeBufToFile
Robert Swieckia96d78d2016-03-14 16:50:50 +0100220 (fuzzer->fileName, fuzzer->dynamicFile, fuzzer->dynamicFileSz,
Jagger5a3c4c32016-04-16 19:27:47 +0200221 O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC) == false) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200222 LOG_E("Couldn't write buffer to file '%s'", fuzzer->fileName);
robert.swiecki@gmail.come7680522015-02-22 22:22:37 +0000223 return false;
224 }
225
robert.swiecki3bb518c2010-10-14 00:48:24 +0000226 return true;
227}
228
Jaggera34b3022016-04-02 02:20:40 +0200229static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000230{
Jagger5a3c4c32016-04-16 19:27:47 +0200231 int dstfd = open(fuzzer->fileName, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644);
Jaggera34b3022016-04-02 02:20:40 +0200232 if (dstfd == -1) {
233 PLOG_E("Couldn't create a temporary file '%s'", fuzzer->fileName);
234 return false;
Robert Swieckie48811e2016-03-09 18:31:19 +0100235 }
Jaggera34b3022016-04-02 02:20:40 +0200236 close(dstfd);
237
238 LOG_D("Created '%s' as an input file", fuzzer->fileName);
robert.swiecki3d505e22010-10-14 01:17:17 +0000239
Robert Swiecki12800cd2016-03-31 15:38:10 +0200240 pid_t pid = fork();
robert.swiecki3bb518c2010-10-14 00:48:24 +0000241 if (pid == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200242 PLOG_E("Couldn't fork");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000243 return false;
244 }
245
246 if (!pid) {
247 /*
robert.swiecki@gmail.comcdf18f92015-02-11 22:22:18 +0000248 * child performs the external file modifications
robert.swiecki3bb518c2010-10-14 00:48:24 +0000249 */
robert.swiecki@gmail.com20851202015-03-01 01:48:15 +0000250 execl(hfuzz->externalCommand, hfuzz->externalCommand, fuzzer->fileName, NULL);
Robert Swieckic8c32db2015-10-09 18:06:22 +0200251 PLOG_F("Couldn't execute '%s %s'", hfuzz->externalCommand, fuzzer->fileName);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000252 return false;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000253 }
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000254
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000255 /*
256 * parent waits until child is done fuzzing the input file
257 */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000258 int childStatus;
259 int flags = 0;
robert.swiecki@gmail.coma2291182015-02-13 16:56:27 +0000260#if defined(__WNOTHREAD)
261 flags |= __WNOTHREAD;
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000262#endif /* defined(__WNOTHREAD) */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000263 while (wait4(pid, &childStatus, flags, NULL) != pid) ;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000264 if (WIFSIGNALED(childStatus)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200265 LOG_E("External command terminated with signal %d", WTERMSIG(childStatus));
robert.swiecki3d505e22010-10-14 01:17:17 +0000266 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000267 }
Jagger1d743382016-04-02 02:09:41 +0200268 if (!WIFEXITED(childStatus)) {
269 LOG_F("External command terminated abnormally, status: %d", childStatus);
270 return false;
271 }
272 LOG_D("External command exited with status %d", WEXITSTATUS(childStatus));
273
274 ssize_t rsz = files_readFileToBufMax(fuzzer->fileName, fuzzer->dynamicFile, hfuzz->maxFileSz);
Jagger1aa94d72016-04-02 02:37:35 +0200275 if (rsz < 0) {
Jagger1d743382016-04-02 02:09:41 +0200276 LOG_W("Couldn't read back '%s' to the buffer", fuzzer->fileName);
277 return false;
278 }
279 fuzzer->dynamicFileSz = rsz;
280
281 if (hfuzz->persistent) {
282 unlink(fuzzer->fileName);
283 }
284
285 return true;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000286}
287
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300288static bool fuzz_runVerifier(honggfuzz_t * hfuzz, fuzzer_t * crashedFuzzer)
289{
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300290 int crashFd = -1;
291 uint8_t *crashBuf = NULL;
292 off_t crashFileSz = 0;
293
294 crashBuf = files_mapFile(crashedFuzzer->crashFileName, &crashFileSz, &crashFd, false);
295 if (crashBuf == NULL) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700296 LOG_E("Couldn't open and map '%s' in R/O mode", crashedFuzzer->crashFileName);
Robert Swieckie48811e2016-03-09 18:31:19 +0100297 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300298 }
Jagger4fe18692016-04-22 23:15:07 +0200299 defer {
300 munmap(crashBuf, crashFileSz);
Jagger4fe18692016-04-22 23:15:07 +0200301 close(crashFd);
302 };
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300303
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700304 LOG_I("Launching verifier for %" PRIx64 " hash", crashedFuzzer->backtrace);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300305 for (int i = 0; i < _HF_VERIFIER_ITER; i++) {
306 fuzzer_t vFuzzer = {
307 .pid = 0,
Anestis Bechtsoudis92b97042016-04-27 12:34:19 +0300308 .persistentPid = 0,
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300309 .timeStartedMillis = util_timeNowMillis(),
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300310 .crashFileName = {0},
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300311 .pc = 0ULL,
312 .backtrace = 0ULL,
313 .access = 0ULL,
314 .exception = 0,
315 .dynamicFileSz = 0,
316 .dynamicFile = NULL,
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200317 .sanCovCnts = {
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200318 .hitBBCnt = 0ULL,
319 .totalBBCnt = 0ULL,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200320 .dsoCnt = 0ULL,
321 .iDsoCnt = 0ULL,
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200322 .newBBCnt = 0ULL,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200323 .crashesCnt = 0ULL,
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200324 },
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300325 .report = {'\0'},
Jaggerb2c1fad2016-03-17 23:37:10 +0100326 .mainWorker = false,
327
Jagger2381ef42016-03-20 23:32:05 +0100328 .linux = {
329 .hwCnts = {
330 .cpuInstrCnt = 0ULL,
331 .cpuBranchCnt = 0ULL,
332 .customCnt = 0ULL,
333 .bbCnt = 0ULL,
334 .newBBCnt = 0ULL,
335 },
336 .perfMmapBuf = NULL,
337 .perfMmapAux = NULL,
Anestis Bechtsoudis92b97042016-04-27 12:34:19 +0300338#if defined(_HF_ARCH_LINUX)
339 .timerId = (timer_t) 0,
340#endif // defined(_HF_ARCH_LINUX)
341 .attachedPid = 0,
342 .persistentSock = -1,
Jagger2381ef42016-03-20 23:32:05 +0100343 },
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300344 };
345
Anestis Bechtsoudis92b97042016-04-27 12:34:19 +0300346 if (arch_archThreadInit(hfuzz, &vFuzzer) == false) {
347 LOG_F("Could not initialize the thread");
348 }
349
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300350 fuzz_getFileName(hfuzz, vFuzzer.fileName);
351 if (files_writeBufToFile
Jagger33cce5d2016-04-16 20:10:36 +0200352 (vFuzzer.fileName, crashBuf, crashFileSz,
353 O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC) == false) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700354 LOG_E("Couldn't write buffer to file '%s'", vFuzzer.fileName);
Robert Swieckie48811e2016-03-09 18:31:19 +0100355 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300356 }
357
Robert Swiecki12800cd2016-03-31 15:38:10 +0200358 vFuzzer.pid = arch_fork(hfuzz, &vFuzzer);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300359 if (vFuzzer.pid == -1) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700360 PLOG_F("Couldn't fork");
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300361 return false;
362 }
363
364 if (!vFuzzer.pid) {
Robert Swiecki1e1b3532016-03-10 18:43:28 +0100365 if (fuzz_prepareExecve(hfuzz, crashedFuzzer->crashFileName) == false) {
366 LOG_E("fuzz_prepareExecve() failed");
Jagger2b97dc92016-03-10 04:28:18 +0100367 return false;
368 }
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300369 if (!arch_launchChild(hfuzz, crashedFuzzer->crashFileName)) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700370 LOG_E("Error launching verifier child process");
Robert Swieckie48811e2016-03-09 18:31:19 +0100371 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300372 }
373 }
374
Robert Swieckia8b8cb82016-08-17 18:27:08 +0200375 arch_prepareChild(hfuzz, &vFuzzer);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300376 arch_reapChild(hfuzz, &vFuzzer);
Robert Swieckia8b8cb82016-08-17 18:27:08 +0200377
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300378 unlink(vFuzzer.fileName);
379
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300380 /* If stack hash doesn't match skip name tag and exit */
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300381 if (crashedFuzzer->backtrace != vFuzzer.backtrace) {
Anestis Bechtsoudis0cde66f2015-10-11 19:37:11 -0700382 LOG_D("Verifier stack hash mismatch");
Robert Swieckie48811e2016-03-09 18:31:19 +0100383 return false;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300384 }
385 }
386
387 /* Workspace is inherited, just append a extra suffix */
388 char verFile[PATH_MAX] = { 0 };
389 snprintf(verFile, sizeof(verFile), "%s.verified", crashedFuzzer->crashFileName);
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300390
Anestis Bechtsoudisd86e6602015-11-07 18:34:06 +0200391 /* Copy file with new suffix & remove original copy */
392 bool dstFileExists = false;
393 if (files_copyFile(crashedFuzzer->crashFileName, verFile, &dstFileExists)) {
394 LOG_I("Successfully verified, saving as (%s)", verFile);
Jaggerd34417d2016-03-16 01:26:54 +0100395 ATOMIC_POST_INC(hfuzz->verifiedCrashesCnt);
Anestis Bechtsoudisd86e6602015-11-07 18:34:06 +0200396 unlink(crashedFuzzer->crashFileName);
397 } else {
398 if (dstFileExists) {
399 LOG_I("It seems that '%s' already exists, skipping", verFile);
400 } else {
401 LOG_E("Couldn't copy '%s' to '%s'", crashedFuzzer->crashFileName, verFile);
Robert Swieckie48811e2016-03-09 18:31:19 +0100402 return false;
Anestis Bechtsoudisd86e6602015-11-07 18:34:06 +0200403 }
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300404 }
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300405
Robert Swieckie48811e2016-03-09 18:31:19 +0100406 return true;
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300407}
408
Robert Swieckid258ff82016-08-29 17:54:20 +0200409static void fuzz_addFileToFileQLocked(honggfuzz_t * hfuzz, uint8_t * data, size_t size)
Robert Swieckif3534bb2016-03-14 18:55:10 +0100410{
Robert Swiecki7084e652016-03-14 19:47:00 +0100411 struct dynfile_t *dynfile = (struct dynfile_t *)util_Malloc(sizeof(struct dynfile_t));
Robert Swieckif3534bb2016-03-14 18:55:10 +0100412 dynfile->size = size;
Robert Swiecki7084e652016-03-14 19:47:00 +0100413 dynfile->data = (uint8_t *) util_Malloc(size);
Robert Swieckif3534bb2016-03-14 18:55:10 +0100414 memcpy(dynfile->data, data, size);
415 TAILQ_INSERT_TAIL(&hfuzz->dynfileq, dynfile, pointers);
416 hfuzz->dynfileqCnt++;
417
418 char fname[PATH_MAX];
Robert Swieckid258ff82016-08-29 17:54:20 +0200419 snprintf(fname, sizeof(fname), "%s/COVERAGE.TIME.%d.PID.%d.ITER.%" PRIu64 ".RND.%" PRIx64,
420 hfuzz->workDir, (int)time(NULL), (int)getpid(),
421 (uint64_t) ATOMIC_GET(hfuzz->mutationsCnt), util_rndGet(0, 0xFFFFFFFFFFFF));
Jagger33cce5d2016-04-16 20:10:36 +0200422 if (files_writeBufToFile(fname, data, size, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_CLOEXEC)
423 == false) {
Robert Swieckif3534bb2016-03-14 18:55:10 +0100424 LOG_W("Couldn't write buffer to file '%s'", fname);
425 }
426}
427
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200428static void fuzz_perfFeedback(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
429{
430 LOG_D
Jagger395df022016-08-21 01:13:25 +0200431 ("New file size: %zu, Perf feedback new/cur (instr,branch): %" PRIu64 "/%" PRIu64 "/%"
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100432 PRIu64 "/%" PRIu64 ", BBcnt new/total: %" PRIu64 "/%" PRIu64, fuzzer->dynamicFileSz,
Jagger247c3b42016-03-21 23:24:05 +0100433 fuzzer->linux.hwCnts.cpuInstrCnt, hfuzz->linux.hwCnts.cpuInstrCnt,
434 fuzzer->linux.hwCnts.cpuBranchCnt, hfuzz->linux.hwCnts.cpuBranchCnt,
435 fuzzer->linux.hwCnts.newBBCnt, hfuzz->linux.hwCnts.bbCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200436
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100437 MX_SCOPED_LOCK(&hfuzz->dynfileq_mutex);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200438
Jagger247c3b42016-03-21 23:24:05 +0100439 int64_t diff0 = hfuzz->linux.hwCnts.cpuInstrCnt - fuzzer->linux.hwCnts.cpuInstrCnt;
440 int64_t diff1 = hfuzz->linux.hwCnts.cpuBranchCnt - fuzzer->linux.hwCnts.cpuBranchCnt;
441 int64_t diff2 = hfuzz->linux.hwCnts.customCnt - fuzzer->linux.hwCnts.customCnt;
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200442
Jagger251d0192016-08-24 00:54:04 +0200443 uint64_t softCnt = 0UL;
444 if (hfuzz->bbFd != -1) {
445 softCnt = ATOMIC_GET(hfuzz->feedback->pidFeedback[fuzzer->pid]);
446 ATOMIC_CLEAR(hfuzz->feedback->pidFeedback[fuzzer->pid]);
447 }
Jaggerb01aaae2016-08-20 03:35:38 +0200448
Jagger8d0002c2016-08-17 03:44:23 +0200449 /*
450 * Coverage is the primary counter, the rest is secondary, and taken into consideration only
451 * if the coverage counter has not been changed
452 */
Jaggerb01aaae2016-08-20 03:35:38 +0200453 if (fuzzer->linux.hwCnts.newBBCnt > 0 || softCnt > 0 || diff0 < 0 || diff1 < 0 || diff2 < 0) {
Jagger247c3b42016-03-21 23:24:05 +0100454 hfuzz->linux.hwCnts.cpuInstrCnt = fuzzer->linux.hwCnts.cpuInstrCnt;
455 hfuzz->linux.hwCnts.cpuBranchCnt = fuzzer->linux.hwCnts.cpuBranchCnt;
456 hfuzz->linux.hwCnts.customCnt = fuzzer->linux.hwCnts.customCnt;
457 hfuzz->linux.hwCnts.bbCnt += fuzzer->linux.hwCnts.newBBCnt;
Jaggerb01aaae2016-08-20 03:35:38 +0200458 hfuzz->linux.hwCnts.softCnt += softCnt;
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200459
Jagger395df022016-08-21 01:13:25 +0200460 LOG_I
461 ("New file size: %zu, Feedback: New (instr,branch,soft,perf,custom): %" PRIu64 "/%"
462 PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 ", Total: %" PRIu64 "/%" PRIu64 "/%" PRIu64
463 "/%" PRIu64 "/%" PRIu64, fuzzer->dynamicFileSz, fuzzer->linux.hwCnts.cpuInstrCnt,
464 fuzzer->linux.hwCnts.cpuBranchCnt, softCnt, fuzzer->linux.hwCnts.newBBCnt,
465 fuzzer->linux.hwCnts.customCnt, hfuzz->linux.hwCnts.cpuInstrCnt,
466 hfuzz->linux.hwCnts.cpuBranchCnt, hfuzz->linux.hwCnts.softCnt,
467 hfuzz->linux.hwCnts.bbCnt, hfuzz->linux.hwCnts.customCnt);
468
Robert Swieckid258ff82016-08-29 17:54:20 +0200469 fuzz_addFileToFileQLocked(hfuzz, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200470 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200471}
472
473static void fuzz_sanCovFeedback(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
474{
475 LOG_D
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100476 ("File size (Best/New): %zu, SanCov feedback (bb,dso): Best: [%" PRIu64
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200477 ",%" PRIu64 "] / New: [%" PRIu64 ",%" PRIu64 "], newBBs:%" PRIu64,
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100478 fuzzer->dynamicFileSz, hfuzz->sanCovCnts.hitBBCnt,
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200479 hfuzz->sanCovCnts.iDsoCnt, fuzzer->sanCovCnts.hitBBCnt, fuzzer->sanCovCnts.iDsoCnt,
480 fuzzer->sanCovCnts.newBBCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200481
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100482 MX_SCOPED_LOCK(&hfuzz->dynfileq_mutex);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200483
Jaggerd5738372016-08-17 20:12:15 +0200484 int64_t diff0 = hfuzz->linux.hwCnts.cpuInstrCnt - fuzzer->linux.hwCnts.cpuInstrCnt;
485 int64_t diff1 = hfuzz->linux.hwCnts.cpuBranchCnt - fuzzer->linux.hwCnts.cpuBranchCnt;
486 int64_t diff2 = hfuzz->linux.hwCnts.customCnt - fuzzer->linux.hwCnts.customCnt;
487
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200488 /*
489 * Keep mutated seed if:
Robert Swiecki142f9412016-03-14 19:22:01 +0100490 * a) Newly discovered (not met before) BBs
491 * b) More instrumented DSOs loaded
Robert Swiecki23ec02a2016-01-19 18:47:45 +0100492 *
Anestis Bechtsoudisb78cf602016-01-07 13:10:50 +0200493 * TODO: (a) method can significantly assist to further improvements in interesting areas
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200494 * discovery if combined with seeds pool/queue support. If a runtime queue is maintained
495 * more interesting seeds can be saved between runs instead of instantly discarded
496 * based on current absolute elitism (only one mutated seed is promoted).
497 */
Jaggerd5738372016-08-17 20:12:15 +0200498
499 bool newCov = (fuzzer->sanCovCnts.newBBCnt > 0
500 || hfuzz->sanCovCnts.iDsoCnt < fuzzer->sanCovCnts.iDsoCnt);
501
502 if (newCov || (diff0 < 0 || diff1 < 0 || diff2 < 0)) {
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100503 LOG_I("SanCov Update: file size (Cur): %zu, newBBs:%" PRIu64
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200504 ", counters (Cur,New): %" PRIu64 "/%" PRIu64 ",%" PRIu64 "/%" PRIu64,
Robert Swiecki3bfc33c2016-03-14 18:12:41 +0100505 fuzzer->dynamicFileSz, fuzzer->sanCovCnts.newBBCnt,
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200506 hfuzz->sanCovCnts.hitBBCnt, hfuzz->sanCovCnts.iDsoCnt, fuzzer->sanCovCnts.hitBBCnt,
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200507 fuzzer->sanCovCnts.iDsoCnt);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200508
Robert Swiecki142f9412016-03-14 19:22:01 +0100509 hfuzz->sanCovCnts.hitBBCnt += fuzzer->sanCovCnts.newBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200510 hfuzz->sanCovCnts.dsoCnt = fuzzer->sanCovCnts.dsoCnt;
511 hfuzz->sanCovCnts.iDsoCnt = fuzzer->sanCovCnts.iDsoCnt;
512 hfuzz->sanCovCnts.crashesCnt += fuzzer->sanCovCnts.crashesCnt;
Robert Swiecki142f9412016-03-14 19:22:01 +0100513 hfuzz->sanCovCnts.newBBCnt = fuzzer->sanCovCnts.newBBCnt;
Anestis Bechtsoudisb78cf602016-01-07 13:10:50 +0200514
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200515 if (hfuzz->sanCovCnts.totalBBCnt < fuzzer->sanCovCnts.totalBBCnt) {
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200516 /* Keep only the max value (for dlopen cases) to measure total target coverage */
Anestis Bechtsoudis56e360f2016-01-11 14:29:17 +0200517 hfuzz->sanCovCnts.totalBBCnt = fuzzer->sanCovCnts.totalBBCnt;
Anestis Bechtsoudisa16f70f2016-01-03 13:03:21 +0200518 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200519
Jaggerd5738372016-08-17 20:12:15 +0200520 hfuzz->linux.hwCnts.cpuInstrCnt = fuzzer->linux.hwCnts.cpuInstrCnt;
521 hfuzz->linux.hwCnts.cpuBranchCnt = fuzzer->linux.hwCnts.cpuBranchCnt;
522 hfuzz->linux.hwCnts.customCnt = fuzzer->linux.hwCnts.customCnt;
523
Robert Swieckid258ff82016-08-29 17:54:20 +0200524 fuzz_addFileToFileQLocked(hfuzz, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200525 }
Anestis Bechtsoudisbe0ac7b2015-12-26 15:38:47 +0200526}
527
Robert Swiecki6d01e822016-03-15 20:21:46 +0100528static fuzzState_t fuzz_getState(honggfuzz_t * hfuzz)
529{
Jaggerd34417d2016-03-16 01:26:54 +0100530 return ATOMIC_GET(hfuzz->state);
Robert Swiecki6d01e822016-03-15 20:21:46 +0100531}
532
533static void fuzz_setState(honggfuzz_t * hfuzz, fuzzState_t state)
534{
Jaggerd34417d2016-03-16 01:26:54 +0100535 ATOMIC_SET(hfuzz->state, state);
Robert Swiecki6d01e822016-03-15 20:21:46 +0100536}
537
Robert Swieckidecf14b2016-03-31 15:09:28 +0200538static void fuzz_fuzzLoop(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
Jagger190f0dc2015-09-05 16:41:22 +0200539{
Robert Swieckidecf14b2016-03-31 15:09:28 +0200540 fuzzer->pid = 0;
541 fuzzer->timeStartedMillis = util_timeNowMillis();
542 fuzzer->crashFileName[0] = '\0';
543 fuzzer->pc = 0ULL;
544 fuzzer->backtrace = 0ULL;
545 fuzzer->access = 0ULL;
546 fuzzer->exception = 0;
547 fuzzer->report[0] = '\0';
548 fuzzer->mainWorker = true;
549 fuzzer->origFileName = "DYNAMIC";
550 fuzzer->flipRate = hfuzz->origFlipRate;
551 fuzzer->dynamicFileSz = 0;
Robert Swieckia96d78d2016-03-14 16:50:50 +0100552
Robert Swieckidecf14b2016-03-31 15:09:28 +0200553 fuzzer->sanCovCnts.hitBBCnt = 0ULL;
554 fuzzer->sanCovCnts.totalBBCnt = 0ULL;
555 fuzzer->sanCovCnts.dsoCnt = 0ULL;
556 fuzzer->sanCovCnts.newBBCnt = 0ULL;
557 fuzzer->sanCovCnts.crashesCnt = 0ULL;
Robert Swieckia96d78d2016-03-14 16:50:50 +0100558
Robert Swieckidecf14b2016-03-31 15:09:28 +0200559 fuzzer->linux.hwCnts.cpuInstrCnt = 0ULL;
560 fuzzer->linux.hwCnts.cpuBranchCnt = 0ULL;
561 fuzzer->linux.hwCnts.customCnt = 0ULL;
562 fuzzer->linux.hwCnts.bbCnt = 0ULL;
563 fuzzer->linux.hwCnts.newBBCnt = 0ULL;
564 fuzzer->linux.perfMmapBuf = NULL;
565 fuzzer->linux.perfMmapAux = NULL;
Jagger190f0dc2015-09-05 16:41:22 +0200566
Anestis Bechtsoudis2013f252015-11-07 22:03:31 +0200567 size_t rnd_index = util_rndGet(0, hfuzz->fileCnt - 1);
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200568
569 /* If dry run mode, pick the next file and not a random one */
Robert Swieckidecf14b2016-03-31 15:09:28 +0200570 if (fuzzer->flipRate == 0.0L && hfuzz->useVerifier) {
Jaggerd34417d2016-03-16 01:26:54 +0100571 rnd_index = ATOMIC_POST_INC(hfuzz->lastFileIndex);
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200572 }
Robert Swiecki129afe82016-03-15 20:03:20 +0100573
Robert Swiecki6d01e822016-03-15 20:21:46 +0100574 if (fuzz_getState(hfuzz) == _HF_STATE_DYNAMIC_PRE) {
Jaggerd34417d2016-03-16 01:26:54 +0100575 rnd_index = ATOMIC_POST_INC(hfuzz->lastFileIndex);
Robert Swieckia96d78d2016-03-14 16:50:50 +0100576 if (rnd_index >= hfuzz->fileCnt) {
Jagger33fd9522016-03-15 22:13:57 +0100577 /*
578 * The waiting logic (for the DYNAMIC_PRE phase to finish) should be based on cond-waits
579 * or mutexes, but it'd complicate code too much
580 */
Robert Swiecki6d01e822016-03-15 20:21:46 +0100581 while (fuzz_getState(hfuzz) == _HF_STATE_DYNAMIC_PRE) {
582 sleep(1);
Robert Swiecki129afe82016-03-15 20:03:20 +0100583 }
Robert Swieckia96d78d2016-03-14 16:50:50 +0100584 }
585 }
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200586
Jagger33fd9522016-03-15 22:13:57 +0100587 fuzzState_t state = fuzz_getState(hfuzz);
Robert Swieckidecf14b2016-03-31 15:09:28 +0200588 if (state != _HF_STATE_DYNAMIC_MAIN) {
589 fuzzer->origFileName = files_basename(hfuzz->files[rnd_index]);
Robert Swieckia08ab1c2016-03-14 18:29:21 +0100590 }
Robert Swiecki6d01e822016-03-15 20:21:46 +0100591
Robert Swieckidecf14b2016-03-31 15:09:28 +0200592 fuzz_getFileName(hfuzz, fuzzer->fileName);
Jagger190f0dc2015-09-05 16:41:22 +0200593
Jagger30384ec2016-04-02 02:30:32 +0200594 if (hfuzz->externalCommand) {
595 if (!fuzz_prepareFileExternally(hfuzz, fuzzer)) {
596 LOG_F("fuzz_prepareFileExternally() failed");
597 }
598 } else if (state == _HF_STATE_DYNAMIC_MAIN) {
Robert Swieckidecf14b2016-03-31 15:09:28 +0200599 if (!fuzz_prepareFileDynamically(hfuzz, fuzzer)) {
Jagger1d8e0c62016-04-02 02:22:40 +0200600 LOG_F("fuzz_prepareFileDynamically() failed");
Robert Swieckia96d78d2016-03-14 16:50:50 +0100601 }
Robert Swiecki6d01e822016-03-15 20:21:46 +0100602 } else if (state == _HF_STATE_DYNAMIC_PRE) {
Robert Swieckidecf14b2016-03-31 15:09:28 +0200603 fuzzer->flipRate = 0.0f;
604 if (!fuzz_prepareFile(hfuzz, fuzzer, rnd_index)) {
Jagger1d8e0c62016-04-02 02:22:40 +0200605 LOG_F("fuzz_prepareFile() failed");
Jagger190f0dc2015-09-05 16:41:22 +0200606 }
Jagger190f0dc2015-09-05 16:41:22 +0200607 } else {
Robert Swieckidecf14b2016-03-31 15:09:28 +0200608 if (!fuzz_prepareFile(hfuzz, fuzzer, rnd_index)) {
Jagger1d8e0c62016-04-02 02:22:40 +0200609 LOG_F("fuzz_prepareFile() failed");
Jagger190f0dc2015-09-05 16:41:22 +0200610 }
611 }
612
Robert Swieckidecf14b2016-03-31 15:09:28 +0200613 fuzzer->pid = fuzzer->persistentPid;
614 if (fuzzer->pid == 0) {
Robert Swiecki12800cd2016-03-31 15:38:10 +0200615 fuzzer->pid = arch_fork(hfuzz, fuzzer);
Robert Swieckidecf14b2016-03-31 15:09:28 +0200616 if (fuzzer->pid == -1) {
Robert Swiecki0f937af2016-03-30 18:19:16 +0200617 PLOG_F("Couldn't fork");
Jaggerbb83e7c2016-03-10 04:33:40 +0100618 }
Robert Swiecki0f937af2016-03-30 18:19:16 +0200619
Robert Swieckidecf14b2016-03-31 15:09:28 +0200620 if (!fuzzer->pid) {
621 if (!fuzz_prepareExecve(hfuzz, fuzzer->fileName)) {
Robert Swiecki0f937af2016-03-30 18:19:16 +0200622 LOG_E("fuzz_prepareExecve() failed");
623 exit(EXIT_FAILURE);
624 }
Robert Swieckidecf14b2016-03-31 15:09:28 +0200625 if (!arch_launchChild(hfuzz, fuzzer->fileName)) {
Robert Swiecki0f937af2016-03-30 18:19:16 +0200626 LOG_E("Error launching child process");
627 exit(EXIT_FAILURE);
628 }
629 }
Robert Swiecki1ae5eab2016-03-31 15:17:46 +0200630
631 if (hfuzz->persistent) {
Robert Swiecki0e673882016-03-31 18:50:29 +0200632 LOG_I("Persistent mode: Launched new persistent PID: %d", (int)fuzzer->pid);
Robert Swiecki12800cd2016-03-31 15:38:10 +0200633 fuzzer->persistentPid = fuzzer->pid;
Robert Swiecki1ae5eab2016-03-31 15:17:46 +0200634 }
Jagger190f0dc2015-09-05 16:41:22 +0200635 }
636
Robert Swieckidecf14b2016-03-31 15:09:28 +0200637 LOG_D("Launched new process, pid: %d, (concurrency: %zd)", fuzzer->pid, hfuzz->threadsMax);
Jagger190f0dc2015-09-05 16:41:22 +0200638
Robert Swieckia8b8cb82016-08-17 18:27:08 +0200639 arch_prepareChild(hfuzz, fuzzer);
Robert Swieckidecf14b2016-03-31 15:09:28 +0200640 arch_reapChild(hfuzz, fuzzer);
Robert Swieckia8b8cb82016-08-17 18:27:08 +0200641
Jaggera34b3022016-04-02 02:20:40 +0200642 if (hfuzz->persistent == false) {
643 unlink(fuzzer->fileName);
644 }
Jagger190f0dc2015-09-05 16:41:22 +0200645
646 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
Robert Swieckidecf14b2016-03-31 15:09:28 +0200647 fuzz_perfFeedback(hfuzz, fuzzer);
Jaggerabb6ae02016-03-18 01:55:51 +0100648 }
649 if (hfuzz->useSanCov) {
Robert Swieckidecf14b2016-03-31 15:09:28 +0200650 fuzz_sanCovFeedback(hfuzz, fuzzer);
Robert Swiecki0f937af2016-03-30 18:19:16 +0200651 }
Jagger190f0dc2015-09-05 16:41:22 +0200652
Robert Swieckidecf14b2016-03-31 15:09:28 +0200653 if (hfuzz->useVerifier && (fuzzer->crashFileName[0] != 0) && fuzzer->backtrace) {
654 if (!fuzz_runVerifier(hfuzz, fuzzer)) {
655 LOG_I("Failed to verify %s", fuzzer->crashFileName);
Anestis Bechtsoudis3085f222015-09-27 18:35:26 +0300656 }
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300657 }
658
Haris Andrianakisc9a71332016-05-09 21:56:30 -0700659 {
660 MX_SCOPED_LOCK(&hfuzz->report_mutex);
661 report_Report(hfuzz, fuzzer->report);
662 }
Robert Swiecki05354ca2016-03-15 19:10:23 +0100663
Jaggerd34417d2016-03-16 01:26:54 +0100664 if (state == _HF_STATE_DYNAMIC_PRE && ATOMIC_PRE_INC(hfuzz->doneFileIndex) >= hfuzz->fileCnt) {
Robert Swiecki6d01e822016-03-15 20:21:46 +0100665 fuzz_setState(hfuzz, _HF_STATE_DYNAMIC_MAIN);
Robert Swiecki05354ca2016-03-15 19:10:23 +0100666 }
Jagger190f0dc2015-09-05 16:41:22 +0200667}
668
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000669static void *fuzz_threadNew(void *arg)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000670{
Robert Swiecki0e673882016-03-31 18:50:29 +0200671 LOG_I("Launched new fuzzing thread");
672
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000673 honggfuzz_t *hfuzz = (honggfuzz_t *) arg;
Anestis Bechtsoudis02b99be2015-12-27 11:53:01 +0200674
Robert Swieckidecf14b2016-03-31 15:09:28 +0200675 fuzzer_t fuzzer = {
676 .pid = 0,
677 .persistentPid = 0,
678 .dynamicFile = util_Malloc(hfuzz->maxFileSz),
Robert Swiecki12800cd2016-03-31 15:38:10 +0200679
Robert Swiecki9f9968a2016-04-01 14:39:51 +0200680#if defined(_HF_ARCH_LINUX)
Robert Swieckie33c90b2016-03-31 17:32:56 +0200681 .linux.timerId = (timer_t) 0,
Robert Swiecki9f9968a2016-04-01 14:39:51 +0200682#endif // defined(_HF_ARCH_LINUX)
Robert Swieckib692f282016-08-25 16:21:08 +0200683 .linux.attachedPid = 0,
684 .linux.persistentSock = -1,
Robert Swieckidecf14b2016-03-31 15:09:28 +0200685 };
Jagger4fe18692016-04-22 23:15:07 +0200686 defer {
687 free(fuzzer.dynamicFile);
688 };
Robert Swieckidecf14b2016-03-31 15:09:28 +0200689
690 if (arch_archThreadInit(hfuzz, &fuzzer) == false) {
Robert Swiecki0f937af2016-03-30 18:19:16 +0200691 LOG_F("Could not initialize the thread");
692 }
693
Robert Swieckia96d78d2016-03-14 16:50:50 +0100694 for (;;) {
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200695 /* Check if dry run mode with verifier enabled */
Robert Swieckia96d78d2016-03-14 16:50:50 +0100696 if (hfuzz->origFlipRate == 0.0L && hfuzz->useVerifier) {
Jaggerd34417d2016-03-16 01:26:54 +0100697 if (ATOMIC_POST_INC(hfuzz->mutationsCnt) >= hfuzz->fileCnt) {
698 ATOMIC_POST_INC(hfuzz->threadsFinished);
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200699 // All files checked, weak-up the main process
700 pthread_kill(fuzz_mainThread, SIGALRM);
701 return NULL;
702 }
703 }
704 /* Check for max iterations limit if set */
Jaggerd34417d2016-03-16 01:26:54 +0100705 else if ((ATOMIC_POST_INC(hfuzz->mutationsCnt) >= hfuzz->mutationsMax)
Anestis Bechtsoudis46ea10e2015-11-07 18:16:25 +0200706 && hfuzz->mutationsMax) {
Jaggerd34417d2016-03-16 01:26:54 +0100707 ATOMIC_POST_INC(hfuzz->threadsFinished);
Robert Swiecki81c6a0d2015-09-08 15:43:20 +0200708 // Wake-up the main process
Jagger6113c432015-09-24 05:00:28 +0200709 pthread_kill(fuzz_mainThread, SIGALRM);
Jaggerea39a8f2015-09-05 00:57:22 +0200710 return NULL;
711 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000712
Robert Swieckidecf14b2016-03-31 15:09:28 +0200713 fuzz_fuzzLoop(hfuzz, &fuzzer);
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000714 }
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000715}
716
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000717static void fuzz_runThread(honggfuzz_t * hfuzz, void *(*thread) (void *))
718{
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000719 pthread_attr_t attr;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000720
robert.swiecki@gmail.com6f5c2392015-02-16 18:13:09 +0000721 pthread_attr_init(&attr);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000722 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000723 pthread_attr_setstacksize(&attr, _HF_PTHREAD_STACKSIZE);
robert.swiecki@gmail.com011981f2015-02-17 19:06:44 +0000724 pthread_attr_setguardsize(&attr, (size_t) sysconf(_SC_PAGESIZE));
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000725
robert.swiecki@gmail.com01b6dd42015-02-16 18:11:28 +0000726 pthread_t t;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000727 if (pthread_create(&t, &attr, thread, (void *)hfuzz) < 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200728 PLOG_F("Couldn't create a new thread");
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000729 }
730
731 return;
732}
733
Jagger08816fd2016-03-11 01:32:38 +0100734void fuzz_threads(honggfuzz_t * hfuzz)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000735{
Jagger6113c432015-09-24 05:00:28 +0200736 fuzz_mainThread = pthread_self();
737
robert.swiecki@gmail.com956276a2015-04-16 16:51:52 +0000738 if (!arch_archInit(hfuzz)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200739 LOG_F("Couldn't prepare arch for fuzzing");
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000740 }
Jagger00265602016-03-10 02:36:27 +0100741 if (!sancov_Init(hfuzz)) {
742 LOG_F("Couldn't prepare sancov options");
743 }
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000744
Robert Swieckia96d78d2016-03-14 16:50:50 +0100745 if (hfuzz->useSanCov || hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
Jaggerebe19292016-03-17 00:11:44 +0100746 fuzz_setState(hfuzz, _HF_STATE_DYNAMIC_PRE);
Robert Swieckia96d78d2016-03-14 16:50:50 +0100747 } else {
Jaggerebe19292016-03-17 00:11:44 +0100748 fuzz_setState(hfuzz, _HF_STATE_STATIC);
Robert Swieckia96d78d2016-03-14 16:50:50 +0100749 }
750
Jaggerea39a8f2015-09-05 00:57:22 +0200751 for (size_t i = 0; i < hfuzz->threadsMax; i++) {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000752 fuzz_runThread(hfuzz, fuzz_threadNew);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000753 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000754}