Implement idea of total (all) and new coverage directories, as well as concept of crash directory
diff --git a/cmdline.c b/cmdline.c
index e107631..731cc66 100644
--- a/cmdline.c
+++ b/cmdline.c
@@ -135,8 +135,10 @@
.fileCnt = 0,
.fileCntDone = false,
.fileExtn = "fuzz",
- .workDir = ".",
- .covDir = NULL,
+ .workDir = NULL,
+ .crashDir = NULL,
+ .covDirAll = NULL,
+ .covDirNew = NULL,
.saveUnique = true,
},
.nullifyStdio = true,
@@ -282,7 +284,9 @@
{ { "debug_level", required_argument, NULL, 'd' }, "Debug level (0 - FATAL ... 4 - DEBUG), (default: '3' [INFO])" },
{ { "extension", required_argument, NULL, 'e' }, "Input file extension (e.g. 'swf'), (default: 'fuzz')" },
{ { "workspace", required_argument, NULL, 'W' }, "Workspace directory to save crashes & runtime files (default: '.')" },
- { { "covdir", required_argument, NULL, 0x103 }, "New coverage is written to a separate directory (default: use the input directory)" },
+ { { "crashdir", required_argument, NULL, 0x10b }, "Directory where crashes are saved to (default: workspace directory)" },
+ { { "covdir_all", required_argument, NULL, 0x103 }, "Coverage is written to a separate directory (default: input directory)" },
+ { { "covdir_new", required_argument, NULL, 0x10a }, "New coverage (beyond the dry-run fuzzing phase) is written to this separate directory" },
{ { "dict", required_argument, NULL, 'w' }, "Dictionary file. Format:http://llvm.org/docs/LibFuzzer.html#dictionaries" },
{ { "stackhash_bl", required_argument, NULL, 'B' }, "Stackhashes blacklist file (one entry per line)" },
{ { "mutate_cmd", required_argument, NULL, 'c' }, "External command producing fuzz files (instead of internal mutators)" },
@@ -344,6 +348,9 @@
break;
case 'f':
hfuzz->io.inputDir = optarg;
+ if (hfuzz->io.covDirAll == NULL) {
+ hfuzz->io.covDirAll = optarg;
+ }
break;
case 'x':
hfuzz->dynFileMethod = _HF_DYNFILE_NONE;
@@ -375,6 +382,9 @@
case 'W':
hfuzz->io.workDir = optarg;
break;
+ case 0x10b:
+ hfuzz->io.crashDir = optarg;
+ break;
case 'r':
hfuzz->mutationsPerRun = strtoul(optarg, NULL, 10);
break;
@@ -421,7 +431,10 @@
hfuzz->dataLimit = strtoull(optarg, NULL, 0);
break;
case 0x103:
- hfuzz->io.covDir = optarg;
+ hfuzz->io.covDirAll = optarg;
+ break;
+ case 0x10a:
+ hfuzz->io.covDirNew = optarg;
break;
case 0x104:
hfuzz->postExternalCommand = optarg;
@@ -558,11 +571,19 @@
return false;
}
- if (hfuzz->io.workDir[0] != '.' || strlen(hfuzz->io.workDir) > 2) {
- if (!files_exists(hfuzz->io.workDir)) {
- LOG_E("Provided workspace directory '%s' doesn't exist", hfuzz->io.workDir);
- return false;
- }
+ if (hfuzz->io.workDir == NULL) {
+ hfuzz->io.workDir = ".";
+ }
+ if (!files_exists(hfuzz->io.workDir)) {
+ LOG_E("Provided workspace directory '%s' doesn't exist", hfuzz->io.workDir);
+ return false;
+ }
+ if (hfuzz->io.crashDir == NULL) {
+ hfuzz->io.crashDir = hfuzz->io.workDir;
+ }
+ if (!files_exists(hfuzz->io.crashDir)) {
+ LOG_E("Provided crash directory '%s' doesn't exist", hfuzz->io.crashDir);
+ return false;
}
if (hfuzz->linux.pid > 0 || hfuzz->linux.pidFile) {
diff --git a/display.c b/display.c
index 1bd6dc4..c013197 100644
--- a/display.c
+++ b/display.c
@@ -187,7 +187,7 @@
}
}
display_put("\n Input Dir : [% " _HF_MONETARY_MOD "zu] '" ESC_BOLD "%s" ESC_RESET "'\n",
- ATOMIC_GET(hfuzz->io.fileCnt), hfuzz->io.inputDir != NULL ? hfuzz->io.inputDir : "[NONE]");
+ ATOMIC_GET(hfuzz->io.fileCnt), hfuzz->io.inputDir);
if (hfuzz->linux.pid > 0) {
display_put(" Remote cmd : [" ESC_BOLD "%d" ESC_RESET "] '" ESC_BOLD "%s" ESC_RESET "'\n",
diff --git a/fuzz.c b/fuzz.c
index f27baff..d6f4f20 100644
--- a/fuzz.c
+++ b/fuzz.c
@@ -371,6 +371,30 @@
return true;
}
+static bool fuzz_writeCovFile(const char* dir, const uint8_t* data, size_t len) {
+ char fname[PATH_MAX];
+
+ uint64_t crc64f = util_CRC64(data, len);
+ uint64_t crc64r = util_CRC64Rev(data, len);
+ snprintf(fname, sizeof(fname), "%s/%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 ".honggfuzz.cov",
+ dir, crc64f, crc64r, (uint32_t)len);
+
+ if (access(fname, R_OK) == 0) {
+ LOG_D("File '%s' already exists in the output corpus directory '%s'", fname, dir);
+ return true;
+ }
+
+ 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_TRUNC | O_CLOEXEC) ==
+ false) {
+ LOG_W("Couldn't write buffer to file '%s'", fname);
+ return false;
+ }
+
+ return true;
+}
+
static void fuzz_addFileToFileQ(run_t* run) {
struct dynfile_t* dynfile = (struct dynfile_t*)util_Malloc(sizeof(struct dynfile_t));
dynfile->size = run->dynamicFileSz;
@@ -381,29 +405,17 @@
TAILQ_INSERT_TAIL(&run->global->dynfileq, dynfile, pointers);
run->global->dynfileqCnt++;
- /* No need to add new coverage if we are supposed to append new coverage-inducing inputs only */
- if (run->state == _HF_STATE_DYNAMIC_PRE && run->global->io.covDir == NULL) {
- LOG_D("New coverage found, but we're in the initial coverage assessment state. Skipping");
+ if (!fuzz_writeCovFile(run->global->io.covDirAll, run->dynamicFile, run->dynamicFileSz)) {
+ LOG_E("Couldn't save the coverage data to '%s'", run->global->io.covDirAll);
+ }
+
+ /* No need to add files to the new coverage dir, if this is just the dry-run phase */
+ if (run->state == _HF_STATE_DYNAMIC_PRE || run->global->io.covDirNew == NULL) {
return;
}
- char fname[PATH_MAX];
- uint64_t crc64f = util_CRC64(run->dynamicFile, run->dynamicFileSz);
- uint64_t crc64r = util_CRC64Rev(run->dynamicFile, run->dynamicFileSz);
- snprintf(fname, sizeof(fname), "%s/%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 ".honggfuzz.cov",
- run->global->io.covDir ? run->global->io.covDir : run->global->io.inputDir, crc64f, crc64r,
- (uint32_t)run->dynamicFileSz);
-
- if (access(fname, R_OK) == 0) {
- LOG_D("File '%s' already exists in the corpus directory", fname);
- return;
- }
-
- LOG_D("Adding file '%s' to the corpus directory", fname);
-
- if (files_writeBufToFile(fname, run->dynamicFile, run->dynamicFileSz,
- O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_CLOEXEC) == false) {
- LOG_W("Couldn't write buffer to file '%s'", fname);
+ if (!fuzz_writeCovFile(run->global->io.covDirNew, run->dynamicFile, run->dynamicFileSz)) {
+ LOG_E("Couldn't save the new coverage data to '%s'", run->global->io.covDirNew);
}
}
diff --git a/honggfuzz.c b/honggfuzz.c
index ab870ba..2212ca0 100644
--- a/honggfuzz.c
+++ b/honggfuzz.c
@@ -150,15 +150,8 @@
}
if (!input_init(&hfuzz)) {
- if (hfuzz.externalCommand) {
- LOG_I(
- "No input file corpus loaded, the external command '%s' is responsible for "
- "creating the fuzz files",
- hfuzz.externalCommand);
- } else {
- LOG_F("Couldn't load input files");
- exit(EXIT_FAILURE);
- }
+ LOG_F("Couldn't load input corpus");
+ exit(EXIT_FAILURE);
}
if (hfuzz.dictionaryFile && (input_parseDictionary(&hfuzz) == false)) {
diff --git a/honggfuzz.h b/honggfuzz.h
index 180a390..bff83e4 100644
--- a/honggfuzz.h
+++ b/honggfuzz.h
@@ -178,13 +178,15 @@
bool useVerifier;
time_t timeStart;
struct {
- char* inputDir;
+ const char* inputDir;
DIR* inputDirP;
size_t fileCnt;
- char* fileExtn;
+ const char* fileExtn;
bool fileCntDone;
- char* workDir;
- char* covDir;
+ const char* workDir;
+ const char* crashDir;
+ const char* covDirAll;
+ const char* covDirNew;
bool saveUnique;
} io;
unsigned mutationsPerRun;
diff --git a/libcommon/files.c b/libcommon/files.c
index beaa829..8c02b24 100644
--- a/libcommon/files.c
+++ b/libcommon/files.c
@@ -112,7 +112,7 @@
return (ssize_t)readSz;
}
-bool files_exists(char* fileName) { return (access(fileName, F_OK) != -1); }
+bool files_exists(const char* fileName) { return (access(fileName, F_OK) != -1); }
bool files_writePatternToFd(int fd, off_t size, unsigned char p) {
void* buf = malloc(size);
@@ -161,7 +161,7 @@
return true;
}
-const char* files_basename(char* path) {
+const char* files_basename(const char* path) {
const char* base = strrchr(path, '/');
return base ? base + 1 : path;
}
diff --git a/libcommon/files.h b/libcommon/files.h
index 3be6984..0d7d9bd 100644
--- a/libcommon/files.h
+++ b/libcommon/files.h
@@ -46,9 +46,9 @@
bool files_sendToSocket(int fd, const uint8_t* buf, size_t fileSz);
-extern bool files_exists(char* fileName);
+extern bool files_exists(const char* fileName);
-extern const char* files_basename(char* fileName);
+extern const char* files_basename(const char* fileName);
extern bool files_copyFile(
const char* source, const char* destination, bool* dstExists, bool try_link);
diff --git a/libcommon/util.c b/libcommon/util.c
index b45760c..b3ceb6e 100644
--- a/libcommon/util.c
+++ b/libcommon/util.c
@@ -626,7 +626,7 @@
0x9090000000000000ULL,
};
-uint64_t util_CRC64(uint8_t* buf, size_t len) {
+uint64_t util_CRC64(const uint8_t* buf, size_t len) {
uint64_t res = 0ULL;
for (size_t i = 0; i < len; i++) {
@@ -636,7 +636,7 @@
return res;
}
-uint64_t util_CRC64Rev(uint8_t* buf, size_t len) {
+uint64_t util_CRC64Rev(const uint8_t* buf, size_t len) {
uint64_t res = 0ULL;
for (ssize_t i = (ssize_t)len - 1; i >= 0; i--) {
diff --git a/libcommon/util.h b/libcommon/util.h
index ff152af..76cacdb 100644
--- a/libcommon/util.h
+++ b/libcommon/util.h
@@ -119,7 +119,7 @@
extern size_t util_decodeCString(char* s);
-extern uint64_t util_CRC64(uint8_t* buf, size_t len);
-extern uint64_t util_CRC64Rev(uint8_t* buf, size_t len);
+extern uint64_t util_CRC64(const uint8_t* buf, size_t len);
+extern uint64_t util_CRC64Rev(const uint8_t* buf, size_t len);
#endif
diff --git a/linux/trace.c b/linux/trace.c
index e09209f..18471c2 100644
--- a/linux/trace.c
+++ b/linux/trace.c
@@ -797,19 +797,19 @@
/* If dry run mode, copy file with same name into workspace */
if (run->global->mutationsPerRun == 0U && run->global->useVerifier) {
- snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.workDir,
+ snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
run->origFileName);
} else if (saveUnique) {
snprintf(run->crashFileName, sizeof(run->crashFileName),
"%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s",
- run->global->io.workDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
+ run->global->io.crashDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
sig_addr, instr, run->global->io.fileExtn);
} else {
char localtmstr[PATH_MAX];
util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
snprintf(run->crashFileName, sizeof(run->crashFileName),
"%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%d.ADDR.%p.INSTR.%s.%s.%d.%s",
- run->global->io.workDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
+ run->global->io.crashDir, arch_sigName(si.si_signo), pc, run->backtrace, si.si_code,
sig_addr, instr, localtmstr, pid, run->global->io.fileExtn);
}
@@ -1026,14 +1026,14 @@
/* If dry run mode, copy file with same name into workspace */
if (run->global->mutationsPerRun == 0U && run->global->useVerifier) {
- snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.workDir,
+ snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
run->origFileName);
} else {
/* Keep the crashes file name format identical */
if (run->backtrace != 0ULL && run->global->io.saveUnique) {
snprintf(run->crashFileName, sizeof(run->crashFileName),
"%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%s.ADDR.%p.INSTR.%s.%s",
- run->global->io.workDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
+ run->global->io.crashDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
run->global->io.fileExtn);
} else {
/* If no stack hash available, all crashes treated as unique */
@@ -1041,7 +1041,7 @@
util_getLocalTime("%F.%H:%M:%S", localtmstr, sizeof(localtmstr), time(NULL));
snprintf(run->crashFileName, sizeof(run->crashFileName),
"%s/%s.PC.%" REG_PM ".STACK.%" PRIx64 ".CODE.%s.ADDR.%p.INSTR.%s.%s.%s",
- run->global->io.workDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
+ run->global->io.crashDir, "SAN", pc, run->backtrace, op, crashAddr, "[UNKNOWN]",
localtmstr, run->global->io.fileExtn);
}
}
diff --git a/mac/arch.c b/mac/arch.c
index 543b5fe..b9a629a 100644
--- a/mac/arch.c
+++ b/mac/arch.c
@@ -252,11 +252,11 @@
/* If dry run mode, copy file with same name into workspace */
if (run->global->mutationsPerRun == 0U && run->global->useVerifier) {
- snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.workDir,
+ snprintf(run->crashFileName, sizeof(run->crashFileName), "%s/%s", run->global->io.crashDir,
run->origFileName);
} else if (run->global->io.saveUnique) {
snprintf(run->crashFileName, sizeof(run->crashFileName),
- "%s/%s.%s.PC.%.16llx.STACK.%.16llx.ADDR.%.16llx.%s", run->global->io.workDir,
+ "%s/%s.%s.PC.%.16llx.STACK.%.16llx.ADDR.%.16llx.%s", run->global->io.crashDir,
arch_sigs[termsig].descr, exception_to_string(run->exception), run->pc, run->backtrace,
run->access, run->global->io.fileExtn);
} else {
@@ -265,7 +265,7 @@
snprintf(run->crashFileName, sizeof(run->crashFileName),
"%s/%s.%s.PC.%.16llx.STACK.%.16llx.ADDR.%.16llx.TIME.%s.PID.%.5d.%s",
- run->global->io.workDir, arch_sigs[termsig].descr, exception_to_string(run->exception),
+ run->global->io.crashDir, arch_sigs[termsig].descr, exception_to_string(run->exception),
run->pc, run->backtrace, run->access, localtmstr, run->pid, run->global->io.fileExtn);
}
diff --git a/posix/arch.c b/posix/arch.c
index 12225b3..82cf929 100644
--- a/posix/arch.c
+++ b/posix/arch.c
@@ -125,7 +125,7 @@
if (run->global->mutationsPerRun == 0U && run->global->useVerifier) {
snprintf(newname, sizeof(newname), "%s", run->origFileName);
} else {
- snprintf(newname, sizeof(newname), "%s/%s.PID.%d.TIME.%s.%s", run->global->io.workDir,
+ snprintf(newname, sizeof(newname), "%s/%s.PID.%d.TIME.%s.%s", run->global->io.crashDir,
arch_sigs[termsig].descr, run->pid, localtmstr, run->global->io.fileExtn);
}