"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "input.c" between
honggfuzz-2.1.tar.gz and honggfuzz-2.2.tar.gz

About: honggfuzz is a security oriented, feedback-driven, evolutionary, easy-to-use fuzzer with powerful analysis options.

input.c  (honggfuzz-2.1):input.c  (honggfuzz-2.2)
/* /*
*
* honggfuzz - file operations * honggfuzz - file operations
* ----------------------------------------- * -----------------------------------------
* *
* Author: Robert Swiecki <swiecki@google.com> * Author: Robert Swiecki <swiecki@google.com>
* *
* Copyright 2010-2018 by Google Inc. All Rights Reserved. * Copyright 2010-2020 by Google Inc. All Rights Reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may * Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain * not use this file except in compliance with the License. You may obtain
* a copy of the License at * a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
skipping to change at line 49 skipping to change at line 48
#include "fuzz.h" #include "fuzz.h"
#include "libhfcommon/common.h" #include "libhfcommon/common.h"
#include "libhfcommon/files.h" #include "libhfcommon/files.h"
#include "libhfcommon/log.h" #include "libhfcommon/log.h"
#include "libhfcommon/util.h" #include "libhfcommon/util.h"
#include "mangle.h" #include "mangle.h"
#include "subproc.h" #include "subproc.h"
void input_setSize(run_t* run, size_t sz) { void input_setSize(run_t* run, size_t sz) {
if (run->dynamicFileSz == sz) { if (run->dynfile->size == sz) {
return; return;
} }
if (sz > run->global->mutate.maxFileSz) { if (sz > run->global->mutate.maxInputSz) {
PLOG_F("Too large size requested: %zu > maxSize: %zu", sz, run->global-> PLOG_F("Too large size requested: %zu > maxSize: %zu", sz, run->global->
mutate.maxFileSz); mutate.maxInputSz);
} }
/* ftruncate of a mmaped file fails under CygWin, it's also painfully slow u nder MacOS X */ /* ftruncate of a mmaped file fails under CygWin, it's also painfully slow u nder MacOS X */
#if !defined(__CYGWIN__) && !defined(_HF_ARCH_DARWIN) #if !defined(__CYGWIN__) && !defined(_HF_ARCH_DARWIN)
if (TEMP_FAILURE_RETRY(ftruncate(run->dynamicFileFd, sz)) == -1) { if (TEMP_FAILURE_RETRY(ftruncate(run->dynfile->fd, sz)) == -1) {
PLOG_W("ftruncate(run->dynamicFileFd=%d, sz=%zu)", run->dynamicFileFd, s PLOG_W("ftruncate(run->dynfile->fd=%d, sz=%zu)", run->dynfile->fd, sz);
z);
} }
#endif /* !defined(__CYGWIN__) && !defined(_HF_ARCH_DARWIN) */ #endif /* !defined(__CYGWIN__) && !defined(_HF_ARCH_DARWIN) */
run->dynamicFileSz = sz; run->dynfile->size = sz;
} }
static bool input_getDirStatsAndRewind(honggfuzz_t* hfuzz) { bool input_getDirStatsAndRewind(honggfuzz_t* hfuzz) {
rewinddir(hfuzz->io.inputDirPtr); rewinddir(hfuzz->io.inputDirPtr);
size_t maxSize = 0U;
size_t fileCnt = 0U; size_t fileCnt = 0U;
for (;;) { for (;;) {
errno = 0; errno = 0;
struct dirent* entry = readdir(hfuzz->io.inputDirPtr); struct dirent* entry = readdir(hfuzz->io.inputDirPtr);
if (entry == NULL && errno == EINTR) { if (entry == NULL && errno == EINTR) {
continue; continue;
} }
if (entry == NULL && errno != 0) { if (entry == NULL && errno != 0) {
PLOG_W("readdir('%s')", hfuzz->io.inputDir); PLOG_W("readdir('%s')", hfuzz->io.inputDir);
return false; return false;
skipping to change at line 97 skipping to change at line 95
struct stat st; struct stat st;
if (stat(path, &st) == -1) { if (stat(path, &st) == -1) {
LOG_W("Couldn't stat() the '%s' file", path); LOG_W("Couldn't stat() the '%s' file", path);
continue; continue;
} }
if (!S_ISREG(st.st_mode)) { if (!S_ISREG(st.st_mode)) {
LOG_D("'%s' is not a regular file, skipping", path); LOG_D("'%s' is not a regular file, skipping", path);
continue; continue;
} }
if (hfuzz->mutate.maxFileSz != 0UL && st.st_size > (off_t)hfuzz->mutate. if (hfuzz->io.maxFileSz && st.st_size > (off_t)hfuzz->io.maxFileSz) {
maxFileSz) { LOG_D("File '%s' is bigger than maximal defined file size (-F): %" P
LOG_D("File '%s' is bigger than maximal defined file size (-F): %" P RIu64 " > %zu",
RId64 " > %" PRId64, path, (uint64_t)st.st_size, hfuzz->io.maxFileSz);
path, (int64_t)st.st_size, (int64_t)hfuzz->mutate.maxFileSz);
} }
if ((size_t)st.st_size > maxSize) { if ((size_t)st.st_size > hfuzz->mutate.maxInputSz) {
maxSize = st.st_size; hfuzz->mutate.maxInputSz = st.st_size;
} }
fileCnt++; fileCnt++;
} }
ATOMIC_SET(hfuzz->io.fileCnt, fileCnt); ATOMIC_SET(hfuzz->io.fileCnt, fileCnt);
if (hfuzz->mutate.maxFileSz == 0U) { if (hfuzz->io.maxFileSz) {
if (maxSize < 8192) { hfuzz->mutate.maxInputSz = hfuzz->io.maxFileSz;
hfuzz->mutate.maxFileSz = 8192; } else if (hfuzz->mutate.maxInputSz < _HF_INPUT_DEFAULT_SIZE) {
} else if (maxSize > _HF_INPUT_MAX_SIZE) { hfuzz->mutate.maxInputSz = _HF_INPUT_DEFAULT_SIZE;
hfuzz->mutate.maxFileSz = _HF_INPUT_MAX_SIZE; } else if (hfuzz->mutate.maxInputSz > _HF_INPUT_MAX_SIZE) {
} else { hfuzz->mutate.maxInputSz = _HF_INPUT_MAX_SIZE;
hfuzz->mutate.maxFileSz = maxSize;
}
} }
if (hfuzz->io.fileCnt == 0U) { if (hfuzz->io.fileCnt == 0U) {
LOG_W("No usable files in the input directory '%s'", hfuzz->io.inputDir) ; LOG_W("No usable files in the input directory '%s'", hfuzz->io.inputDir) ;
} }
LOG_D("Analyzed '%s' directory: maxFileSz:%zu, number of usable files:%zu", LOG_D("Analyzed '%s' directory: maxInputSz:%zu, number of usable files:%zu",
hfuzz->io.inputDir, hfuzz->io.inputDir,
hfuzz->mutate.maxFileSz, hfuzz->io.fileCnt); hfuzz->mutate.maxInputSz, hfuzz->io.fileCnt);
rewinddir(hfuzz->io.inputDirPtr); rewinddir(hfuzz->io.inputDirPtr);
return true; return true;
} }
bool input_getNext(run_t* run, char fname[PATH_MAX], bool rewind) { bool input_getNext(run_t* run, char fname[PATH_MAX], bool rewind) {
static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER;
MX_SCOPED_LOCK(&input_mutex); MX_SCOPED_LOCK(&input_mutex);
skipping to change at line 225 skipping to change at line 221
char* lineptr = NULL; char* lineptr = NULL;
size_t n = 0; size_t n = 0;
defer { defer {
free(lineptr); free(lineptr);
}; };
for (;;) { for (;;) {
ssize_t len = getdelim(&lineptr, &n, '\n', fDict); ssize_t len = getdelim(&lineptr, &n, '\n', fDict);
if (len == -1) { if (len == -1) {
break; break;
} }
if (hfuzz->mutate.dictionaryCnt == ARRAYSIZE(hfuzz->mutate.dictionary))
{
LOG_W("Maximum number of dictionary entries '%zu' alread loaded. Ski
pping the rest",
ARRAYSIZE(hfuzz->mutate.dictionary));
break;
}
if (len > 1 && lineptr[len - 1] == '\n') { if (len > 1 && lineptr[len - 1] == '\n') {
lineptr[len - 1] = '\0'; lineptr[len - 1] = '\0';
len--; len--;
} }
if (lineptr[0] == '#') { if (lineptr[0] == '#') {
continue; continue;
} }
if (lineptr[0] == '\n') { if (lineptr[0] == '\n') {
continue; continue;
} }
if (lineptr[0] == '\0') { if (lineptr[0] == '\0') {
continue; continue;
} }
const char* start = strchr(lineptr, '"');
char* end = strrchr(lineptr, '"');
if (!start || !end) {
LOG_W("Malformed dictionary line '%s', skipping", lineptr);
continue;
}
if ((uintptr_t)start == (uintptr_t)end) {
LOG_W("Malformed dictionary line '%s', skipping", lineptr);
continue;
}
*end = '\0';
char bufv[1025] = {}; char bufv[1025] = {};
if (sscanf(lineptr, "\"%1024[^\"]", bufv) != 1 && if (sscanf(&start[1], "%1024c", bufv) != 1) {
sscanf(lineptr, "%*1024[^=]=\"%1024[^\"]", bufv) != 1) { LOG_W("Malformed dictionary line '%s', skipping", lineptr);
LOG_W("Incorrect dictionary entry: '%s'. Skipping", lineptr);
continue; continue;
} }
LOG_D("Parsing dictionary word: '%s'", bufv); LOG_D("Parsing dictionary word: '%s'", bufv);
len = util_decodeCString(bufv); len = util_decodeCString(bufv);
struct strings_t* str = (struct strings_t*)util_Calloc(sizeof(struct str size_t dictEntry = ATOMIC_POST_INC(hfuzz->mutate.dictionaryCnt);
ings_t) + len + 1); len = HF_MIN((size_t)len, sizeof(hfuzz->mutate.dictionary[dictEntry].val
memcpy(str->s, bufv, len); ));
str->len = len; memcpy(hfuzz->mutate.dictionary[dictEntry].val, bufv, len);
hfuzz->mutate.dictionaryCnt++; hfuzz->mutate.dictionary[dictEntry].len = len;
TAILQ_INSERT_TAIL(&hfuzz->mutate.dictq, str, pointers);
LOG_D("Dictionary: loaded word: '%s' (len=%zu)", str->s, str->len); LOG_D("Dictionary: loaded word: '%s' (len=%zd)", bufv, len);
} }
LOG_I("Loaded %zu words from the dictionary '%s'", hfuzz->mutate.dictionaryC nt, LOG_I("Loaded %zu words from the dictionary '%s'", hfuzz->mutate.dictionaryC nt,
hfuzz->mutate.dictionaryFile); hfuzz->mutate.dictionaryFile);
return true; return true;
} }
void input_freeDictionary(honggfuzz_t* hfuzz) {
while (!TAILQ_EMPTY(&hfuzz->mutate.dictq)) {
struct strings_t* str = TAILQ_FIRST(&hfuzz->mutate.dictq);
TAILQ_REMOVE(&hfuzz->mutate.dictq, str, pointers);
free(str);
hfuzz->mutate.dictionaryCnt--;
}
}
bool input_parseBlacklist(honggfuzz_t* hfuzz) { bool input_parseBlacklist(honggfuzz_t* hfuzz) {
FILE* fBl = fopen(hfuzz->feedback.blacklistFile, "rb"); FILE* fBl = fopen(hfuzz->feedback.blacklistFile, "rb");
if (fBl == NULL) { if (fBl == NULL) {
PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->feedback.blacklistFile); PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->feedback.blacklistFile);
return false; return false;
} }
defer { defer {
fclose(fBl); fclose(fBl);
}; };
skipping to change at line 323 skipping to change at line 326
} }
if (hfuzz->feedback.blacklistCnt > 0) { if (hfuzz->feedback.blacklistCnt > 0) {
LOG_I("Loaded %zu stack hash(es) from the blacklist file", hfuzz->feedba ck.blacklistCnt); LOG_I("Loaded %zu stack hash(es) from the blacklist file", hfuzz->feedba ck.blacklistCnt);
} else { } else {
LOG_F("Empty stack hashes blacklist file '%s'", hfuzz->feedback.blacklis tFile); LOG_F("Empty stack hashes blacklist file '%s'", hfuzz->feedback.blacklis tFile);
} }
return true; return true;
} }
bool input_writeCovFile(const char* dir, const uint8_t* data, size_t len) { static void input_generateFileName(dynfile_t* dynfile, const char* dir, char fna
char fname[PATH_MAX]; me[PATH_MAX]) {
uint64_t crc64f = util_CRC64(dynfile->data, dynfile->size);
uint64_t crc64r = util_CRC64Rev(dynfile->data, dynfile->size);
if (dir) {
snprintf(fname, PATH_MAX, "%s/%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 "
.honggfuzz.cov",
dir, crc64f, crc64r, (uint32_t)dynfile->size);
} else {
snprintf(fname, PATH_MAX, "%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 ".ho
nggfuzz.cov",
crc64f, crc64r, (uint32_t)dynfile->size);
}
}
uint64_t crc64f = util_CRC64(data, len); bool input_writeCovFile(const char* dir, dynfile_t* dynfile) {
uint64_t crc64r = util_CRC64Rev(data, len); char fname[PATH_MAX];
snprintf(fname, sizeof(fname), "%s/%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 input_generateFileName(dynfile, dir, fname);
".honggfuzz.cov",
dir, crc64f, crc64r, (uint32_t)len);
if (files_exists(fname)) { if (files_exists(fname)) {
LOG_D("File '%s' already exists in the output corpus directory '%s'", fn ame, dir); LOG_D("File '%s' already exists in the output corpus directory '%s'", fn ame, dir);
return true; return true;
} }
LOG_D("Adding file '%s' to the corpus directory '%s'", fname, dir); LOG_D("Adding file '%s' to the corpus directory '%s'", fname, dir);
if (!files_writeBufToFile(fname, data, len, O_WRONLY | O_CREAT | O_EXCL | O_ if (!files_writeBufToFile(
CLOEXEC)) { fname, dynfile->data, dynfile->size, O_WRONLY | O_CREAT | O_EXCL | O
LOG_W("Couldn't write buffer to file '%s'", fname); _CLOEXEC)) {
LOG_W("Couldn't write buffer to file '%s' (sz=%zu)", fname, dynfile->siz
e);
return false; return false;
} }
return true; return true;
} }
/* true if item1 is bigger than item2 */ /* true if item1 is bigger than item2 */
static bool input_cmpCov(struct dynfile_t* item1, struct dynfile_t* item2) { static bool input_cmpCov(dynfile_t* item1, dynfile_t* item2) {
for (size_t j = 0; j < ARRAYSIZE(item1->cov); j++) { for (size_t j = 0; j < ARRAYSIZE(item1->cov); j++) {
if (item1->cov[j] > item2->cov[j]) { if (item1->cov[j] > item2->cov[j]) {
return true; return true;
} }
if (item1->cov[j] < item2->cov[j]) { if (item1->cov[j] < item2->cov[j]) {
return false; return false;
} }
} }
/* Both are equal */ /* Both are equal */
return false; return false;
} }
#define TAILQ_FOREACH_HF(var, head, field) \ #define TAILQ_FOREACH_HF(var, head, field) \
for ((var) = TAILQ_FIRST((head)); (var); (var) = TAILQ_NEXT((var), field)) for ((var) = TAILQ_FIRST((head)); (var); (var) = TAILQ_NEXT((var), field))
void input_addDynamicInput( void input_addDynamicInput(run_t* run) {
honggfuzz_t* hfuzz, const uint8_t* data, size_t len, uint64_t cov[4], const ATOMIC_SET(run->global->timing.lastCovUpdate, time(NULL));
char* path) {
ATOMIC_SET(hfuzz->timing.lastCovUpdate, time(NULL)); dynfile_t* dynfile = (dynfile_t*)util_Calloc(sizeof(dynfile_t));
dynfile->size = run->dynfile->size;
struct dynfile_t* dynfile = (struct dynfile_t*)util_Malloc(sizeof(struct dyn memcpy(dynfile->cov, run->dynfile->cov, sizeof(dynfile->cov));
file_t) + len); dynfile->timeExecUSecs = util_timeNowUSecs() - run->timeStartedUSecs;
for (size_t i = 0; i < ARRAYSIZE(dynfile->cov); i++) { dynfile->data = (uint8_t*)util_AllocCopy(run->dynfile->data, run->dynfile->s
dynfile->cov[i] = cov[i]; ize);
} dynfile->src = run->dynfile->src;
dynfile->size = len; if (run->dynfile->src) {
memcpy(dynfile->data, data, len); ATOMIC_POST_INC(run->dynfile->src->refs);
snprintf(dynfile->path, sizeof(dynfile->path), "%s", path); }
input_generateFileName(dynfile, NULL, dynfile->path);
MX_SCOPED_RWLOCK_WRITE(&hfuzz->io.dynfileq_mutex);
MX_SCOPED_RWLOCK_WRITE(&run->global->io.dynfileq_mutex);
/* Sort it by coverage - put better coverage in front of the list */
struct dynfile_t* iter = NULL; dynfile->idx = ATOMIC_PRE_INC(run->global->io.dynfileqCnt);
TAILQ_FOREACH_HF(iter, &hfuzz->io.dynfileq, pointers) {
run->global->feedback.maxCov[0] = HF_MAX(run->global->feedback.maxCov[0], dy
nfile->cov[0]);
run->global->feedback.maxCov[1] = HF_MAX(run->global->feedback.maxCov[1], dy
nfile->cov[1]);
run->global->feedback.maxCov[2] = HF_MAX(run->global->feedback.maxCov[2], dy
nfile->cov[2]);
run->global->feedback.maxCov[3] = HF_MAX(run->global->feedback.maxCov[3], dy
nfile->cov[3]);
run->global->io.dynfileqMaxSz = HF_MAX(run->global->io.dynfileqMaxSz, dynfil
e->size);
/* Sort it by coverage - put better coverage earlier in the list */
dynfile_t* iter = NULL;
TAILQ_FOREACH_HF(iter, &run->global->io.dynfileq, pointers) {
if (input_cmpCov(dynfile, iter)) { if (input_cmpCov(dynfile, iter)) {
TAILQ_INSERT_BEFORE(iter, dynfile, pointers); TAILQ_INSERT_BEFORE(iter, dynfile, pointers);
break; break;
} }
} }
if (iter == NULL) { if (iter == NULL) {
TAILQ_INSERT_TAIL(&hfuzz->io.dynfileq, dynfile, pointers); TAILQ_INSERT_TAIL(&run->global->io.dynfileq, dynfile, pointers);
} }
hfuzz->io.dynfileqCnt++;
if (hfuzz->socketFuzzer.enabled) { if (run->global->socketFuzzer.enabled) {
/* Don't add coverage data to files in socketFuzzer mode */ /* Don't add coverage data to files in socketFuzzer mode */
return; return;
} }
if (hfuzz->cfg.minimize) {
/* When minimizing we should only delete files */
return;
}
const char* outDir = hfuzz->io.outputDir ? hfuzz->io.outputDir : hfuzz->io.i const char* outDir =
nputDir; run->global->io.outputDir ? run->global->io.outputDir : run->global->io.
if (!input_writeCovFile(outDir, data, len)) { inputDir;
LOG_E("Couldn't save the coverage data to '%s'", hfuzz->io.outputDir); if (!input_writeCovFile(outDir, dynfile)) {
LOG_E("Couldn't save the coverage data to '%s'", run->global->io.outputD
ir);
} }
/* No need to add files to the new coverage dir, if it's not the main phase */ /* No need to add files to the new coverage dir, if it's not the main phase */
if (fuzz_getState(hfuzz) != _HF_STATE_DYNAMIC_MAIN) { if (fuzz_getState(run->global) != _HF_STATE_DYNAMIC_MAIN) {
return; return;
} }
hfuzz->io.newUnitsAdded++; ATOMIC_POST_INC(run->global->io.newUnitsAdded);
if (hfuzz->io.covDirNew && !input_writeCovFile(hfuzz->io.covDirNew, data, le if (run->global->io.covDirNew && !input_writeCovFile(run->global->io.covDirN
n)) { ew, dynfile)) {
LOG_E("Couldn't save the new coverage data to '%s'", hfuzz->io.covDirNew LOG_E("Couldn't save the new coverage data to '%s'", run->global->io.cov
); DirNew);
} }
} }
bool input_prepareDynamicInput(run_t* run, bool needs_mangle) { bool input_inDynamicCorpus(run_t* run, const char* fname) {
struct dynfile_t* current = NULL; MX_SCOPED_RWLOCK_WRITE(&run->global->io.dynfileq_mutex);
dynfile_t* iter = NULL;
TAILQ_FOREACH_HF(iter, &run->global->io.dynfileq, pointers) {
if (strncmp(iter->path, fname, PATH_MAX) == 0) {
return true;
}
}
return false;
}
static inline int input_speedFactor(run_t* run, dynfile_t* dynfile) {
/* Slower the input, lower the chance of it being tested */
uint64_t avg_usecs_per_input =
((uint64_t)(time(NULL) - run->global->timing.timeStart) * 1000000);
avg_usecs_per_input /= ATOMIC_GET(run->global->cnts.mutationsCnt);
avg_usecs_per_input /= run->global->threads.threadsMax;
/* Cap both vals to 1us-1s */
avg_usecs_per_input = HF_CAP(avg_usecs_per_input, 1U, 1000000U);
uint64_t sample_usecs = HF_CAP(dynfile->timeExecUSecs, 1U, 1000000U);
if (sample_usecs >= avg_usecs_per_input) {
return (int)(sample_usecs / avg_usecs_per_input);
} else {
return -(int)(avg_usecs_per_input / sample_usecs);
}
}
static inline int input_skipFactor(run_t* run, dynfile_t* dynfile, int* speed_fa
ctor) {
int penalty = 0;
{
*speed_factor = HF_CAP(input_speedFactor(run, dynfile) / 2, -15, 15);
penalty += *speed_factor;
}
{
/* Inputs with lower total coverage -> lower chance of being tested */
static const int scaleMap[200] = {
[95 ... 199] = -15,
[90 ... 94] = -7,
[80 ... 89] = -3,
[60 ... 79] = -1,
[50 ... 59] = 0,
[30 ... 49] = 5,
[11 ... 29] = 10,
[0 ... 10] = 15,
};
uint64_t maxCov0 = ATOMIC_GET(run->global->feedback.maxCov[0]);
if (maxCov0) {
const unsigned percentile = (dynfile->cov[0] * 100) / maxCov0;
penalty += scaleMap[percentile];
}
}
{
/* Older inputs -> lower chance of being tested */
static const int scaleMap[200] = {
[100 ... 199] = -10,
[95 ... 99] = -5,
[91 ... 94] = -1,
[81 ... 90] = 0,
[71 ... 80] = 1,
[41 ... 70] = 2,
[0 ... 40] = 3,
};
const unsigned percentile = (dynfile->idx * 100) / run->global->io.dynfi
leqCnt;
penalty += scaleMap[percentile];
}
{
/* If the input wasn't source of other inputs so far, make it less likel
y to be tested */
penalty += HF_CAP((1 - (int)dynfile->refs) * 3, -30, 5);
}
{
/* Add penalty for the input being too big - 0 is for 1kB inputs */
if (dynfile->size > 0) {
penalty += HF_CAP(((int)util_Log2(dynfile->size) - 10), -5, 5);
}
}
return penalty;
}
bool input_prepareDynamicInput(run_t* run, bool needs_mangle) {
if (ATOMIC_GET(run->global->io.dynfileqCnt) == 0) { if (ATOMIC_GET(run->global->io.dynfileqCnt) == 0) {
LOG_F("The dynamic file corpus is empty. This shouldn't happen"); LOG_F("The dynamic file corpus is empty. This shouldn't happen");
} }
{ int speed_factor = 0;
for (;;) {
MX_SCOPED_RWLOCK_WRITE(&run->global->io.dynfileq_mutex); MX_SCOPED_RWLOCK_WRITE(&run->global->io.dynfileq_mutex);
if (run->global->io.dynfileqCurrent == NULL) { if (run->global->io.dynfileqCurrent == NULL) {
run->global->io.dynfileqCurrent = TAILQ_FIRST(&run->global->io.dynfi leq); run->global->io.dynfileqCurrent = TAILQ_FIRST(&run->global->io.dynfi leq);
} }
current = run->global->io.dynfileqCurrent;
if (run->triesLeft) {
run->triesLeft--;
break;
}
run->current = run->global->io.dynfileqCurrent;
run->global->io.dynfileqCurrent = TAILQ_NEXT(run->global->io.dynfileqCur rent, pointers); run->global->io.dynfileqCurrent = TAILQ_NEXT(run->global->io.dynfileqCur rent, pointers);
int skip_factor = input_skipFactor(run, run->current, &speed_factor);
if (skip_factor <= 0) {
run->triesLeft = -(skip_factor);
break;
}
if ((util_rnd64() % skip_factor) == 0) {
break;
}
} }
input_setSize(run, current->size); input_setSize(run, run->current->size);
memcpy(run->dynamicFile, current->data, current->size); memcpy(run->dynfile->cov, run->current->cov, sizeof(run->dynfile->cov));
run->dynfile->idx = run->current->idx;
run->dynfile->timeExecUSecs = run->current->timeExecUSecs;
snprintf(run->dynfile->path, sizeof(run->dynfile->path), "%s", run->current-
>path);
run->dynfile->src = run->current;
run->dynfile->refs = 0;
memcpy(run->dynfile->data, run->current->data, run->current->size);
if (needs_mangle) { if (needs_mangle) {
mangle_mangleContent(run); mangle_mangleContent(run, speed_factor);
} }
return true; return true;
} }
size_t input_getRandomInputAsBuf(run_t* run, const uint8_t** buf) {
if (ATOMIC_GET(run->global->io.dynfileqCnt) == 0) {
LOG_E("The dynamic input queue shouldn't be empty");
*buf = NULL;
return 0;
}
dynfile_t* current = NULL;
{
MX_SCOPED_RWLOCK_WRITE(&run->global->io.dynfileq_mutex);
if (run->global->io.dynfileq2Current == NULL) {
run->global->io.dynfileq2Current = TAILQ_FIRST(&run->global->io.dynf
ileq);
}
current = run->global->io.dynfileq2Current;
run->global->io.dynfileq2Current = TAILQ_NEXT(run->global->io.dynfileq2C
urrent, pointers);
}
*buf = current->data;
return current->size;
}
static bool input_shouldReadNewFile(run_t* run) {
if (fuzz_getState(run->global) != _HF_STATE_DYNAMIC_DRY_RUN) {
input_setSize(run, run->global->mutate.maxInputSz);
return true;
}
if (!run->staticFileTryMore) {
run->staticFileTryMore = true;
/* Start with 4 bytes, increase the size in following iterations */
input_setSize(run, HF_MIN(4U, run->global->mutate.maxInputSz));
return true;
}
/* Increase size of the current file by a factor of 2, and return it instead
of a new file */
size_t newsz = run->dynfile->size * 2;
if (newsz >= run->global->mutate.maxInputSz) {
/* That's the largest size for this specific file that will be ever used
*/
newsz = run->global->mutate.maxInputSz;
run->staticFileTryMore = false;
}
input_setSize(run, newsz);
return false;
}
bool input_prepareStaticFile(run_t* run, bool rewind, bool needs_mangle) { bool input_prepareStaticFile(run_t* run, bool rewind, bool needs_mangle) {
if (!input_getNext(run, run->origFileName, /* rewind= */ rewind)) { if (input_shouldReadNewFile(run)) {
return false; for (;;) {
if (!input_getNext(run, run->dynfile->path, /* rewind= */ rewind)) {
return false;
}
if (!needs_mangle || !input_inDynamicCorpus(run, run->dynfile->path)
) {
LOG_D("Skipping '%s' as it's already in the dynamic corpus", run
->dynfile->path);
break;
}
}
run->global->io.testedFileCnt++;
} }
input_setSize(run, run->global->mutate.maxFileSz);
char path[PATH_MAX]; char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", run->global->io.inputDir, run->origFil eName); snprintf(path, sizeof(path), "%s/%s", run->global->io.inputDir, run->dynfile ->path);
ssize_t fileSz = files_readFileToBufMax(path, run->dynamicFile, run->global- >mutate.maxFileSz); ssize_t fileSz = files_readFileToBufMax(path, run->dynfile->data, run->dynfi le->size);
if (fileSz < 0) { if (fileSz < 0) {
LOG_E("Couldn't read contents of '%s'", path); LOG_E("Couldn't read contents of '%s'", path);
return false; return false;
} }
if (run->staticFileTryMore && ((size_t)fileSz < run->dynfile->size)) {
/* The file is smaller than the requested size, no need to re-read it an
ymore */
run->staticFileTryMore = false;
}
input_setSize(run, fileSz); input_setSize(run, fileSz);
memset(run->dynfile->cov, '\0', sizeof(run->dynfile->cov));
run->dynfile->idx = 0;
run->dynfile->src = NULL;
run->dynfile->refs = 0;
if (needs_mangle) { if (needs_mangle) {
mangle_mangleContent(run); mangle_mangleContent(run, /* slow_factor= */ 0);
} }
return true; return true;
} }
void input_removeStaticFile(const char* dir, const char* name) { bool input_removeStaticFile(const char* dir, const char* name) {
char path[PATH_MAX]; char path[PATH_MAX];
snprintf(path, sizeof(path), "%s/%s", dir, name); snprintf(path, sizeof(path), "%s/%s", dir, name);
if (unlink(path) == -1) { if (unlink(path) == -1 && errno != EEXIST) {
PLOG_E("unlink('%s') failed", path); PLOG_E("unlink('%s') failed", path);
return false;
} }
return true;
} }
bool input_prepareExternalFile(run_t* run) { bool input_prepareExternalFile(run_t* run) {
snprintf(run->origFileName, sizeof(run->origFileName), "[EXTERNAL]"); snprintf(run->dynfile->path, sizeof(run->dynfile->path), "[EXTERNAL]");
int fd = files_writeBufToTmpFile(run->global->io.workDir, (const uint8_t*)"" , 0, 0); int fd = files_writeBufToTmpFile(run->global->io.workDir, (const uint8_t*)"" , 0, 0);
if (fd == -1) { if (fd == -1) {
LOG_E("Couldn't write input file to a temporary buffer"); LOG_E("Couldn't write input file to a temporary buffer");
return false; return false;
} }
defer { defer {
close(fd); close(fd);
}; };
char fname[PATH_MAX]; char fname[PATH_MAX];
snprintf(fname, sizeof(fname), "/dev/fd/%d", fd); snprintf(fname, sizeof(fname), "/dev/fd/%d", fd);
const char* const argv[] = {run->global->exe.externalCommand, fname, NULL}; const char* const argv[] = {run->global->exe.externalCommand, fname, NULL};
if (subproc_System(run, argv) != 0) { if (subproc_System(run, argv) != 0) {
LOG_E("Subprocess '%s' returned abnormally", run->global->exe.externalCo mmand); LOG_E("Subprocess '%s' returned abnormally", run->global->exe.externalCo mmand);
return false; return false;
} }
LOG_D("Subporcess '%s' finished with success", run->global->exe.externalComm and); LOG_D("Subporcess '%s' finished with success", run->global->exe.externalComm and);
input_setSize(run, run->global->mutate.maxFileSz); input_setSize(run, run->global->mutate.maxInputSz);
ssize_t sz = files_readFromFdSeek(fd, run->dynamicFile, run->global->mutate. ssize_t sz = files_readFromFdSeek(fd, run->dynfile->data, run->global->mutat
maxFileSz, 0); e.maxInputSz, 0);
if (sz == -1) { if (sz == -1) {
LOG_E("Couldn't read file from fd=%d", fd); LOG_E("Couldn't read file from fd=%d", fd);
return false; return false;
} }
input_setSize(run, (size_t)sz); input_setSize(run, (size_t)sz);
return true; return true;
} }
bool input_postProcessFile(run_t* run, const char* cmd) { bool input_postProcessFile(run_t* run, const char* cmd) {
int fd = int fd =
files_writeBufToTmpFile(run->global->io.workDir, run->dynamicFile, run-> dynamicFileSz, 0); files_writeBufToTmpFile(run->global->io.workDir, run->dynfile->data, run ->dynfile->size, 0);
if (fd == -1) { if (fd == -1) {
LOG_E("Couldn't write input file to a temporary buffer"); LOG_E("Couldn't write input file to a temporary buffer");
return false; return false;
} }
defer { defer {
close(fd); close(fd);
}; };
char fname[PATH_MAX]; char fname[PATH_MAX];
snprintf(fname, sizeof(fname), "/dev/fd/%d", fd); snprintf(fname, sizeof(fname), "/dev/fd/%d", fd);
const char* const argv[] = {cmd, fname, NULL}; const char* const argv[] = {cmd, fname, NULL};
if (subproc_System(run, argv) != 0) { if (subproc_System(run, argv) != 0) {
LOG_E("Subprocess '%s' returned abnormally", cmd); LOG_E("Subprocess '%s' returned abnormally", cmd);
return false; return false;
} }
LOG_D("Subporcess '%s' finished with success", cmd); LOG_D("Subporcess '%s' finished with success", cmd);
input_setSize(run, run->global->mutate.maxFileSz); input_setSize(run, run->global->mutate.maxInputSz);
ssize_t sz = files_readFromFdSeek(fd, run->dynamicFile, run->global->mutate. ssize_t sz = files_readFromFdSeek(fd, run->dynfile->data, run->global->mutat
maxFileSz, 0); e.maxInputSz, 0);
if (sz == -1) { if (sz == -1) {
LOG_E("Couldn't read file from fd=%d", fd); LOG_E("Couldn't read file from fd=%d", fd);
return false; return false;
} }
input_setSize(run, (size_t)sz); input_setSize(run, (size_t)sz);
return true;
}
bool input_prepareDynamicFileForMinimization(run_t* run) {
MX_SCOPED_RWLOCK_WRITE(&run->global->io.dynfileq_mutex);
if (run->global->io.dynfileqCnt == 0) {
LOG_F("The dynamic file corpus is empty (for minimization). This shouldn
't happen");
}
if (run->global->io.dynfileqCurrent == NULL) {
run->global->io.dynfileqCurrent = TAILQ_FIRST(&run->global->io.dynfileq)
;
} else {
run->global->io.dynfileqCurrent = TAILQ_NEXT(run->global->io.dynfileqCur
rent, pointers);
}
if (run->global->io.dynfileqCurrent == NULL) {
return false;
}
input_setSize(run, run->global->io.dynfileqCurrent->size);
memcpy(run->dynamicFile, run->global->io.dynfileqCurrent->data,
run->global->io.dynfileqCurrent->size);
snprintf(
run->origFileName, sizeof(run->origFileName), "%s", run->global->io.dynf
ileqCurrent->path);
LOG_D("Cov: %" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64,
run->global->io.dynfileqCurrent->cov[0], run->global->io.dynfileqCurrent
->cov[1],
run->global->io.dynfileqCurrent->cov[2], run->global->io.dynfileqCurrent
->cov[3]);
return true; return true;
} }
 End of changes. 55 change blocks. 
153 lines changed or deleted 335 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)