static void mangle_Expand(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); size_t len = util_rndGet(1, run->dynamicFileSz - off); mangle_Inflate(run, off, len); mangle_Move(run, off, off + len, run->dynamicFileSz); }
static void fuzz_mangleContent(honggfuzz_t * hfuzz, uint8_t * buf, off_t fileSz) { /* * Just copy the file if "-r 0" */ if (hfuzz->flipRate == 0.0) { return; } uint64_t changesCnt = fileSz * hfuzz->flipRate; if (hfuzz->flipMode == 'b') { changesCnt *= 8UL; } changesCnt = util_rndGet(1, changesCnt); uint32_t start = hfuzz->fuzzStart; uint32_t end = (hfuzz->fuzzEnd == UINT_MAX) ? fileSz : hfuzz->fuzzEnd; for (uint64_t x = 0; x < changesCnt; x++) { off_t pos = util_rndGet(start, end - 1); if (hfuzz->flipMode == 'b') { buf[pos] ^= (1 << util_rndGet(0, 7)); } else { buf[pos] = (uint8_t) util_rndGet(0, 255); } } }
static void mangle_MemMove(run_t* run) { size_t off_from = util_rndGet(0, run->dynamicFileSz - 1); size_t off_to = util_rndGet(0, run->dynamicFileSz - 1); size_t len = util_rndGet(0, run->dynamicFileSz); mangle_Move(run, off_from, off_to, len); }
static void mangle_InsertRndPrintable(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); size_t len = util_rndGet(1, run->dynamicFileSz - off); mangle_Inflate(run, off, len); mangle_Move(run, off, off + len, run->dynamicFileSz); util_rndBufPrintable(&run->dynamicFile[off], len); }
static void mangle_Bytes(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); uint32_t val = (uint32_t)util_rnd64(); /* Overwrite with random 2,3,4-byte values */ size_t toCopy = util_rndGet(2, 4); mangle_Overwrite(run, (uint8_t*)&val, off, toCopy); }
static void mangle_CloneByte(run_t* run) { size_t off1 = util_rndGet(0, run->dynamicFileSz - 1); size_t off2 = util_rndGet(0, run->dynamicFileSz - 1); uint8_t tmp = run->dynamicFile[off1]; run->dynamicFile[off1] = run->dynamicFile[off2]; run->dynamicFile[off2] = tmp; }
static void mangle_PrintableBytes(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); uint32_t val; util_rndBufPrintable((uint8_t*)&val, sizeof(val)); /* Overwrite with random 2,3,4-byte values */ size_t toCopy = util_rndGet(2, 4); mangle_Overwrite(run, (uint8_t*)&val, off, toCopy); }
static void mangle_AddSub(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); /* 1,2,4,8 */ uint64_t varLen = 1U << util_rndGet(0, 3); if ((run->dynamicFileSz - off) < varLen) { varLen = 1; } mangle_AddSubWithRange(run, off, varLen); }
static void mangle_Shrink(run_t* run) { if (run->dynamicFileSz <= 1U) { return; } size_t len = util_rndGet(1, run->dynamicFileSz - 1); size_t off = util_rndGet(0, len); input_setSize(run, run->dynamicFileSz - len); mangle_Move(run, off + len, off, run->dynamicFileSz); }
static void mangle_DictionaryNoCheck(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1); struct strings_t* str = TAILQ_FIRST(&run->global->mutate.dictq); for (uint64_t i = 0; i < choice; i++) { str = TAILQ_NEXT(str, pointers); } mangle_Overwrite(run, (uint8_t*)str->s, off, str->len); }
static void mangle_AddSubPrintable(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); /* 1,2,4,8 */ uint64_t varLen = 1U << util_rndGet(0, 3); if ((run->dynamicFileSz - off) < varLen) { varLen = 1; } mangle_AddSubWithRange(run, off, varLen); util_turnToPrintable((uint8_t*)&run->dynamicFile[off], varLen); }
static void mangle_ASCIIVal(run_t* run) { char buf[32]; snprintf(buf, sizeof(buf), "%" PRId64, (int64_t)util_rnd64()); size_t off = util_rndGet(0, run->dynamicFileSz - 1); mangle_Overwrite(run, (uint8_t*)buf, off, strlen(buf)); }
static void fuzz_getFileName(honggfuzz_t * hfuzz, char *fileName) { struct timeval tv; gettimeofday(&tv, NULL); snprintf(fileName, PATH_MAX, "%s/.honggfuzz.%d.%lu.%llx.%s", hfuzz->workDir, (int)getpid(), (unsigned long int)tv.tv_sec, (unsigned long long int)util_rndGet(0, 1ULL << 62), hfuzz->fileExtn); }
static void fuzz_getFileName(honggfuzz_t * hfuzz, char *fileName) { struct timeval tv; gettimeofday(&tv, NULL); snprintf(fileName, PATH_MAX, ".honggfuzz.%d.%lu.%lu.%lu.%s", (int)getpid(), (unsigned long int)tv.tv_sec, (unsigned long int)tv.tv_usec, (unsigned long int)util_rndGet(0, 1 << 30), hfuzz->fileExtn); return; }
void util_rndBuf(uint8_t * buf, size_t sz) { /* MMIX LCG PRNG */ static const uint64_t a = 6364136223846793005ULL; static const uint64_t c = 1442695040888963407ULL; uint64_t x = util_rndGet(0, 1ULL << 62); for (size_t i = 0; i < sz; i++) { x = (a * x + c); buf[i] = (uint8_t) (x & 0xFF); } }
static bool fuzz_prepareFile(honggfuzz_t * hfuzz, char *fileName) { int rnd_index = util_rndGet(0, hfuzz->fileCnt - 1); off_t fileSz; int srcfd; uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd); if (buf == NULL) { LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]); return false; } LOGMSG(l_DEBUG, "Mmaped '%s' in R/O mode, size: %d", hfuzz->files[rnd_index], fileSz); int dstfd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644); if (dstfd == -1) { LOGMSG_P(l_ERROR, "Couldn't create a temporary file '%s' in the current directory", fileName); munmap(buf, fileSz); close(srcfd); return false; } fuzz_mangleContent(hfuzz, buf, fileSz); if (!files_writeToFd(dstfd, buf, fileSz)) { munmap(buf, fileSz); close(srcfd); close(dstfd); return false; } munmap(buf, fileSz); close(srcfd); close(dstfd); return true; }
static void mangle_MemSetWithVal(run_t* run, int val) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); size_t sz = util_rndGet(1, run->dynamicFileSz - off); memset(&run->dynamicFile[off], val, sz); }
static bool fuzz_prepareFileExternally(honggfuzz_t * hfuzz, char *fileName) { int rnd_index = util_rndGet(0, hfuzz->fileCnt - 1); off_t fileSz; int srcfd; int dstfd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644); if (dstfd == -1) { LOGMSG_P(l_ERROR, "Couldn't create a temporary file '%s' in the current directory", fileName); return false; } LOGMSG(l_DEBUG, "Created '%f' as an input file", fileName); if (hfuzz->inputFile) { uint8_t *buf = files_mapFileToRead(hfuzz->files[rnd_index], &fileSz, &srcfd); if (buf == NULL) { LOGMSG(l_ERROR, "Couldn't open and map '%s' in R/O mode", hfuzz->files[rnd_index]); close(dstfd); return false; } LOGMSG(l_DEBUG, "Mmaped '%s' in R/O mode, size: %d", hfuzz->files[rnd_index], fileSz); bool ret = files_writeToFd(dstfd, buf, fileSz); munmap(buf, fileSz); close(srcfd); if (!ret) { close(dstfd); return false; } } close(dstfd); pid_t pid = fork(); if (pid == -1) { LOGMSG_P(l_ERROR, "Couldn't fork"); return false; } if (!pid) { /* * child does the external file modifications */ execl(hfuzz->externalCommand, hfuzz->externalCommand, fileName, NULL); LOGMSG_P(l_FATAL, "Couldn't execute '%s %s'", hfuzz->externalCommand, fileName); return false; } else { /* * parent waits until child is done fuzzing the input file */ int childStatus; pid_t terminatedPid; do { terminatedPid = wait(&childStatus); } while (terminatedPid != pid); if (WIFEXITED(childStatus)) { LOGMSG(l_DEBUG, "External command exited with status %d", WEXITSTATUS(childStatus)); return true; } else if (WIFSIGNALED(childStatus)) { LOGMSG(l_ERROR, "External command terminated with signal %d", WTERMSIG(childStatus)); return false; } LOGMSG(l_FATAL, "External command terminated abnormally, status: %d", childStatus); return false; } abort(); /* NOTREACHED */ }
/* * Called once before fuzzing starts. Prepare mach ports for attaching crash reporter. */ bool arch_archInit(honggfuzz_t * hfuzz) { char plist[PATH_MAX]; snprintf(plist, sizeof(plist), "/Users/%s/Library/Preferences/com.apple.DebugSymbols.plist", getlogin()); if (files_exists(plist)) { LOG_W ("honggfuzz won't work if DBGShellCommands are set in ~/Library/Preferences/com.apple.DebugSymbols.plist"); } /* * Allocate exception port. */ if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &g_exception_port) != KERN_SUCCESS) { return false; } /* * Insert exception receive port. */ if (mach_port_insert_right (mach_task_self(), g_exception_port, g_exception_port, MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) { return false; } /* * Get bootstrap port. */ mach_port_t bootstrap = MACH_PORT_NULL; if (task_get_bootstrap_port(mach_task_self(), &bootstrap) != KERN_SUCCESS) { return false; } /* * Generate and register exception port service. */ snprintf(g_service_name, sizeof(g_service_name), "com.google.code.honggfuzz.%d", (int)util_rndGet(0, 999999)); if (bootstrap_check_in(bootstrap, g_service_name, &g_exception_port) != KERN_SUCCESS) { return false; } /* * Create a collection thread to catch the exceptions from the * children */ pthread_t exception_thread; if (pthread_create(&exception_thread, NULL, wait_for_exception, 0)) { LOG_F("Parent: could not create thread to wait for child's exception"); return false; } if (pthread_detach(exception_thread)) { LOG_F("Parent: could not detach thread to wait for child's exception"); return false; } return true; }
static void mangle_PrintableByte(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); run->dynamicFile[off] = util_rndPrintable(); }
static void mangle_Byte(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); run->dynamicFile[off] = (uint8_t)util_rnd64(); }
static void mangle_NegBytePrintable(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); run->dynamicFile[off] = 94 - (run->dynamicFile[off] - 32) + 32; }
static void mangle_MemSet(run_t* run) { mangle_MemSetWithVal(run, (int)util_rndGet(0, UINT8_MAX)); }
static void mangle_RandomPrintable(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); size_t len = util_rndGet(1, run->dynamicFileSz - off); util_rndBufPrintable(&run->dynamicFile[off], len); }
static void mangle_AddSubWithRange(run_t* run, size_t off, uint64_t varLen) { int delta = (int)util_rndGet(0, 8192); delta -= 4096; switch (varLen) { case 1: { run->dynamicFile[off] += delta; return; break; } case 2: { int16_t val; memcpy(&val, &run->dynamicFile[off], sizeof(val)); if (util_rnd64() & 0x1) { val += delta; } else { /* Foreign endianess */ val = __builtin_bswap16(val); val += delta; val = __builtin_bswap16(val); } mangle_Overwrite(run, (uint8_t*)&val, off, varLen); return; break; } case 4: { int32_t val; memcpy(&val, &run->dynamicFile[off], sizeof(val)); if (util_rnd64() & 0x1) { val += delta; } else { /* Foreign endianess */ val = __builtin_bswap32(val); val += delta; val = __builtin_bswap32(val); } mangle_Overwrite(run, (uint8_t*)&val, off, varLen); return; break; } case 8: { int64_t val; memcpy(&val, &run->dynamicFile[off], sizeof(val)); if (util_rnd64() & 0x1) { val += delta; } else { /* Foreign endianess */ val = __builtin_bswap64(val); val += delta; val = __builtin_bswap64(val); } mangle_Overwrite(run, (uint8_t*)&val, off, varLen); return; break; } default: { LOG_F("Unknown variable length size: %" PRIu64, varLen); break; } } }
static void mangle_DecByte(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); run->dynamicFile[off] -= (uint8_t)1UL; }
static void mangle_DecBytePrintable(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); run->dynamicFile[off] = (run->dynamicFile[off] - 32 + 94) % 95 + 32; }
void mangle_mangleContent(run_t* run) { static void (*const mangleFuncs[])(run_t * run) = { mangle_Byte, mangle_Bit, mangle_Bytes, mangle_Magic, mangle_IncByte, mangle_DecByte, mangle_NegByte, mangle_AddSub, mangle_Dictionary, mangle_DictionaryInsert, mangle_MemMove, mangle_MemSet, mangle_Random, mangle_CloneByte, mangle_Expand, mangle_Shrink, mangle_InsertRnd, mangle_ASCIIVal, }; static void (*const manglePrintableFuncs[])(run_t * run) = { mangle_PrintableByte, mangle_BitPrintable, mangle_PrintableBytes, mangle_MagicPrintable, mangle_IncBytePrintable, mangle_DecBytePrintable, mangle_NegBytePrintable, mangle_AddSubPrintable, mangle_DictionaryPrintable, mangle_DictionaryInsertPrintable, mangle_MemMove, mangle_MemSetPrintable, mangle_RandomPrintable, mangle_CloneByte, mangle_Expand, mangle_Shrink, mangle_InsertRndPrintable, mangle_ASCIIVal, }; if (run->mutationsPerRun == 0U) { return; } /* No point in modifying it, if its size is 0 */ if (run->dynamicFileSz == 0UL) { input_setSize(run, 1UL); } /* Max number of stacked changes is, by default, 6 */ uint64_t changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun); if (run->global->cfg.only_printable) { for (uint64_t x = 0; x < changesCnt; x++) { uint64_t choice = util_rndGet(0, ARRAYSIZE(manglePrintableFuncs) - 1); manglePrintableFuncs[choice](run); } } else { for (uint64_t x = 0; x < changesCnt; x++) { uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1); mangleFuncs[choice](run); } } }
#include "util.h" static inline void mangle_Overwrite(uint8_t * dst, const uint8_t * src, size_t dstSz, size_t off, size_t sz) { size_t maxToCopy = dstSz - off; if (sz > maxToCopy) { sz = maxToCopy; } memcpy(&dst[off], src, sz); } static void mangle_Byte(honggfuzz_t * hfuzz UNUSED, uint8_t * buf, size_t bufSz UNUSED, size_t off) { buf[off] = (uint8_t) util_rndGet(0, UINT8_MAX); } static void mangle_Bytes(honggfuzz_t * hfuzz UNUSED, uint8_t * buf, size_t bufSz, size_t off) { uint32_t val = (uint32_t) util_rndGet(0, UINT32_MAX); /* Overwrite with random 2,3,4-byte values */ size_t toCopy = util_rndGet(2, 4); mangle_Overwrite(buf, (uint8_t *) & val, bufSz, off, toCopy); } static void mangle_Bit(honggfuzz_t * hfuzz UNUSED, uint8_t * buf, size_t bufSz UNUSED, size_t off) { buf[off] ^= ((uint8_t) 1 << util_rndGet(0, 7)); }
static void mangle_NegByte(run_t* run) { size_t off = util_rndGet(0, run->dynamicFileSz - 1); run->dynamicFile[off] = ~(run->dynamicFile[off]); }