blob: 7f8bd197d5019b0241503409597242d2569860e4 [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"
robert.swiecki@gmail.com36700b52015-02-22 05:03:16 +000051#include "mangle.h"
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +000052#include "report.h"
53#include "util.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000054
robert.swiecki3bb518c2010-10-14 00:48:24 +000055static void fuzz_getFileName(honggfuzz_t * hfuzz, char *fileName)
56{
robert.swieckiba512632011-01-28 11:57:26 +000057 struct timeval tv;
58 gettimeofday(&tv, NULL);
59
robert.swiecki@gmail.com6f319912015-02-28 05:01:37 +000060 snprintf(fileName, PATH_MAX, ".honggfuzz.%d.%lu.%llx.%s", (int)getpid(),
61 (unsigned long int)tv.tv_sec, (unsigned long long int)util_rndGet(0, 1ULL << 62),
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +000062 hfuzz->fileExtn);
robert.swiecki3bb518c2010-10-14 00:48:24 +000063
64 return;
65}
66
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +000067static bool fuzz_prepareFileDynamically(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +000068{
robert.swiecki@gmail.com41d8e052015-02-19 01:10:41 +000069 while (pthread_mutex_lock(&hfuzz->dynamicFile_mutex)) ;
70
robert.swiecki@gmail.comd2391392015-02-26 01:34:10 +000071 if (hfuzz->inputFile && hfuzz->branchBestCnt == 0) {
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +000072 int srcfd = open(hfuzz->files[rnd_index], O_RDONLY);
73 if (srcfd == -1) {
74 LOGMSG_P(l_ERROR, "Couldn't open '%s' to read", hfuzz->files[rnd_index]);
robert.swiecki@gmail.com41d8e052015-02-19 01:10:41 +000075 while (pthread_mutex_unlock(&hfuzz->dynamicFile_mutex)) ;
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +000076 return false;
77 }
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +000078 struct stat sbuf;
79 if (fstat(srcfd, &sbuf) == -1) {
80 LOGMSG_P(l_ERROR, "Couldn't stat '%s' (fd='%d')", hfuzz->files[rnd_index], srcfd);
81 while (pthread_mutex_unlock(&hfuzz->dynamicFile_mutex)) ;
82 close(srcfd);
83 return false;
robert.swiecki@gmail.com3109d0a2015-02-25 18:12:45 +000084 }
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +000085
robert.swiecki@gmail.com3109d0a2015-02-25 18:12:45 +000086 if ((size_t) sbuf.st_size > hfuzz->maxFileSz) {
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +000087 while (pthread_mutex_unlock(&hfuzz->dynamicFile_mutex)) ;
88 close(srcfd);
89 LOGMSG(l_ERROR,
robert.swiecki@gmail.com0a7eabe2015-02-22 14:47:45 +000090 "File size (%zu) is bigger than the maximal allocated buffer/file size (-F) (%zu)",
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +000091 sbuf.st_size, hfuzz->maxFileSz);
92 return false;
robert.swiecki@gmail.com0a7eabe2015-02-22 14:47:45 +000093 }
94
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +000095 if (files_readFromFd(srcfd, hfuzz->dynamicFileBest, sbuf.st_size) == false) {
96 while (pthread_mutex_unlock(&hfuzz->dynamicFile_mutex)) ;
97 close(srcfd);
robert.swiecki@gmail.com3109d0a2015-02-25 18:12:45 +000098 LOGMSG(l_ERROR, "Could read '%zu' bytes from '%s' (fd='%d')", sbuf.st_size,
99 hfuzz->files[rnd_index], srcfd);
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +0000100 return false;
101 }
102 hfuzz->dynamicFileBestSz = sbuf.st_size;
robert.swiecki@gmail.comd2391392015-02-26 01:34:10 +0000103 hfuzz->branchBestCnt = 1;
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +0000104 close(srcfd);
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000105 }
106
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000107 fuzzer->dynamicFileSz = hfuzz->dynamicFileBestSz;
robert.swiecki@gmail.com3b6c6292015-02-26 11:48:46 +0000108 memcpy(fuzzer->dynamicFile, hfuzz->dynamicFileBest, hfuzz->dynamicFileBestSz);
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000109
robert.swiecki@gmail.com41d8e052015-02-19 01:10:41 +0000110 while (pthread_mutex_unlock(&hfuzz->dynamicFile_mutex)) ;
111
robert.swiecki@gmail.com141c4522015-02-19 15:49:23 +0000112 /* The first pass should be on an empty/initial file */
113 if (hfuzz->branchBestCnt > 0) {
robert.swiecki5fa9d902015-02-25 15:31:56 +0000114 if (mangle_Resize(hfuzz, NULL, &fuzzer->dynamicFileSz, -1) == false) {
robert.swiecki@gmail.com173f5192015-02-23 00:06:47 +0000115 return false;
116 }
robert.swiecki@gmail.com36700b52015-02-22 05:03:16 +0000117 mangle_mangleContent(hfuzz, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
robert.swiecki@gmail.com141c4522015-02-19 15:49:23 +0000118 }
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000119
robert.swiecki@gmail.com3b6c6292015-02-26 11:48:46 +0000120 int dstfd;
121 uint8_t *buf = files_mapFileToWriteIni(fuzzer->fileName, fuzzer->dynamicFileSz, &dstfd,
122 fuzzer->dynamicFile);
123 if (buf == NULL) {
124 LOGMSG(l_ERROR, "Couldn't map file '%s' in R/W mode, size=%zu", fuzzer->fileName,
125 fuzzer->dynamicFile);
126 return false;
127 }
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +0000128 files_unmapFileCloseFdMSync(buf, fuzzer->dynamicFileSz, dstfd);
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000129
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000130 return true;
robert.swiecki@gmail.comd7aed312015-02-03 21:26:37 +0000131}
132
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000133static bool fuzz_prepareFile(honggfuzz_t * hfuzz, char *fileName, int rnd_index)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000134{
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000135 int srcfd = open(hfuzz->files[rnd_index], O_RDONLY);
136 if (srcfd == -1) {
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000137 LOGMSG_P(l_ERROR, "Couldn't open '%s' for R/O", hfuzz->files[rnd_index]);
138 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000139 }
140
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000141 struct stat sbuf;
142 if (fstat(srcfd, &sbuf) == -1) {
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000143 LOGMSG_P(l_ERROR, "Couldn't fstat(fd='%s' fname='%s')", srcfd, hfuzz->files[rnd_index]);
144 close(srcfd);
145 return false;
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000146 }
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000147 size_t fileSz = (size_t) sbuf.st_size;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000148
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000149 uint8_t *tmpbuf = malloc(fileSz);
150 if (tmpbuf == NULL) {
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000151 LOGMSG_P(l_ERROR, "Couldn't malloc(size='%zu')", fileSz);
152 close(srcfd);
153 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000154 }
155
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000156 if (files_readFromFd(srcfd, tmpbuf, fileSz) == false) {
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000157 LOGMSG(l_ERROR, "Couldn't read '%zu' bytes from '%s' (fd='%d')", fileSz,
158 hfuzz->files[rnd_index], srcfd);
159 close(srcfd);
160 free(tmpbuf);
161 return false;
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000162 }
163 close(srcfd);
164
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000165 int dstfd;
166 uint8_t *buf = files_mapFileToWriteIni(fileName, fileSz, &dstfd, tmpbuf);
167 if (buf == NULL) {
168 LOGMSG(l_ERROR, "Couldn't map '%s' for R/W, size='%zu'", fileName, fileSz);
169 free(tmpbuf);
170 return false;
171 }
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000172
173 free(tmpbuf);
174
175 if (mangle_Resize(hfuzz, &buf, &fileSz, dstfd) == false) {
176 files_unmapFileCloseFd(buf, fileSz, dstfd);
robert.swiecki@gmail.come7680522015-02-22 22:22:37 +0000177 LOGMSG(l_ERROR, "File resizing failed");
178 return false;
179 }
180
robert.swiecki@gmail.com36700b52015-02-22 05:03:16 +0000181 mangle_mangleContent(hfuzz, buf, fileSz);
robert.swiecki@gmail.comc070b942015-02-25 18:29:19 +0000182 files_unmapFileCloseFdMSync(buf, fileSz, dstfd);
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000183
robert.swiecki3bb518c2010-10-14 00:48:24 +0000184 return true;
185}
186
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000187static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, char *fileName, int rnd_index)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000188{
robert.swiecki@gmail.com0a7eabe2015-02-22 14:47:45 +0000189 size_t fileSz;
robert.swiecki3d505e22010-10-14 01:17:17 +0000190 int srcfd;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000191
robert.swiecki3d505e22010-10-14 01:17:17 +0000192 int dstfd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
193 if (dstfd == -1) {
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000194 LOGMSG_P(l_ERROR, "Couldn't create a temporary file '%s' in the current directory",
195 fileName);
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000196 return false;
197 }
198
199 LOGMSG(l_DEBUG, "Created '%f' as an input file", fileName);
200
201 if (hfuzz->inputFile) {
202 uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd);
203 if (buf == NULL) {
204 LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]);
205 close(dstfd);
206 return false;
207 }
208
209 LOGMSG(l_DEBUG, "Mmaped '%s' in R/O mode, size: %d", hfuzz->files[rnd_index], fileSz);
210
211 bool ret = files_writeToFd(dstfd, buf, fileSz);
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000212 files_unmapFileCloseFd(buf, fileSz, srcfd);
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000213
214 if (!ret) {
215 close(dstfd);
216 return false;
217 }
robert.swiecki3d505e22010-10-14 01:17:17 +0000218 }
219
robert.swiecki3d505e22010-10-14 01:17:17 +0000220 close(dstfd);
221
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000222 pid_t pid = vfork();
robert.swiecki3bb518c2010-10-14 00:48:24 +0000223 if (pid == -1) {
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000224 LOGMSG_P(l_ERROR, "Couldn't vfork");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000225 return false;
226 }
227
228 if (!pid) {
229 /*
robert.swiecki@gmail.comcdf18f92015-02-11 22:22:18 +0000230 * child performs the external file modifications
robert.swiecki3bb518c2010-10-14 00:48:24 +0000231 */
robert.swiecki3d505e22010-10-14 01:17:17 +0000232 execl(hfuzz->externalCommand, hfuzz->externalCommand, fileName, NULL);
groebert@google.comb857deb2010-10-21 19:09:29 +0000233 LOGMSG_P(l_FATAL, "Couldn't execute '%s %s'", hfuzz->externalCommand, fileName);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000234 return false;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000235 }
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000236
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000237 /*
238 * parent waits until child is done fuzzing the input file
239 */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000240 int childStatus;
241 int flags = 0;
robert.swiecki@gmail.coma2291182015-02-13 16:56:27 +0000242#if defined(__WNOTHREAD)
243 flags |= __WNOTHREAD;
robert.swiecki@gmail.com8a9df0e2015-02-13 17:08:06 +0000244#endif /* defined(__WNOTHREAD) */
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000245 while (wait4(pid, &childStatus, flags, NULL) != pid) ;
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000246 if (WIFEXITED(childStatus)) {
247 LOGMSG(l_DEBUG, "External command exited with status %d", WEXITSTATUS(childStatus));
248 return true;
249 }
250 if (WIFSIGNALED(childStatus)) {
robert.swiecki@gmail.coma2291182015-02-13 16:56:27 +0000251 LOGMSG(l_ERROR, "External command terminated with signal %d", WTERMSIG(childStatus));
robert.swiecki3d505e22010-10-14 01:17:17 +0000252 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000253 }
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000254 LOGMSG(l_FATAL, "External command terminated abnormally, status: %d", childStatus);
255 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000256
257 abort(); /* NOTREACHED */
258}
259
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000260static int fuzz_numOfProc(honggfuzz_t * hfuzz)
261{
262 int i;
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000263 sem_getvalue(hfuzz->sem, &i);
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000264 return hfuzz->threadsMax - i;
265}
266
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000267static void *fuzz_threadNew(void *arg)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000268{
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000269 honggfuzz_t *hfuzz = (honggfuzz_t *) arg;
270 fuzzer_t fuzzer = {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000271 .pid = 0,
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000272 .timeStarted = time(NULL),
273 .pc = 0ULL,
274 .backtrace = 0ULL,
275 .access = 0ULL,
276 .exception = 0,
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000277 .dynamicFileSz = 0,
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000278 .dynamicFile = malloc(hfuzz->maxFileSz),
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000279 .branchCnt = 0,
280 .report = {'\0'}
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000281 };
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000282 if (fuzzer.dynamicFile == NULL) {
283 LOGMSG(l_FATAL, "malloc(%zu) failed", hfuzz->maxFileSz);
284 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000285
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000286 int rnd_index = util_rndGet(0, hfuzz->fileCnt - 1);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000287 strncpy(fuzzer.origFileName, files_basename(hfuzz->files[rnd_index]), PATH_MAX);
288 fuzz_getFileName(hfuzz, fuzzer.fileName);
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000289
robert.swiecki@gmail.comcac22fd2015-02-19 14:03:28 +0000290 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
robert.swiecki@gmail.com624233e2015-02-18 10:26:05 +0000291 if (!fuzz_prepareFileDynamically(hfuzz, &fuzzer, rnd_index)) {
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000292 exit(EXIT_FAILURE);
293 }
294 } else if (hfuzz->externalCommand != NULL) {
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000295 if (!fuzz_prepareFileExternally(hfuzz, fuzzer.fileName, rnd_index)) {
296 exit(EXIT_FAILURE);
297 }
298 } else {
299 if (!fuzz_prepareFile(hfuzz, fuzzer.fileName, rnd_index)) {
300 exit(EXIT_FAILURE);
301 }
robert.swiecki@gmail.com1f98a162015-02-11 15:09:22 +0000302 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000303
robert.swiecki5fa9d902015-02-25 15:31:56 +0000304#if defined(_HF_ARCH_LINUX)
robert.swiecki@gmail.comdfde1c72015-02-18 13:22:55 +0000305#include <unistd.h>
306#include <sys/syscall.h>
307 fuzzer.pid = syscall(__NR_fork);
robert.swiecki@gmail.com4fc19692015-02-25 15:45:11 +0000308#else /* defined(_HF_ARCH_LINUX) */
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000309 fuzzer.pid = fork();
robert.swiecki5fa9d902015-02-25 15:31:56 +0000310#endif /* defined(_HF_ARCH_LINUX) */
robert.swiecki@gmail.comdfde1c72015-02-18 13:22:55 +0000311
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000312 if (fuzzer.pid == -1) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000313 LOGMSG_P(l_FATAL, "Couldn't fork");
314 exit(EXIT_FAILURE);
315 }
316
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000317 if (!fuzzer.pid) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000318 /*
robert.swiecki@gmail.com6ff9af82015-02-11 18:52:05 +0000319 * Ok, kill the parent if this fails
robert.swiecki3bb518c2010-10-14 00:48:24 +0000320 */
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000321 if (!arch_launchChild(hfuzz, fuzzer.fileName)) {
robert.swiecki@gmail.com6f5c2392015-02-16 18:13:09 +0000322 LOGMSG(l_ERROR, "Error launching child process, killing parent");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000323 exit(EXIT_FAILURE);
324 }
325 }
326
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000327 LOGMSG(l_INFO, "Launched new process, pid: %d, (%d/%d)", fuzzer.pid, fuzz_numOfProc(hfuzz),
328 hfuzz->threadsMax);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000329
330 arch_reapChild(hfuzz, &fuzzer);
331 unlink(fuzzer.fileName);
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000332
robert.swiecki@gmail.comcac22fd2015-02-19 14:03:28 +0000333 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
robert.swiecki@gmail.com41d8e052015-02-19 01:10:41 +0000334 while (pthread_mutex_lock(&hfuzz->dynamicFile_mutex)) ;
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000335 if (fuzzer.branchCnt >= hfuzz->branchBestCnt) {
336 LOGMSG(l_INFO,
robert.swiecki@gmail.come342f222015-02-28 05:10:03 +0000337 "New BEST feedback: File Size (New/Old): %zu/%zu', Perf feedback (Curr/High): %"
338 PRId64 "/%" PRId64, fuzzer.dynamicFileSz, hfuzz->dynamicFileBestSz,
339 fuzzer.branchCnt, hfuzz->branchBestCnt);
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000340 memcpy(hfuzz->dynamicFileBest, fuzzer.dynamicFile, fuzzer.dynamicFileSz);
341 hfuzz->dynamicFileBestSz = fuzzer.dynamicFileSz;
342 hfuzz->branchBestCnt = fuzzer.branchCnt;
robert.swiecki@gmail.com85a0a952015-02-19 01:58:39 +0000343
robert.swiecki@gmail.comba92e192015-02-21 02:14:07 +0000344#define _HF_CURRENT_BEST "CURRENT_BEST"
345#define _HF_CURRENT_BEST_TMP ".tmp.CURRENT_BEST"
346 int fd = open(_HF_CURRENT_BEST_TMP, O_CREAT | O_WRONLY | O_TRUNC, 0644);
347 if (fd != -1) {
348 if (files_writeToFd(fd, fuzzer.dynamicFile, fuzzer.dynamicFileSz)) {
349 rename(_HF_CURRENT_BEST_TMP, _HF_CURRENT_BEST);
robert.swiecki@gmail.com2421ce82015-02-26 11:33:11 +0000350 } else {
351 unlink(_HF_CURRENT_BEST_TMP);
robert.swiecki@gmail.comba92e192015-02-21 02:14:07 +0000352 }
robert.swiecki@gmail.comba92e192015-02-21 02:14:07 +0000353 close(fd);
354 }
robert.swiecki@gmail.com85a0a952015-02-19 01:58:39 +0000355
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000356 }
robert.swiecki@gmail.com41d8e052015-02-19 01:10:41 +0000357 while (pthread_mutex_unlock(&hfuzz->dynamicFile_mutex)) ;
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000358 }
359
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000360 report_Report(hfuzz, fuzzer.report);
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000361 free(fuzzer.dynamicFile);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000362
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000363 sem_post(hfuzz->sem);
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000364
365 return NULL;
366}
367
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000368static void *fuzz_threadPid(void *arg)
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000369{
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000370 honggfuzz_t *hfuzz = (honggfuzz_t *) arg;
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000371 if (!arch_archInit(hfuzz)) {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000372 LOGMSG(l_FATAL, "Couldn't prepare parent for fuzzing");
robert.swiecki@gmail.com882900b2015-02-11 13:56:22 +0000373 }
374
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000375 fuzzer_t fuzzer = {
376 .pid = hfuzz->pid,
377 .timeStarted = time(NULL),
378 .pc = 0ULL,
379 .backtrace = 0ULL,
380 .access = 0ULL,
381 .exception = 0,
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000382 .dynamicFileSz = 0,
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000383 .dynamicFile = malloc(hfuzz->maxFileSz),
robert.swiecki@gmail.comd4dd4df2015-02-18 00:50:12 +0000384 .branchCnt = 0,
385 .report = {'\0'}
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000386 };
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000387 if (fuzzer.dynamicFile == NULL) {
388 LOGMSG(l_FATAL, "malloc(%zu) failed", hfuzz->maxFileSz);
389 }
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000390
391 char fileName[] = ".honggfuzz.empty.XXXXXX";
392 int fd;
393 if ((fd = mkstemp(fileName)) == -1) {
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000394 free(fuzzer.dynamicFile);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000395 LOGMSG_P(l_ERROR, "Couldn't create a temporary file");
396 return NULL;
397 }
398 close(fd);
399
400 strncpy(fuzzer.origFileName, "PID_FUZZING", PATH_MAX);
401 strncpy(fuzzer.fileName, fileName, PATH_MAX);
402
403 arch_reapChild(hfuzz, &fuzzer);
404 unlink(fuzzer.fileName);
robert.swiecki@gmail.come7190b92015-02-14 23:05:42 +0000405 report_Report(hfuzz, fuzzer.report);
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000406 free(fuzzer.dynamicFile);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000407
408 // There's no more hfuzz->pid to analyze. Just exit
409 LOGMSG(l_INFO, "PID: %d exited. Exiting", fuzzer.pid);
410 exit(EXIT_SUCCESS);
411
412 return NULL;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000413}
414
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000415static void fuzz_runThread(honggfuzz_t * hfuzz, void *(*thread) (void *))
416{
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000417 pthread_attr_t attr;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000418
robert.swiecki@gmail.com6f5c2392015-02-16 18:13:09 +0000419 pthread_attr_init(&attr);
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000420 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
robert.swiecki@gmail.com441089a2015-02-23 13:14:07 +0000421 pthread_attr_setstacksize(&attr, _HF_PTHREAD_STACKSIZE);
robert.swiecki@gmail.com011981f2015-02-17 19:06:44 +0000422 pthread_attr_setguardsize(&attr, (size_t) sysconf(_SC_PAGESIZE));
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000423
robert.swiecki@gmail.com01b6dd42015-02-16 18:11:28 +0000424 pthread_t t;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000425 if (pthread_create(&t, &attr, thread, (void *)hfuzz) < 0) {
426 LOGMSG_P(l_FATAL, "Couldn't create a new thread");
427 }
428
429 return;
430}
431
robert.swiecki3bb518c2010-10-14 00:48:24 +0000432void fuzz_main(honggfuzz_t * hfuzz)
433{
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000434 char semName[PATH_MAX];
robert.swiecki5fa9d902015-02-25 15:31:56 +0000435 snprintf(semName, sizeof(semName), "/honggfuzz.%d.%d.%" PRIx64, getpid(),
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000436 (int)time(NULL), util_rndGet(1, 1ULL << 62));
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000437
robert.swiecki@gmail.com757ee192015-02-13 16:54:02 +0000438 hfuzz->sem = sem_open(semName, O_CREAT, 0644, hfuzz->threadsMax);
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000439 if (hfuzz->sem == SEM_FAILED) {
440 LOGMSG_P(l_FATAL, "sem_open() failed");
robert.swiecki@gmail.come7635392015-02-11 16:17:49 +0000441 }
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +0000442 // If we're doing a PID fuzzing, the parent of the PID will be a
443 // dedicated thread anyway
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000444 if (hfuzz->pid) {
445 fuzz_runThread(hfuzz, fuzz_threadPid);
446 } else {
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000447 if (!arch_archInit(hfuzz)) {
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000448 LOGMSG(l_FATAL, "Couldn't prepare parent for fuzzing");
449 }
robert.swiecki@gmail.comef829fa2011-06-22 13:51:57 +0000450 }
451
robert.swiecki3bb518c2010-10-14 00:48:24 +0000452 for (;;) {
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000453 if (sem_wait(hfuzz->sem) == -1) {
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000454 LOGMSG_P(l_FATAL, "sem_wait() failed");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000455 }
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000456
457 if (hfuzz->mutationsMax && (hfuzz->mutationsCnt >= hfuzz->mutationsMax)) {
robert.swiecki@gmail.com89068552015-02-28 05:18:25 +0000458#if defined(_HF_ARCH_DARWIN)
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.com89068552015-02-28 05:18:25 +0000463#else /* defined(_HF_ARCH_DARWIN) */
464 while (fuzz_numOfProc(hfuzz) > 1) {
robert.swiecki@gmail.com09df3dc2015-02-28 05:25:45 +0000465 usleep(10000);
robert.swiecki@gmail.com89068552015-02-28 05:18:25 +0000466 }
467#endif /* defined(_HF_ARCH_DARWIN) */
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000468 LOGMSG(l_INFO, "Finished fuzzing %ld times.", hfuzz->mutationsMax);
robert.swiecki@gmail.com9bc725e2015-02-13 12:40:06 +0000469 sem_destroy(hfuzz->sem);
robert.swiecki@gmail.come507cb62015-02-11 17:14:49 +0000470 exit(EXIT_SUCCESS);
471 }
472
473 hfuzz->mutationsCnt++;
robert.swiecki@gmail.comc8443142015-02-13 13:46:40 +0000474 fuzz_runThread(hfuzz, fuzz_threadNew);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000475 }
476}