summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Swiecki <robert@swiecki.net>2017-09-28 15:45:02 +0200
committerRobert Swiecki <robert@swiecki.net>2017-09-28 15:45:02 +0200
commit47476f22f795f3813f42249efaa44d8afe2eba48 (patch)
tree2e2219eba265bbf9ae301d8e9421798efaadbcd1
parent0ff5b7c7b4dd7e2e14ae282db77199ff27430614 (diff)
downloadhonggfuzz-47476f22f795f3813f42249efaa44d8afe2eba48.tar.gz
Move the honggfuzz_t and fuzzer_t types out of common #3
-rw-r--r--input.c308
-rw-r--r--input.h37
2 files changed, 345 insertions, 0 deletions
diff --git a/input.c b/input.c
new file mode 100644
index 00000000..63d728fa
--- /dev/null
+++ b/input.c
@@ -0,0 +1,308 @@
+/*
+ *
+ * honggfuzz - file operations
+ * -----------------------------------------
+ *
+ * Author: Robert Swiecki <swiecki@google.com>
+ *
+ * Copyright 2010-2015 by Google Inc. All Rights Reserved.
+ *
+ * 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
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ */
+
+#include "input.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "libcommon/common.h"
+#include "libcommon/files.h"
+
+#if defined(_HF_ARCH_LINUX)
+#include <sys/syscall.h>
+#if defined(__NR_memfd_create)
+#include <linux/memfd.h>
+#endif /* defined(__NR_memfd_create) */
+#endif /* defined(_HF_ARCH_LINUX) */
+
+#include "libcommon/log.h"
+#include "libcommon/util.h"
+
+static bool input_getDirStatsAndRewind(honggfuzz_t * hfuzz)
+{
+ rewinddir(hfuzz->inputDirP);
+
+ size_t maxSize = 0U;
+ size_t fileCnt = 0U;
+ for (;;) {
+ errno = 0;
+ struct dirent *entry = readdir(hfuzz->inputDirP);
+ if (entry == NULL && errno == EINTR) {
+ continue;
+ }
+ if (entry == NULL && errno != 0) {
+ PLOG_W("readdir('%s')", hfuzz->inputDir);
+ return false;
+ }
+ if (entry == NULL) {
+ break;
+ }
+
+ char fname[PATH_MAX];
+ snprintf(fname, sizeof(fname), "%s/%s", hfuzz->inputDir, entry->d_name);
+ LOG_D("Analyzing file '%s'", fname);
+
+ struct stat st;
+ if (stat(fname, &st) == -1) {
+ LOG_W("Couldn't stat() the '%s' file", fname);
+ continue;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ LOG_D("'%s' is not a regular file, skipping", fname);
+ continue;
+ }
+ if (hfuzz->maxFileSz != 0UL && st.st_size > (off_t) hfuzz->maxFileSz) {
+ LOG_W("File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %"
+ PRId64, fname, (int64_t) st.st_size, (int64_t) hfuzz->maxFileSz);
+ }
+ if (st.st_size == 0U) {
+ LOG_W("File '%s' is empty", fname);
+ continue;
+ }
+ if ((size_t) st.st_size > maxSize) {
+ maxSize = st.st_size;
+ }
+ fileCnt++;
+ }
+
+ ATOMIC_SET(hfuzz->fileCnt, fileCnt);
+ if (hfuzz->maxFileSz == 0U) {
+ if (maxSize < 8192) {
+ hfuzz->maxFileSz = 8192;
+ } else {
+ hfuzz->maxFileSz = maxSize;
+ }
+ }
+ if (hfuzz->persistent && hfuzz->maxFileSz > (1024U * 128)) {
+ LOG_D("Persistent mode enabled, lowering maximum input size to 128KiB");
+ hfuzz->maxFileSz = 1024U * 128;
+ }
+
+ if (hfuzz->fileCnt == 0U) {
+ LOG_W("No usable files in the input directory '%s'", hfuzz->inputDir);
+ return false;
+ }
+
+ LOG_D("Re-read the '%s', maxFileSz:%zu, number of usable files:%zu", hfuzz->inputDir,
+ hfuzz->maxFileSz, hfuzz->fileCnt);
+
+ rewinddir(hfuzz->inputDirP);
+
+ return true;
+}
+
+bool input_getNext(honggfuzz_t * hfuzz, char *fname, bool rewind)
+{
+ static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER;
+ MX_SCOPED_LOCK(&input_mutex);
+
+ if (hfuzz->fileCnt == 0U) {
+ return false;
+ }
+
+ for (;;) {
+ errno = 0;
+ struct dirent *entry = readdir(hfuzz->inputDirP);
+ if (entry == NULL && errno == EINTR) {
+ continue;
+ }
+ if (entry == NULL && errno != 0) {
+ PLOG_W("readdir_r('%s')", hfuzz->inputDir);
+ return false;
+ }
+ if (entry == NULL && rewind == false) {
+ return false;
+ }
+ if (entry == NULL && rewind == true) {
+ if (input_getDirStatsAndRewind(hfuzz) == false) {
+ LOG_E("input_getDirStatsAndRewind('%s')", hfuzz->inputDir);
+ return false;
+ }
+ continue;
+ }
+
+ snprintf(fname, PATH_MAX, "%s/%s", hfuzz->inputDir, entry->d_name);
+
+ struct stat st;
+ if (stat(fname, &st) == -1) {
+ LOG_W("Couldn't stat() the '%s' file", fname);
+ continue;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ LOG_D("'%s' is not a regular file, skipping", fname);
+ continue;
+ }
+ if (st.st_size == 0U) {
+ LOG_D("File '%s' is empty", fname);
+ continue;
+ }
+ return true;
+ }
+}
+
+bool input_init(honggfuzz_t * hfuzz)
+{
+ hfuzz->fileCnt = 0U;
+
+ if (!hfuzz->inputDir) {
+ LOG_W("No input file/dir specified");
+ return false;
+ }
+
+ int dir_fd = open(hfuzz->inputDir, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+ if (dir_fd == -1) {
+ PLOG_W("open('%s', O_DIRECTORY|O_RDONLY|O_CLOEXEC)", hfuzz->inputDir);
+ return false;
+ }
+ if ((hfuzz->inputDirP = fdopendir(dir_fd)) == NULL) {
+ close(dir_fd);
+ PLOG_W("opendir('%s')", hfuzz->inputDir);
+ return false;
+ }
+ if (input_getDirStatsAndRewind(hfuzz) == false) {
+ hfuzz->fileCnt = 0U;
+ LOG_W("input_getDirStatsAndRewind('%s')", hfuzz->inputDir);
+ return false;
+ }
+
+ return true;
+}
+
+bool input_parseDictionary(honggfuzz_t * hfuzz)
+{
+ FILE *fDict = fopen(hfuzz->dictionaryFile, "rb");
+ if (fDict == NULL) {
+ PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->dictionaryFile);
+ return false;
+ }
+ defer {
+ fclose(fDict);
+ };
+
+ char *lineptr = NULL;
+ size_t n = 0;
+ defer {
+ free(lineptr);
+ };
+ for (;;) {
+ ssize_t len = getdelim(&lineptr, &n, '\n', fDict);
+ if (len == -1) {
+ break;
+ }
+ if (len > 1 && lineptr[len - 1] == '\n') {
+ lineptr[len - 1] = '\0';
+ len--;
+ }
+ if (lineptr[0] == '#') {
+ continue;
+ }
+ if (lineptr[0] == '\n') {
+ continue;
+ }
+ if (lineptr[0] == '\0') {
+ continue;
+ }
+ char bufn[1025] = { 0 };
+ char bufv[1025] = { 0 };
+ if (sscanf(lineptr, "\"%1024s", bufv) != 1 &&
+ sscanf(lineptr, "%1024[^=]=\"%1024s", bufn, bufv) != 2) {
+ LOG_W("Incorrect dictionary entry: '%s'. Skipping", lineptr);
+ continue;
+ }
+
+ char *s = util_StrDup(bufv);
+ struct strings_t *str = (struct strings_t *)util_Malloc(sizeof(struct strings_t));
+ str->len = util_decodeCString(s);
+ str->s = s;
+ hfuzz->dictionaryCnt += 1;
+ TAILQ_INSERT_TAIL(&hfuzz->dictq, str, pointers);
+
+ LOG_D("Dictionary: loaded word: '%s' (len=%zu)", str->s, str->len);
+ }
+ LOG_I("Loaded %zu words from the dictionary", hfuzz->dictionaryCnt);
+ return true;
+}
+
+bool input_parseBlacklist(honggfuzz_t * hfuzz)
+{
+ FILE *fBl = fopen(hfuzz->blacklistFile, "rb");
+ if (fBl == NULL) {
+ PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->blacklistFile);
+ return false;
+ }
+ defer {
+ fclose(fBl);
+ };
+
+ char *lineptr = NULL;
+ /* lineptr can be NULL, but it's fine for free() */
+ defer {
+ free(lineptr);
+ };
+ size_t n = 0;
+ for (;;) {
+ if (getline(&lineptr, &n, fBl) == -1) {
+ break;
+ }
+
+ if ((hfuzz->blacklist =
+ util_Realloc(hfuzz->blacklist,
+ (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]))) == NULL) {
+ PLOG_W("realloc failed (sz=%zu)",
+ (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]));
+ return false;
+ }
+
+ hfuzz->blacklist[hfuzz->blacklistCnt] = strtoull(lineptr, 0, 16);
+ LOG_D("Blacklist: loaded %'" PRIu64 "'", hfuzz->blacklist[hfuzz->blacklistCnt]);
+
+ // Verify entries are sorted so we can use interpolation search
+ if (hfuzz->blacklistCnt > 1) {
+ if (hfuzz->blacklist[hfuzz->blacklistCnt - 1] > hfuzz->blacklist[hfuzz->blacklistCnt]) {
+ LOG_F
+ ("Blacklist file not sorted. Use 'tools/createStackBlacklist.sh' to sort records");
+ return false;
+ }
+ }
+ hfuzz->blacklistCnt += 1;
+ }
+
+ if (hfuzz->blacklistCnt > 0) {
+ LOG_I("Loaded %zu stack hash(es) from the blacklist file", hfuzz->blacklistCnt);
+ } else {
+ LOG_F("Empty stack hashes blacklist file '%s'", hfuzz->blacklistFile);
+ }
+ return true;
+}
diff --git a/input.h b/input.h
new file mode 100644
index 00000000..8f5632d9
--- /dev/null
+++ b/input.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * honggfuzz - fetching input for fuzzing
+ * -----------------------------------------
+ *
+ * Author: Robert Swiecki <swiecki@google.com>
+ *
+ * Copyright 2010-2015 by Google Inc. All Rights Reserved.
+ *
+ * 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
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ */
+
+#ifndef _HF_INPUT_H_
+#define _HF_INPUT_H_
+
+#include "honggfuzz.h"
+
+extern bool input_getNext(honggfuzz_t * hfuzz, char *fname, bool rewind);
+
+extern bool input_init(honggfuzz_t * hfuzz);
+
+extern bool input_parseDictionary(honggfuzz_t * hfuzz);
+
+extern bool input_parseBlacklist(honggfuzz_t * hfuzz);
+
+#endif /* ifndef _HF_INPUT_H_ */