1 /*
2 *
3 * honggfuzz - fuzzing routines
4 * -----------------------------------------
5 *
6 * Author:
7 * Robert Swiecki <swiecki@google.com>
8 * Felix Gröbert <groebert@google.com>
9 *
10 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
11 *
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
14 * a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * 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.
23 *
24 */
25
26 #include "common.h"
27 #include "fuzz.h"
28
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <inttypes.h>
32 #include <pthread.h>
33 #include <signal.h>
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/param.h>
40 #include <sys/resource.h>
41 #include <sys/mman.h>
42 #include <sys/stat.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <time.h>
47 #include <unistd.h>
48
49 #include "arch.h"
50 #include "files.h"
51 #include "log.h"
52 #include "mangle.h"
53 #include "report.h"
54 #include "sancov.h"
55 #include "util.h"
56
57 extern char **environ;
58
59 static pthread_t fuzz_mainThread;
60
fuzz_getFileName(honggfuzz_t * hfuzz,char * fileName)61 static void fuzz_getFileName(honggfuzz_t * hfuzz, char *fileName)
62 {
63 struct timeval tv;
64 gettimeofday(&tv, NULL);
65
66 snprintf(fileName, PATH_MAX, "%s/.honggfuzz.%d.%lu.%llx.%s", hfuzz->workDir, (int)getpid(),
67 (unsigned long int)tv.tv_sec, (unsigned long long int)util_rndGet(0, 1ULL << 62),
68 hfuzz->fileExtn);
69 }
70
fuzz_prepareExecve(honggfuzz_t * hfuzz,const char * fileName)71 static 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 */
76 if (hfuzz->tmOut) {
77 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) {
87 PLOG_D("Couldn't set the ITIMER_PROF timer");
88 }
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) {
114 PLOG_D("Couldn't enforce the RLIMIT_CPU resource limit");
115 }
116 }
117
118 /*
119 * The address space limit. If big enough - roughly the size of RAM used
120 */
121 if (hfuzz->asLimit) {
122 struct rlimit rl = {
123 .rlim_cur = hfuzz->asLimit * 1024ULL * 1024ULL,
124 .rlim_max = hfuzz->asLimit * 1024ULL * 1024ULL,
125 };
126 if (setrlimit(RLIMIT_AS, &rl) == -1) {
127 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
144 if (hfuzz->clearEnv) {
145 environ = NULL;
146 }
147 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
156 return true;
157 }
158
fuzz_prepareFileDynamically(honggfuzz_t * hfuzz,fuzzer_t * fuzzer)159 static bool fuzz_prepareFileDynamically(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
160 {
161 struct dynfile_t *dynfile;
162
163 {
164 MX_LOCK(&hfuzz->dynfileq_mutex);
165 DEFER(MX_UNLOCK(&hfuzz->dynfileq_mutex));
166
167 if (hfuzz->dynfileqCnt == 0) {
168 LOG_F("No files in the dynamic queue. The initial phase did not "
169 "result in positive counters/coverage");
170 }
171
172 size_t i = 0U;
173 size_t dynFilePos = util_rndGet(0, hfuzz->dynfileqCnt - 1);
174 TAILQ_FOREACH(dynfile, &hfuzz->dynfileq, pointers) {
175 if (i++ == dynFilePos) {
176 break;
177 }
178 }
179 }
180
181 memcpy(fuzzer->dynamicFile, dynfile->data, dynfile->size);
182 fuzzer->dynamicFileSz = dynfile->size;
183
184 mangle_Resize(hfuzz, fuzzer->dynamicFile, &fuzzer->dynamicFileSz);
185 mangle_mangleContent(hfuzz, fuzzer);
186
187 if (files_writeBufToFile
188 (fuzzer->fileName, fuzzer->dynamicFile, fuzzer->dynamicFileSz,
189 O_WRONLY | O_CREAT | O_EXCL | O_TRUNC) == false) {
190 LOG_E("Couldn't write buffer to file '%s'", fuzzer->fileName);
191 return false;
192 }
193
194 return true;
195 }
196
fuzz_prepareFile(honggfuzz_t * hfuzz,fuzzer_t * fuzzer,int rnd_index)197 static bool fuzz_prepareFile(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
198 {
199 size_t fileSz =
200 files_readFileToBufMax(hfuzz->files[rnd_index], fuzzer->dynamicFile, hfuzz->maxFileSz);
201 if (fileSz == 0UL) {
202 LOG_E("Couldn't read contents of '%s'", hfuzz->files[rnd_index]);
203 return false;
204 }
205 fuzzer->dynamicFileSz = fileSz;
206
207 /* If flip rate is 0.0, early abort file mangling */
208 if (fuzzer->flipRate != 0.0L) {
209 mangle_Resize(hfuzz, fuzzer->dynamicFile, &fuzzer->dynamicFileSz);
210 mangle_mangleContent(hfuzz, fuzzer);
211 }
212
213 if (files_writeBufToFile
214 (fuzzer->fileName, fuzzer->dynamicFile, fuzzer->dynamicFileSz,
215 O_WRONLY | O_CREAT | O_EXCL) == false) {
216 LOG_E("Couldn't write buffer to file '%s'", fuzzer->fileName);
217 return false;
218 }
219
220 return true;
221 }
222
fuzz_prepareFileExternally(honggfuzz_t * hfuzz,fuzzer_t * fuzzer,int rnd_index)223 static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, fuzzer_t * fuzzer, int rnd_index)
224 {
225 {
226 int dstfd = open(fuzzer->fileName, O_CREAT | O_EXCL | O_RDWR, 0644);
227 if (dstfd == -1) {
228 PLOG_E("Couldn't create a temporary file '%s'", fuzzer->fileName);
229 return false;
230 }
231 DEFER(close(dstfd));
232
233 LOG_D("Created '%s' as an input file", fuzzer->fileName);
234
235 if (hfuzz->inputFile) {
236 size_t fileSz = files_readFileToBufMax(hfuzz->files[rnd_index], fuzzer->dynamicFile,
237 hfuzz->maxFileSz);
238 if (fileSz == 0UL) {
239 LOG_E("Couldn't read '%s'", hfuzz->files[rnd_index]);
240 unlink(fuzzer->fileName);
241 return false;
242 }
243
244 if (files_writeToFd(dstfd, fuzzer->dynamicFile, fileSz) == false) {
245 unlink(fuzzer->fileName);
246 return false;
247 }
248 }
249
250 }
251
252 pid_t pid = arch_fork(hfuzz);
253 if (pid == -1) {
254 PLOG_E("Couldn't fork");
255 return false;
256 }
257
258 if (!pid) {
259 /*
260 * child performs the external file modifications
261 */
262 execl(hfuzz->externalCommand, hfuzz->externalCommand, fuzzer->fileName, NULL);
263 PLOG_F("Couldn't execute '%s %s'", hfuzz->externalCommand, fuzzer->fileName);
264 return false;
265 }
266
267 /*
268 * parent waits until child is done fuzzing the input file
269 */
270 int childStatus;
271 int flags = 0;
272 #if defined(__WNOTHREAD)
273 flags |= __WNOTHREAD;
274 #endif /* defined(__WNOTHREAD) */
275 while (wait4(pid, &childStatus, flags, NULL) != pid) ;
276 if (WIFEXITED(childStatus)) {
277 LOG_D("External command exited with status %d", WEXITSTATUS(childStatus));
278 return true;
279 }
280 if (WIFSIGNALED(childStatus)) {
281 LOG_E("External command terminated with signal %d", WTERMSIG(childStatus));
282 return false;
283 }
284 LOG_F("External command terminated abnormally, status: %d", childStatus);
285 return false;
286 }
287
fuzz_runVerifier(honggfuzz_t * hfuzz,fuzzer_t * crashedFuzzer)288 static bool fuzz_runVerifier(honggfuzz_t * hfuzz, fuzzer_t * crashedFuzzer)
289 {
290 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) {
296 LOG_E("Couldn't open and map '%s' in R/O mode", crashedFuzzer->crashFileName);
297 return false;
298 }
299 DEFER(munmap(crashBuf, crashFileSz));
300 DEFER(close(crashFd));
301
302 LOG_I("Launching verifier for %" PRIx64 " hash", crashedFuzzer->backtrace);
303 for (int i = 0; i < _HF_VERIFIER_ITER; i++) {
304 fuzzer_t vFuzzer = {
305 .pid = 0,
306 .timeStartedMillis = util_timeNowMillis(),
307 .crashFileName = {0},
308 .pc = 0ULL,
309 .backtrace = 0ULL,
310 .access = 0ULL,
311 .exception = 0,
312 .dynamicFileSz = 0,
313 .dynamicFile = NULL,
314 .hwCnts = {
315 .cpuInstrCnt = 0ULL,
316 .cpuBranchCnt = 0ULL,
317 .customCnt = 0ULL,
318 .bbCnt = 0ULL,
319 },
320 .sanCovCnts = {
321 .hitBBCnt = 0ULL,
322 .totalBBCnt = 0ULL,
323 .dsoCnt = 0ULL,
324 .iDsoCnt = 0ULL,
325 .newBBCnt = 0ULL,
326 .crashesCnt = 0ULL,
327 },
328 .report = {'\0'},
329 .mainWorker = false
330 };
331
332 fuzz_getFileName(hfuzz, vFuzzer.fileName);
333 if (files_writeBufToFile
334 (vFuzzer.fileName, crashBuf, crashFileSz, O_WRONLY | O_CREAT | O_EXCL) == false) {
335 LOG_E("Couldn't write buffer to file '%s'", vFuzzer.fileName);
336 return false;
337 }
338
339 vFuzzer.pid = arch_fork(hfuzz);
340 if (vFuzzer.pid == -1) {
341 PLOG_F("Couldn't fork");
342 return false;
343 }
344
345 if (!vFuzzer.pid) {
346 if (fuzz_prepareExecve(hfuzz, crashedFuzzer->crashFileName) == false) {
347 LOG_E("fuzz_prepareExecve() failed");
348 return false;
349 }
350 if (!arch_launchChild(hfuzz, crashedFuzzer->crashFileName)) {
351 LOG_E("Error launching verifier child process");
352 return false;
353 }
354 }
355
356 arch_reapChild(hfuzz, &vFuzzer);
357 unlink(vFuzzer.fileName);
358
359 /* If stack hash doesn't match skip name tag and exit */
360 if (crashedFuzzer->backtrace != vFuzzer.backtrace) {
361 LOG_D("Verifier stack hash mismatch");
362 return false;
363 }
364 }
365
366 /* Workspace is inherited, just append a extra suffix */
367 char verFile[PATH_MAX] = { 0 };
368 snprintf(verFile, sizeof(verFile), "%s.verified", crashedFuzzer->crashFileName);
369
370 /* Copy file with new suffix & remove original copy */
371 bool dstFileExists = false;
372 if (files_copyFile(crashedFuzzer->crashFileName, verFile, &dstFileExists)) {
373 LOG_I("Successfully verified, saving as (%s)", verFile);
374 __sync_fetch_and_add(&hfuzz->verifiedCrashesCnt, 1UL);
375 unlink(crashedFuzzer->crashFileName);
376 } else {
377 if (dstFileExists) {
378 LOG_I("It seems that '%s' already exists, skipping", verFile);
379 } else {
380 LOG_E("Couldn't copy '%s' to '%s'", crashedFuzzer->crashFileName, verFile);
381 return false;
382 }
383 }
384
385 return true;
386 }
387
fuzz_addFileToFileQLocked(honggfuzz_t * hfuzz,uint8_t * data,size_t size)388 static void fuzz_addFileToFileQLocked(honggfuzz_t * hfuzz, uint8_t * data, size_t size)
389 {
390 struct dynfile_t *dynfile = (struct dynfile_t *)util_Malloc(sizeof(struct dynfile_t));
391 dynfile->size = size;
392 dynfile->data = (uint8_t *) util_Malloc(size);
393 memcpy(dynfile->data, data, size);
394 TAILQ_INSERT_TAIL(&hfuzz->dynfileq, dynfile, pointers);
395 hfuzz->dynfileqCnt++;
396
397 char fname[PATH_MAX];
398 snprintf(fname, sizeof(fname), "%s/COVERAGE_DATA.PID.%d.RND.%" PRIu64 ".%" PRIx64,
399 hfuzz->workDir, getpid(), (uint64_t) time(NULL), util_rndGet(0, 0xFFFFFFFFFFFF));
400 if (files_writeBufToFile(fname, data, size, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC) == false) {
401 LOG_W("Couldn't write buffer to file '%s'", fname);
402 }
403 }
404
fuzz_perfFeedback(honggfuzz_t * hfuzz,fuzzer_t * fuzzer)405 static void fuzz_perfFeedback(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
406 {
407 LOG_D
408 ("New file size: %zu, Perf feedback new/cur (instr,branch): %" PRIu64 "/%" PRIu64 ",%"
409 PRIu64 "/%" PRIu64 ", BBcnt new/total: %" PRIu64 "/%" PRIu64, fuzzer->dynamicFileSz,
410 fuzzer->hwCnts.cpuInstrCnt, hfuzz->hwCnts.cpuInstrCnt, fuzzer->hwCnts.cpuBranchCnt,
411 hfuzz->hwCnts.cpuBranchCnt, fuzzer->hwCnts.bbCnt, hfuzz->hwCnts.bbCnt);
412
413 MX_LOCK(&hfuzz->dynfileq_mutex);
414 DEFER(MX_UNLOCK(&hfuzz->dynfileq_mutex));
415
416 int64_t diff0 = hfuzz->hwCnts.cpuInstrCnt - fuzzer->hwCnts.cpuInstrCnt;
417 int64_t diff1 = hfuzz->hwCnts.cpuBranchCnt - fuzzer->hwCnts.cpuBranchCnt;
418 int64_t diff2 = hfuzz->hwCnts.customCnt - fuzzer->hwCnts.customCnt;
419
420 if (diff0 < 0 || diff1 < 0 || diff2 < 0 || fuzzer->hwCnts.bbCnt > 0) {
421 LOG_I
422 ("New file size: %zu, Perf feedback new/cur (instr,branch): %" PRIu64 "/%" PRIu64 ",%"
423 PRIu64 "/%" PRIu64 ", BBcnt new/total: %" PRIu64 "/%" PRIu64, fuzzer->dynamicFileSz,
424 fuzzer->hwCnts.cpuInstrCnt, hfuzz->hwCnts.cpuInstrCnt, fuzzer->hwCnts.cpuBranchCnt,
425 hfuzz->hwCnts.cpuBranchCnt, fuzzer->hwCnts.bbCnt, hfuzz->hwCnts.bbCnt);
426
427 hfuzz->hwCnts.cpuInstrCnt = fuzzer->hwCnts.cpuInstrCnt;
428 hfuzz->hwCnts.cpuBranchCnt = fuzzer->hwCnts.cpuBranchCnt;
429 hfuzz->hwCnts.customCnt = fuzzer->hwCnts.customCnt;
430 hfuzz->hwCnts.bbCnt += fuzzer->hwCnts.bbCnt;
431
432 fuzz_addFileToFileQLocked(hfuzz, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
433 }
434 }
435
fuzz_sanCovFeedback(honggfuzz_t * hfuzz,fuzzer_t * fuzzer)436 static void fuzz_sanCovFeedback(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
437 {
438 LOG_D
439 ("File size (Best/New): %zu, SanCov feedback (bb,dso): Best: [%" PRIu64
440 ",%" PRIu64 "] / New: [%" PRIu64 ",%" PRIu64 "], newBBs:%" PRIu64,
441 fuzzer->dynamicFileSz, hfuzz->sanCovCnts.hitBBCnt,
442 hfuzz->sanCovCnts.iDsoCnt, fuzzer->sanCovCnts.hitBBCnt, fuzzer->sanCovCnts.iDsoCnt,
443 fuzzer->sanCovCnts.newBBCnt);
444
445 MX_LOCK(&hfuzz->dynfileq_mutex);
446 DEFER(MX_UNLOCK(&hfuzz->dynfileq_mutex));
447
448 /*
449 * Keep mutated seed if:
450 * a) Newly discovered (not met before) BBs
451 * b) More instrumented DSOs loaded
452 *
453 * TODO: (a) method can significantly assist to further improvements in interesting areas
454 * discovery if combined with seeds pool/queue support. If a runtime queue is maintained
455 * more interesting seeds can be saved between runs instead of instantly discarded
456 * based on current absolute elitism (only one mutated seed is promoted).
457 */
458 if (fuzzer->sanCovCnts.newBBCnt > 0 || hfuzz->sanCovCnts.iDsoCnt < fuzzer->sanCovCnts.iDsoCnt) {
459 LOG_I("SanCov Update: file size (Cur): %zu, newBBs:%" PRIu64
460 ", counters (Cur,New): %" PRIu64 "/%" PRIu64 ",%" PRIu64 "/%" PRIu64,
461 fuzzer->dynamicFileSz, fuzzer->sanCovCnts.newBBCnt,
462 hfuzz->sanCovCnts.hitBBCnt, hfuzz->sanCovCnts.iDsoCnt, fuzzer->sanCovCnts.hitBBCnt,
463 fuzzer->sanCovCnts.iDsoCnt);
464
465 hfuzz->sanCovCnts.hitBBCnt += fuzzer->sanCovCnts.newBBCnt;
466 hfuzz->sanCovCnts.dsoCnt = fuzzer->sanCovCnts.dsoCnt;
467 hfuzz->sanCovCnts.iDsoCnt = fuzzer->sanCovCnts.iDsoCnt;
468 hfuzz->sanCovCnts.crashesCnt += fuzzer->sanCovCnts.crashesCnt;
469 hfuzz->sanCovCnts.newBBCnt = fuzzer->sanCovCnts.newBBCnt;
470
471 if (hfuzz->sanCovCnts.totalBBCnt < fuzzer->sanCovCnts.totalBBCnt) {
472 /* Keep only the max value (for dlopen cases) to measure total target coverage */
473 hfuzz->sanCovCnts.totalBBCnt = fuzzer->sanCovCnts.totalBBCnt;
474 }
475
476 fuzz_addFileToFileQLocked(hfuzz, fuzzer->dynamicFile, fuzzer->dynamicFileSz);
477 }
478 }
479
fuzz_getState(honggfuzz_t * hfuzz)480 static fuzzState_t fuzz_getState(honggfuzz_t * hfuzz)
481 {
482 return __sync_fetch_and_add(&hfuzz->state, 0UL);
483 }
484
fuzz_setState(honggfuzz_t * hfuzz,fuzzState_t state)485 static void fuzz_setState(honggfuzz_t * hfuzz, fuzzState_t state)
486 {
487 __sync_lock_test_and_set(&hfuzz->state, state);
488 }
489
fuzz_fuzzLoop(honggfuzz_t * hfuzz)490 static void fuzz_fuzzLoop(honggfuzz_t * hfuzz)
491 {
492 fuzzer_t fuzzer = {
493 .pid = 0,
494 .timeStartedMillis = util_timeNowMillis(),
495 .crashFileName = {0},
496 .pc = 0ULL,
497 .backtrace = 0ULL,
498 .access = 0ULL,
499 .exception = 0,
500 .mainWorker = true,
501 .flipRate = hfuzz->origFlipRate,
502
503 .sanCovCnts = {
504 .hitBBCnt = 0ULL,
505 .totalBBCnt = 0ULL,
506 .dsoCnt = 0ULL,
507 .iDsoCnt = 0ULL,
508 .newBBCnt = 0ULL,
509 .crashesCnt = 0ULL,
510 },
511 .dynamicFileSz = 0,
512 .dynamicFile = util_Malloc(hfuzz->maxFileSz),
513
514 .hwCnts = {
515 .cpuInstrCnt = 0ULL,
516 .cpuBranchCnt = 0ULL,
517 .customCnt = 0ULL,
518 .bbCnt = 0ULL,
519 },
520 .report = {'\0'},
521 };
522 DEFER(free(fuzzer.dynamicFile));
523
524 size_t rnd_index = util_rndGet(0, hfuzz->fileCnt - 1);
525
526 /* If dry run mode, pick the next file and not a random one */
527 if (fuzzer.flipRate == 0.0L && hfuzz->useVerifier) {
528 rnd_index = __sync_fetch_and_add(&hfuzz->lastFileIndex, 1UL);
529 }
530
531 if (fuzz_getState(hfuzz) == _HF_STATE_DYNAMIC_PRE) {
532 rnd_index = __sync_fetch_and_add(&hfuzz->lastFileIndex, 1UL);
533 if (rnd_index >= hfuzz->fileCnt) {
534 while (fuzz_getState(hfuzz) == _HF_STATE_DYNAMIC_PRE) {
535 sleep(1);
536 }
537 }
538 }
539
540 if (hfuzz->state == _HF_STATE_DYNAMIC_MAIN) {
541 strncpy(fuzzer.origFileName, "DYNAMIC", PATH_MAX);
542 } else {
543 strncpy(fuzzer.origFileName, files_basename(hfuzz->files[rnd_index]), PATH_MAX);
544 }
545
546 fuzzState_t state = fuzz_getState(hfuzz);
547 fuzz_getFileName(hfuzz, fuzzer.fileName);
548
549 if (state == _HF_STATE_DYNAMIC_MAIN) {
550 if (!fuzz_prepareFileDynamically(hfuzz, &fuzzer)) {
551 exit(EXIT_FAILURE);
552 }
553 } else if (state == _HF_STATE_DYNAMIC_PRE) {
554 fuzzer.flipRate = 0.0f;
555 if (!fuzz_prepareFile(hfuzz, &fuzzer, rnd_index)) {
556 exit(EXIT_FAILURE);
557 }
558 } else if (hfuzz->externalCommand != NULL) {
559 if (!fuzz_prepareFileExternally(hfuzz, &fuzzer, rnd_index)) {
560 exit(EXIT_FAILURE);
561 }
562 } else {
563 if (!fuzz_prepareFile(hfuzz, &fuzzer, rnd_index)) {
564 exit(EXIT_FAILURE);
565 }
566 }
567
568 fuzzer.pid = arch_fork(hfuzz);
569 if (fuzzer.pid == -1) {
570 PLOG_F("Couldn't fork");
571 exit(EXIT_FAILURE);
572 }
573
574 if (!fuzzer.pid) {
575 if (!fuzz_prepareExecve(hfuzz, fuzzer.fileName)) {
576 LOG_E("fuzz_prepareExecve() failed");
577 exit(EXIT_FAILURE);
578 }
579 if (!arch_launchChild(hfuzz, fuzzer.fileName)) {
580 LOG_E("Error launching child process");
581 exit(EXIT_FAILURE);
582 }
583 }
584
585 LOG_D("Launched new process, pid: %d, (concurrency: %zd)", fuzzer.pid, hfuzz->threadsMax);
586
587 arch_reapChild(hfuzz, &fuzzer);
588 unlink(fuzzer.fileName);
589
590 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
591 fuzz_perfFeedback(hfuzz, &fuzzer);
592 } else if (hfuzz->useSanCov) {
593 fuzz_sanCovFeedback(hfuzz, &fuzzer);
594 }
595
596 if (hfuzz->useVerifier && (fuzzer.crashFileName[0] != 0) && fuzzer.backtrace) {
597 if (!fuzz_runVerifier(hfuzz, &fuzzer)) {
598 LOG_I("Failed to verify %s", fuzzer.crashFileName);
599 }
600 }
601
602 report_Report(hfuzz, fuzzer.report);
603
604 if (state == _HF_STATE_DYNAMIC_PRE
605 && __sync_add_and_fetch(&hfuzz->doneFileIndex, 1UL) >= hfuzz->fileCnt) {
606 fuzz_setState(hfuzz, _HF_STATE_DYNAMIC_MAIN);
607 }
608 }
609
fuzz_threadNew(void * arg)610 static void *fuzz_threadNew(void *arg)
611 {
612 honggfuzz_t *hfuzz = (honggfuzz_t *) arg;
613
614 for (;;) {
615 /* Check if dry run mode with verifier enabled */
616 if (hfuzz->origFlipRate == 0.0L && hfuzz->useVerifier) {
617 if (__sync_fetch_and_add(&hfuzz->mutationsCnt, 1UL) >= hfuzz->fileCnt) {
618 __sync_fetch_and_add(&hfuzz->threadsFinished, 1UL);
619 // All files checked, weak-up the main process
620 pthread_kill(fuzz_mainThread, SIGALRM);
621 return NULL;
622 }
623 }
624 /* Check for max iterations limit if set */
625 else if ((__sync_fetch_and_add(&hfuzz->mutationsCnt, 1UL) >= hfuzz->mutationsMax)
626 && hfuzz->mutationsMax) {
627 __sync_fetch_and_add(&hfuzz->threadsFinished, 1UL);
628 // Wake-up the main process
629 pthread_kill(fuzz_mainThread, SIGALRM);
630 return NULL;
631 }
632
633 fuzz_fuzzLoop(hfuzz);
634 }
635 }
636
fuzz_runThread(honggfuzz_t * hfuzz,void * (* thread)(void *))637 static void fuzz_runThread(honggfuzz_t * hfuzz, void *(*thread) (void *))
638 {
639 pthread_attr_t attr;
640
641 pthread_attr_init(&attr);
642 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
643 pthread_attr_setstacksize(&attr, _HF_PTHREAD_STACKSIZE);
644 pthread_attr_setguardsize(&attr, (size_t) sysconf(_SC_PAGESIZE));
645
646 pthread_t t;
647 if (pthread_create(&t, &attr, thread, (void *)hfuzz) < 0) {
648 PLOG_F("Couldn't create a new thread");
649 }
650
651 return;
652 }
653
fuzz_threads(honggfuzz_t * hfuzz)654 void fuzz_threads(honggfuzz_t * hfuzz)
655 {
656 fuzz_mainThread = pthread_self();
657
658 if (!arch_archInit(hfuzz)) {
659 LOG_F("Couldn't prepare arch for fuzzing");
660 }
661 if (!sancov_Init(hfuzz)) {
662 LOG_F("Couldn't prepare sancov options");
663 }
664
665 if (hfuzz->useSanCov || hfuzz->dynFileMethod != _HF_DYNFILE_NONE) {
666 hfuzz->state = _HF_STATE_DYNAMIC_PRE;
667 } else {
668 hfuzz->state = _HF_STATE_STATIC;
669 }
670
671 for (size_t i = 0; i < hfuzz->threadsMax; i++) {
672 fuzz_runThread(hfuzz, fuzz_threadNew);
673 }
674 }
675