blob: 94725fa589511939ecc9c6ea6132bfa433855f18 [file] [log] [blame]
robert.swiecki3bb518c2010-10-14 00:48:24 +00001/*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00002 *
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +00003 * honggfuzz - fuzzing routines
4 * -----------------------------------------
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00005 *
robert.swiecki@gmail.com8531f692015-02-17 12:25:36 +00006 * Author:
7 * Robert Swiecki <swiecki@google.com>
8 * Felix Gröbert <groebert@google.com>
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00009 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000010 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000011 *
12 * Licensed under the Apache License, Version 2.0 (the "License"); you may
13 * not use this file except in compliance with the License. You may obtain
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000014 * a copy of the License at
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000015 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000016 * http://www.apache.org/licenses/LICENSE-2.0
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000017 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000018 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
21 * implied. See the License for the specific language governing
22 * permissions and limitations under the License.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000023 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000024 */
robert.swiecki3bb518c2010-10-14 00:48:24 +000025
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000026#include "common.h"
27#include "fuzz.h"
28
29#include <errno.h>
30#include <fcntl.h>
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +000031#include <inttypes.h>
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +000032#include <pthread.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000033#include <signal.h>
34#include <stddef.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000039#include <sys/mman.h>
40#include <sys/param.h>
41#include <sys/stat.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000042#include <sys/time.h>
43#include <sys/types.h>
44#include <sys/wait.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000045#include <time.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000046#include <unistd.h>
robert.swiecki3bb518c2010-10-14 00:48:24 +000047
robert.swiecki3bb518c2010-10-14 00:48:24 +000048#include "arch.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000049#include "files.h"
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +000050#include "log.h"
51#include "report.h"
52#include "util.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000053
54static void fuzz_mangleContent(honggfuzz_t * hfuzz, uint8_t * buf, off_t fileSz)
55{
robert.swieckicccbf0c2011-01-28 11:58:04 +000056 /*
57 * Just copy the file if "-r 0"
58 */
robert.swiecki@gmail.comb0383372015-02-13 14:17:27 +000059 uint64_t changesCnt = fileSz * hfuzz->flipRate;
60
61 if (changesCnt == 0ULL) {
robert.swieckiba512632011-01-28 11:57:26 +000062 return;
63 }
64
robert.swiecki3bb518c2010-10-14 00:48:24 +000065 if (hfuzz->flipMode == 'b') {
66 changesCnt *= 8UL;
67 }
68
69 changesCnt = util_rndGet(1, changesCnt);
70
71 for (uint64_t x = 0; x < changesCnt; x++) {
72 off_t pos = util_rndGet(0, fileSz - 1);
73
74 if (hfuzz->flipMode == 'b') {
75 buf[pos] ^= (1 << util_rndGet(0, 7));
76 } else {
77 buf[pos] = (uint8_t) util_rndGet(0, 255);
78 }
79 }
80}
81
82static void fuzz_getFileName(honggfuzz_t * hfuzz, char *fileName)
83{
robert.swieckiba512632011-01-28 11:57:26 +000084 struct timeval tv;
85 gettimeofday(&tv, NULL);
86
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000087 snprintf(fileName, PATH_MAX, ".honggfuzz.%d.%lu.%lu.%lu.%lu.%s",
88 (int)getpid(), (unsigned long int)tv.tv_sec,
89 (unsigned long int)tv.tv_usec,
90 (unsigned long int)util_rndGet(0, 1 << 30),
91 (unsigned long int)util_rndGet(0, 1 << 30), hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +000092
93 return;
94}
95
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +000096static size_t fuzz_appendOrTrunc(int fd, off_t fileSz)
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +000097{
98 const int chance_one_in_x = 10;
99 if (util_rndGet(1, chance_one_in_x) != 1) {
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000100 return fileSz;
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000101 }
102
robert.swiecki@gmail.com37f194e2015-02-03 21:35:07 +0000103 off_t maxSz = 2 * fileSz;
104 if (fileSz > (1024 * 1024 * 20)) {
105 maxSz = fileSz + (fileSz / 4);
106 }
107 if (fileSz > (1024 * 1024 * 100)) {
108 maxSz = fileSz;
109 }
110
111 off_t newSz = util_rndGet(1, maxSz);
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000112 if (ftruncate(fd, newSz) == -1) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000113 LOGMSG_P(l_WARN,
114 "Couldn't truncate file from '%ld' to '%ld' bytes", (long)fileSz, (long)newSz);
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000115 return fileSz;
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000116 }
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000117 return newSz;
118}
119
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000120static bool fuzz_prepareFileDynamically(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000121{
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000122 if (hfuzz->inputFile && hfuzz->branchBestCnt == 0) {
123 int srcfd;
124 off_t fileSz;
125 uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd);
126 if (buf == NULL) {
127 LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]);
128 return false;
129 }
130 size_t toCopy =
131 (size_t) fileSz <
132 sizeof(hfuzz->dynamicFileBest) ? (size_t) fileSz : sizeof(hfuzz->dynamicFileBest);
133 memcpy(hfuzz->dynamicFileBest, buf, toCopy);
134 hfuzz->dynamicFileBestSz = toCopy;
135 files_unmapFileCloseFd(buf, fileSz, srcfd);
136 }
137
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000138 memcpy(fuzzer->dynamicFile, hfuzz->dynamicFileBest, hfuzz->dynamicFileBestSz);
139 fuzzer->dynamicFileSz = hfuzz->dynamicFileBestSz;
140
robert.swiecki@gmail.com1aac7532015-02-18 11:34:50 +0000141 uint64_t choice = util_rndGet(1, 64);
robert.swiecki@gmail.com0078cf12015-02-18 01:23:11 +0000142 if (choice <= 8) {
robert.swiecki@gmail.com6e255ca2015-02-18 01:15:25 +0000143 fuzzer->dynamicFileSz = fuzzer->dynamicFileSz + choice;
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000144 }
robert.swiecki@gmail.com0078cf12015-02-18 01:23:11 +0000145 if (choice == 9) {
robert.swiecki@gmail.com6e255ca2015-02-18 01:15:25 +0000146 fuzzer->dynamicFileSz = util_rndGet(1, fuzzer->dynamicFileSz);
147 }
robert.swiecki@gmail.com0078cf12015-02-18 01:23:11 +0000148 if (choice == 10) {
robert.swiecki@gmail.com6e255ca2015-02-18 01:15:25 +0000149 fuzzer->dynamicFileSz = util_rndGet(fuzzer->dynamicFileSz, sizeof(fuzzer->dynamicFile));
150 }
151 if (fuzzer->dynamicFileSz > sizeof(fuzzer->dynamicFile)) {
152 fuzzer->dynamicFileSz = sizeof(fuzzer->dynamicFile);
153 }
154
robert.swiecki@gmail.com1aac7532015-02-18 11:34:50 +0000155 LOGMSG(l_DEBUG, "DynamicFile: old size:'%zu' new_size:'%zu'", hfuzz->dynamicFileBestSz,
156 fuzzer->dynamicFileSz);
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000157
158 fuzz_mangleContent(hfuzz, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
159
160 int dstfd = open(fuzzer->fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
161 if (dstfd == -1) {
162 LOGMSG_P(l_ERROR,
163 "Couldn't create a temporary file '%s' in the current directory",
164 fuzzer->fileName);
165 return false;
166 }
167
168 if (!files_writeToFd(dstfd, fuzzer->dynamicFile, fuzzer->dynamicFileSz)) {
169 close(dstfd);
170 return false;
171 }
172
173 close(dstfd);
174 return true;
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000175}
176
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000177static bool fuzz_prepareFile(honggfuzz_t * hfuzz, char *fileName, int rnd_index)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000178{
robert.swiecki3bb518c2010-10-14 00:48:24 +0000179 off_t fileSz;
180 int srcfd;
181
182 uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000183 if (buf == NULL) {
robert.swiecki56b88012010-12-31 14:04:13 +0000184 LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000185 return false;
186 }
187
188 LOGMSG(l_DEBUG, "Mmaped '%s' in R/O mode, size: %d", hfuzz->files[rnd_index], fileSz);
189
190 int dstfd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000191 if (dstfd == -1) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000192 LOGMSG_P(l_ERROR,
193 "Couldn't create a temporary file '%s' in the current directory", fileName);
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000194 files_unmapFileCloseFd(buf, fileSz, srcfd);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000195 return false;
196 }
197
198 fuzz_mangleContent(hfuzz, buf, fileSz);
199
200 if (!files_writeToFd(dstfd, buf, fileSz)) {
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000201 files_unmapFileCloseFd(buf, fileSz, srcfd);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000202 close(dstfd);
203 return false;
204 }
205
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000206 files_unmapFileCloseFd(buf, fileSz, srcfd);
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000207
208 fuzz_appendOrTrunc(dstfd, fileSz);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000209 close(dstfd);
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000210
robert.swiecki3bb518c2010-10-14 00:48:24 +0000211 return true;
212}
213
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000214static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, char *fileName, int rnd_index)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000215{
robert.swiecki3d505e22010-10-14 01:17:17 +0000216 off_t fileSz;
217 int srcfd;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000218
robert.swiecki3d505e22010-10-14 01:17:17 +0000219 int dstfd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
220 if (dstfd == -1) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000221 LOGMSG_P(l_ERROR,
222 "Couldn't create a temporary file '%s' in the current directory", fileName);
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000223 return false;
224 }
225
226 LOGMSG(l_DEBUG, "Created '%f' as an input file", fileName);
227
228 if (hfuzz->inputFile) {
229 uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd);
230 if (buf == NULL) {
231 LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]);
232 close(dstfd);
233 return false;
234 }
235
236 LOGMSG(l_DEBUG, "Mmaped '%s' in R/O mode, size: %d", hfuzz->files[rnd_index], fileSz);
237
238 bool ret = files_writeToFd(dstfd, buf, fileSz);
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000239 files_unmapFileCloseFd(buf, fileSz, srcfd);
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000240
241 if (!ret) {
242 close(dstfd);
243 return false;
244 }
robert.swiecki3d505e22010-10-14 01:17:17 +0000245 }
246
robert.swiecki3d505e22010-10-14 01:17:17 +0000247 close(dstfd);
248
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000249 pid_t pid = vfork();
robert.swiecki3bb518c2010-10-14 00:48:24 +0000250 if (pid == -1) {
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000251 LOGMSG_P(l_ERROR, "Couldn't vfork");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000252 return false;
253 }
254
255 if (!pid) {
256 /*
robert.swiecki@gmail.comcdf18f92015-02-11 22:22:18 +0000257 * child performs the external file modifications
robert.swiecki3bb518c2010-10-14 00:48:24 +0000258 */
robert.swiecki3d505e22010-10-14 01:17:17 +0000259 execl(hfuzz->externalCommand, hfuzz->externalCommand, fileName, NULL);
groebert@google.comb857deb2010-10-21 19:09:29 +0000260 LOGMSG_P(l_FATAL, "Couldn't execute '%s %s'", hfuzz->externalCommand, fileName);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000261 return false;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000262 }
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000263
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000264 /*
265 * parent waits until child is done fuzzing the input file
266 */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000267 int childStatus;
268 int flags = 0;
robert.swiecki@gmail.coma2291182015-02-13 16:56:27 +0000269#if defined(__WNOTHREAD)
270 flags |= __WNOTHREAD;
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000271#endif /* defined(__WNOTHREAD) */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000272 while (wait4(pid, &childStatus, flags, NULL) != pid) ;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000273 if (WIFEXITED(childStatus)) {
274 LOGMSG(l_DEBUG, "External command exited with status %d", WEXITSTATUS(childStatus));
275 return true;
276 }
277 if (WIFSIGNALED(childStatus)) {
robert.swiecki@gmail.coma2291182015-02-13 16:56:27 +0000278 LOGMSG(l_ERROR, "External command terminated with signal %d", WTERMSIG(childStatus));
robert.swiecki3d505e22010-10-14 01:17:17 +0000279 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000280 }
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000281 LOGMSG(l_FATAL, "External command terminated abnormally, status: %d", childStatus);
282 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000283
284 abort(); /* NOTREACHED */
285}
286
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000287static int fuzz_numOfProc(honggfuzz_t * hfuzz)
288{
289 int i;
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000290 sem_getvalue(hfuzz->sem, &i);
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000291 return hfuzz->threadsMax - i;
292}
293
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000294static void *fuzz_threadNew(void *arg)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000295{
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000296 honggfuzz_t *hfuzz = (honggfuzz_t *) arg;
297 fuzzer_t fuzzer = {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000298 .pid = 0,
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000299 .timeStarted = time(NULL),
300 .pc = 0ULL,
301 .backtrace = 0ULL,
302 .access = 0ULL,
303 .exception = 0,
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000304 .dynamicFileSz = 0,
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000305 .branchCnt = 0,
306 .report = {'\0'}
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000307 };
robert.swiecki3bb518c2010-10-14 00:48:24 +0000308
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000309 int rnd_index = util_rndGet(0, hfuzz->fileCnt - 1);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000310 strncpy(fuzzer.origFileName, files_basename(hfuzz->files[rnd_index]), PATH_MAX);
311 fuzz_getFileName(hfuzz, fuzzer.fileName);
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000312
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000313 if (hfuzz->createDynamically) {
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000314 if (!fuzz_prepareFileDynamically(hfuzz, &fuzzer, rnd_index)) {
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000315 exit(EXIT_FAILURE);
316 }
317 } else if (hfuzz->externalCommand != NULL) {
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000318 if (!fuzz_prepareFileExternally(hfuzz, fuzzer.fileName, rnd_index)) {
319 exit(EXIT_FAILURE);
320 }
321 } else {
322 if (!fuzz_prepareFile(hfuzz, fuzzer.fileName, rnd_index)) {
323 exit(EXIT_FAILURE);
324 }
robert.swiecki@gmail.com1f98a162015-02-11 15:09:22 +0000325 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000326
robert.swiecki@gmail.comdfde1c72015-02-18 13:22:55 +0000327#if _HF_ARCH == LINUX
328#include <unistd.h>
329#include <sys/syscall.h>
330 fuzzer.pid = syscall(__NR_fork);
331#else
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000332 fuzzer.pid = fork();
robert.swiecki@gmail.comdfde1c72015-02-18 13:22:55 +0000333#endif /* _HF_ARCH == LINUX */
334
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000335 if (fuzzer.pid == -1) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000336 LOGMSG_P(l_FATAL, "Couldn't fork");
337 exit(EXIT_FAILURE);
338 }
339
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000340 if (!fuzzer.pid) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000341 /*
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000342 * Ok, kill the parent if this fails
robert.swiecki3bb518c2010-10-14 00:48:24 +0000343 */
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000344 if (!arch_launchChild(hfuzz, fuzzer.fileName)) {
robert.swiecki@gmail.com6f5c2392015-02-16 18:13:09 +0000345 LOGMSG(l_ERROR, "Error launching child process, killing parent");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000346 exit(EXIT_FAILURE);
347 }
348 }
349
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000350 LOGMSG(l_INFO, "Launched new process, pid: %d, (%d/%d)", fuzzer.pid,
351 fuzz_numOfProc(hfuzz), hfuzz->threadsMax);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000352
353 arch_reapChild(hfuzz, &fuzzer);
354 unlink(fuzzer.fileName);
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000355
356 if (hfuzz->createDynamically) {
357 if (fuzzer.branchCnt >= hfuzz->branchBestCnt) {
358 LOGMSG(l_INFO,
359 "New file: OLD_SZ: '%llu', NEW_SZ: '%llu', OLD_BRANCHES: '%llu', NEW_BRACNHES: '%llu'",
360 hfuzz->dynamicFileBestSz, fuzzer.dynamicFileSz, hfuzz->branchBestCnt,
361 fuzzer.branchCnt);
362 memcpy(hfuzz->dynamicFileBest, fuzzer.dynamicFile, fuzzer.dynamicFileSz);
363 hfuzz->dynamicFileBestSz = fuzzer.dynamicFileSz;
364 hfuzz->branchBestCnt = fuzzer.branchCnt;
365 }
366 }
367
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000368 report_Report(hfuzz, fuzzer.report);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000369
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000370 sem_post(hfuzz->sem);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000371
372 return NULL;
373}
374
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000375static void *fuzz_threadPid(void *arg)
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000376{
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000377 honggfuzz_t *hfuzz = (honggfuzz_t *) arg;
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000378 if (!arch_archInit(hfuzz)) {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000379 LOGMSG(l_FATAL, "Couldn't prepare parent for fuzzing");
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000380 }
381
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000382 fuzzer_t fuzzer = {
383 .pid = hfuzz->pid,
384 .timeStarted = time(NULL),
385 .pc = 0ULL,
386 .backtrace = 0ULL,
387 .access = 0ULL,
388 .exception = 0,
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000389 .dynamicFileSz = 0,
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000390 .branchCnt = 0,
391 .report = {'\0'}
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000392 };
393
394 char fileName[] = ".honggfuzz.empty.XXXXXX";
395 int fd;
396 if ((fd = mkstemp(fileName)) == -1) {
397 LOGMSG_P(l_ERROR, "Couldn't create a temporary file");
398 return NULL;
399 }
400 close(fd);
401
402 strncpy(fuzzer.origFileName, "PID_FUZZING", PATH_MAX);
403 strncpy(fuzzer.fileName, fileName, PATH_MAX);
404
405 arch_reapChild(hfuzz, &fuzzer);
406 unlink(fuzzer.fileName);
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000407 report_Report(hfuzz, fuzzer.report);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000408
409 // There's no more hfuzz->pid to analyze. Just exit
410 LOGMSG(l_INFO, "PID: %d exited. Exiting", fuzzer.pid);
411 exit(EXIT_SUCCESS);
412
413 return NULL;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000414}
415
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000416static void fuzz_runThread(honggfuzz_t * hfuzz, void *(*thread) (void *))
417{
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000418 pthread_attr_t attr;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000419
robert.swiecki@gmail.com6f5c2392015-02-16 18:13:09 +0000420 pthread_attr_init(&attr);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000421 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
robert.swiecki@gmail.com01b6dd42015-02-16 18:11:28 +0000422 pthread_attr_setstacksize(&attr, _HF_PTHREAD_STACKSIZE);
robert.swiecki@gmail.com011981f2015-02-17 19:06:44 +0000423 pthread_attr_setguardsize(&attr, (size_t) sysconf(_SC_PAGESIZE));
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000424
robert.swiecki@gmail.com01b6dd42015-02-16 18:11:28 +0000425 pthread_t t;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000426 if (pthread_create(&t, &attr, thread, (void *)hfuzz) < 0) {
427 LOGMSG_P(l_FATAL, "Couldn't create a new thread");
428 }
429
430 return;
431}
432
robert.swiecki3bb518c2010-10-14 00:48:24 +0000433void fuzz_main(honggfuzz_t * hfuzz)
434{
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000435 char semName[PATH_MAX];
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000436 snprintf(semName, sizeof(semName), "honggfuzz.%d.%d.%" PRIx64, getpid(),
437 (int)time(NULL), util_rndGet(1, 1ULL << 62));
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000438
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000439 hfuzz->sem = sem_open(semName, O_CREAT, 0644, hfuzz->threadsMax);
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000440 if (hfuzz->sem == SEM_FAILED) {
441 LOGMSG_P(l_FATAL, "sem_open() failed");
robert.swiecki@gmail.come7635392015-02-11 16:17:49 +0000442 }
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000443 // If we're doing a PID fuzzing, the parent of the PID will be a
444 // dedicated thread anyway
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000445 if (hfuzz->pid) {
446 fuzz_runThread(hfuzz, fuzz_threadPid);
447 } else {
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000448 if (!arch_archInit(hfuzz)) {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000449 LOGMSG(l_FATAL, "Couldn't prepare parent for fuzzing");
450 }
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000451 }
452
robert.swiecki3bb518c2010-10-14 00:48:24 +0000453 for (;;) {
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000454 if (sem_wait(hfuzz->sem) == -1) {
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000455 LOGMSG_P(l_FATAL, "sem_wait() failed");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000456 }
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000457
458 if (hfuzz->mutationsMax && (hfuzz->mutationsCnt >= hfuzz->mutationsMax)) {
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000459 /*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +0000460 * Sleep a bit to let any running fuzzers terminate
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000461 */
groebert@google.com20e368f2015-02-13 14:19:25 +0000462 usleep(1.2 * hfuzz->tmOut * 1000000);
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000463 LOGMSG(l_INFO, "Finished fuzzing %ld times.", hfuzz->mutationsMax);
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000464 sem_destroy(hfuzz->sem);
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000465 exit(EXIT_SUCCESS);
466 }
467
468 hfuzz->mutationsCnt++;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000469 fuzz_runThread(hfuzz, fuzz_threadNew);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000470 }
471}