blob: 806435965d94bff6c53c7e70b98fe4e9dec0f356 [file] [log] [blame]
Robert Swiecki47476f22017-09-28 15:45:02 +02001/*
2 *
3 * honggfuzz - file operations
4 * -----------------------------------------
5 *
6 * Author: Robert Swiecki <swiecki@google.com>
7 *
8 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
11 * not use this file except in compliance with the License. You may obtain
12 * a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
19 * implied. See the License for the specific language governing
20 * permissions and limitations under the License.
21 *
22 */
23
24#include "input.h"
25
26#include <dirent.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <inttypes.h>
30#include <stdint.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/mman.h>
35#include <sys/socket.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include <unistd.h>
39
40#include "libcommon/common.h"
41#include "libcommon/files.h"
42
43#if defined(_HF_ARCH_LINUX)
44#include <sys/syscall.h>
45#if defined(__NR_memfd_create)
46#include <linux/memfd.h>
Robert Swiecki4e595fb2017-10-11 17:26:51 +020047#endif /* defined(__NR_memfd_create) */
48#endif /* defined(_HF_ARCH_LINUX) */
Robert Swiecki47476f22017-09-28 15:45:02 +020049
50#include "libcommon/log.h"
51#include "libcommon/util.h"
52
Robert Swieckid50ed422017-11-13 23:32:26 +010053static bool input_getDirStatsAndRewind(honggfuzz_t* hfuzz) {
Robert Swieckia35d9d82017-12-15 22:00:41 +010054 rewinddir(hfuzz->io.inputDirPtr);
Robert Swiecki47476f22017-09-28 15:45:02 +020055
56 size_t maxSize = 0U;
57 size_t fileCnt = 0U;
58 for (;;) {
59 errno = 0;
Robert Swieckia35d9d82017-12-15 22:00:41 +010060 struct dirent* entry = readdir(hfuzz->io.inputDirPtr);
Robert Swiecki47476f22017-09-28 15:45:02 +020061 if (entry == NULL && errno == EINTR) {
62 continue;
63 }
64 if (entry == NULL && errno != 0) {
Robert Swiecki82c707c2017-11-14 16:36:23 +010065 PLOG_W("readdir('%s')", hfuzz->io.inputDir);
Robert Swiecki47476f22017-09-28 15:45:02 +020066 return false;
67 }
68 if (entry == NULL) {
69 break;
70 }
71
72 char fname[PATH_MAX];
Robert Swiecki82c707c2017-11-14 16:36:23 +010073 snprintf(fname, sizeof(fname), "%s/%s", hfuzz->io.inputDir, entry->d_name);
Robert Swiecki47476f22017-09-28 15:45:02 +020074 LOG_D("Analyzing file '%s'", fname);
75
76 struct stat st;
77 if (stat(fname, &st) == -1) {
78 LOG_W("Couldn't stat() the '%s' file", fname);
79 continue;
80 }
81 if (!S_ISREG(st.st_mode)) {
82 LOG_D("'%s' is not a regular file, skipping", fname);
83 continue;
84 }
Robert Swiecki4e595fb2017-10-11 17:26:51 +020085 if (hfuzz->maxFileSz != 0UL && st.st_size > (off_t)hfuzz->maxFileSz) {
Robert Swieckid0fa62c2017-09-28 18:11:05 +020086 LOG_W("File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %" PRId64,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020087 fname, (int64_t)st.st_size, (int64_t)hfuzz->maxFileSz);
Robert Swiecki47476f22017-09-28 15:45:02 +020088 }
Robert Swiecki4e595fb2017-10-11 17:26:51 +020089 if ((size_t)st.st_size > maxSize) {
Robert Swiecki47476f22017-09-28 15:45:02 +020090 maxSize = st.st_size;
91 }
92 fileCnt++;
93 }
94
Robert Swiecki82c707c2017-11-14 16:36:23 +010095 ATOMIC_SET(hfuzz->io.fileCnt, fileCnt);
Robert Swiecki47476f22017-09-28 15:45:02 +020096 if (hfuzz->maxFileSz == 0U) {
97 if (maxSize < 8192) {
98 hfuzz->maxFileSz = 8192;
99 } else {
100 hfuzz->maxFileSz = maxSize;
101 }
102 }
103 if (hfuzz->persistent && hfuzz->maxFileSz > (1024U * 128)) {
104 LOG_D("Persistent mode enabled, lowering maximum input size to 128KiB");
105 hfuzz->maxFileSz = 1024U * 128;
106 }
107
Robert Swiecki82c707c2017-11-14 16:36:23 +0100108 if (hfuzz->io.fileCnt == 0U) {
109 LOG_W("No usable files in the input directory '%s'", hfuzz->io.inputDir);
Robert Swiecki47476f22017-09-28 15:45:02 +0200110 return false;
111 }
112
Robert Swiecki82c707c2017-11-14 16:36:23 +0100113 LOG_D("Re-read the '%s', maxFileSz:%zu, number of usable files:%zu", hfuzz->io.inputDir,
114 hfuzz->maxFileSz, hfuzz->io.fileCnt);
Robert Swiecki47476f22017-09-28 15:45:02 +0200115
Robert Swieckia35d9d82017-12-15 22:00:41 +0100116 rewinddir(hfuzz->io.inputDirPtr);
Robert Swiecki47476f22017-09-28 15:45:02 +0200117
118 return true;
119}
120
Robert Swieckid50ed422017-11-13 23:32:26 +0100121bool input_getNext(run_t* run, char* fname, bool rewind) {
Robert Swiecki47476f22017-09-28 15:45:02 +0200122 static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER;
123 MX_SCOPED_LOCK(&input_mutex);
124
Robert Swiecki82c707c2017-11-14 16:36:23 +0100125 if (run->global->io.fileCnt == 0U) {
Robert Swiecki47476f22017-09-28 15:45:02 +0200126 return false;
127 }
128
129 for (;;) {
130 errno = 0;
Robert Swieckia35d9d82017-12-15 22:00:41 +0100131 struct dirent* entry = readdir(run->global->io.inputDirPtr);
Robert Swiecki47476f22017-09-28 15:45:02 +0200132 if (entry == NULL && errno == EINTR) {
133 continue;
134 }
135 if (entry == NULL && errno != 0) {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100136 PLOG_W("readdir_r('%s')", run->global->io.inputDir);
Robert Swiecki47476f22017-09-28 15:45:02 +0200137 return false;
138 }
139 if (entry == NULL && rewind == false) {
140 return false;
141 }
142 if (entry == NULL && rewind == true) {
Robert Swiecki78633d12017-11-13 23:24:55 +0100143 if (input_getDirStatsAndRewind(run->global) == false) {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100144 LOG_E("input_getDirStatsAndRewind('%s')", run->global->io.inputDir);
Robert Swiecki47476f22017-09-28 15:45:02 +0200145 return false;
146 }
147 continue;
148 }
149
Robert Swiecki82c707c2017-11-14 16:36:23 +0100150 snprintf(fname, PATH_MAX, "%s/%s", run->global->io.inputDir, entry->d_name);
Robert Swiecki47476f22017-09-28 15:45:02 +0200151
152 struct stat st;
153 if (stat(fname, &st) == -1) {
154 LOG_W("Couldn't stat() the '%s' file", fname);
155 continue;
156 }
157 if (!S_ISREG(st.st_mode)) {
158 LOG_D("'%s' is not a regular file, skipping", fname);
159 continue;
160 }
Robert Swiecki47476f22017-09-28 15:45:02 +0200161 return true;
162 }
163}
164
Robert Swieckid50ed422017-11-13 23:32:26 +0100165bool input_init(honggfuzz_t* hfuzz) {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100166 hfuzz->io.fileCnt = 0U;
Robert Swiecki47476f22017-09-28 15:45:02 +0200167
Robert Swiecki82c707c2017-11-14 16:36:23 +0100168 if (!hfuzz->io.inputDir) {
Robert Swiecki47476f22017-09-28 15:45:02 +0200169 LOG_W("No input file/dir specified");
170 return false;
171 }
172
Robert Swiecki82c707c2017-11-14 16:36:23 +0100173 int dir_fd = open(hfuzz->io.inputDir, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
Robert Swiecki47476f22017-09-28 15:45:02 +0200174 if (dir_fd == -1) {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100175 PLOG_W("open('%s', O_DIRECTORY|O_RDONLY|O_CLOEXEC)", hfuzz->io.inputDir);
Robert Swiecki47476f22017-09-28 15:45:02 +0200176 return false;
177 }
Robert Swieckia35d9d82017-12-15 22:00:41 +0100178 if ((hfuzz->io.inputDirPtr = fdopendir(dir_fd)) == NULL) {
Robert Swiecki47476f22017-09-28 15:45:02 +0200179 close(dir_fd);
Robert Swiecki82c707c2017-11-14 16:36:23 +0100180 PLOG_W("opendir('%s')", hfuzz->io.inputDir);
Robert Swiecki47476f22017-09-28 15:45:02 +0200181 return false;
182 }
183 if (input_getDirStatsAndRewind(hfuzz) == false) {
Robert Swiecki82c707c2017-11-14 16:36:23 +0100184 hfuzz->io.fileCnt = 0U;
185 LOG_W("input_getDirStatsAndRewind('%s')", hfuzz->io.inputDir);
Robert Swiecki47476f22017-09-28 15:45:02 +0200186 return false;
187 }
188
189 return true;
190}
191
Robert Swieckid50ed422017-11-13 23:32:26 +0100192bool input_parseDictionary(honggfuzz_t* hfuzz) {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200193 FILE* fDict = fopen(hfuzz->dictionaryFile, "rb");
Robert Swiecki47476f22017-09-28 15:45:02 +0200194 if (fDict == NULL) {
195 PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->dictionaryFile);
196 return false;
197 }
Robert Swiecki0b566112017-10-17 17:39:07 +0200198 defer { fclose(fDict); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200199
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200200 char* lineptr = NULL;
Robert Swiecki47476f22017-09-28 15:45:02 +0200201 size_t n = 0;
Robert Swiecki0b566112017-10-17 17:39:07 +0200202 defer { free(lineptr); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200203 for (;;) {
204 ssize_t len = getdelim(&lineptr, &n, '\n', fDict);
205 if (len == -1) {
206 break;
207 }
208 if (len > 1 && lineptr[len - 1] == '\n') {
209 lineptr[len - 1] = '\0';
210 len--;
211 }
212 if (lineptr[0] == '#') {
213 continue;
214 }
215 if (lineptr[0] == '\n') {
216 continue;
217 }
218 if (lineptr[0] == '\0') {
219 continue;
220 }
Robert Swiecki49117302017-12-27 20:47:31 +0100221 char bufn[1025] = {};
222 char bufv[1025] = {};
223 if (sscanf(lineptr, "\"%1024[^\"]", bufv) != 1 &&
224 sscanf(lineptr, "%1024[^=]=\"%1024[^\"]", bufn, bufv) != 2) {
Robert Swiecki47476f22017-09-28 15:45:02 +0200225 LOG_W("Incorrect dictionary entry: '%s'. Skipping", lineptr);
226 continue;
227 }
228
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200229 char* s = util_StrDup(bufv);
230 struct strings_t* str = (struct strings_t*)util_Malloc(sizeof(struct strings_t));
Robert Swiecki47476f22017-09-28 15:45:02 +0200231 str->len = util_decodeCString(s);
232 str->s = s;
233 hfuzz->dictionaryCnt += 1;
234 TAILQ_INSERT_TAIL(&hfuzz->dictq, str, pointers);
235
236 LOG_D("Dictionary: loaded word: '%s' (len=%zu)", str->s, str->len);
237 }
238 LOG_I("Loaded %zu words from the dictionary", hfuzz->dictionaryCnt);
239 return true;
240}
241
Robert Swieckid50ed422017-11-13 23:32:26 +0100242bool input_parseBlacklist(honggfuzz_t* hfuzz) {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200243 FILE* fBl = fopen(hfuzz->blacklistFile, "rb");
Robert Swiecki47476f22017-09-28 15:45:02 +0200244 if (fBl == NULL) {
245 PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->blacklistFile);
246 return false;
247 }
Robert Swiecki0b566112017-10-17 17:39:07 +0200248 defer { fclose(fBl); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200249
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200250 char* lineptr = NULL;
Robert Swiecki47476f22017-09-28 15:45:02 +0200251 /* lineptr can be NULL, but it's fine for free() */
Robert Swiecki0b566112017-10-17 17:39:07 +0200252 defer { free(lineptr); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200253 size_t n = 0;
254 for (;;) {
255 if (getline(&lineptr, &n, fBl) == -1) {
256 break;
257 }
258
Robert Swieckid50ed422017-11-13 23:32:26 +0100259 if ((hfuzz->blacklist = util_Realloc(hfuzz->blacklist,
260 (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]))) == NULL) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200261 PLOG_W(
262 "realloc failed (sz=%zu)", (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]));
Robert Swiecki47476f22017-09-28 15:45:02 +0200263 return false;
264 }
265
266 hfuzz->blacklist[hfuzz->blacklistCnt] = strtoull(lineptr, 0, 16);
267 LOG_D("Blacklist: loaded %'" PRIu64 "'", hfuzz->blacklist[hfuzz->blacklistCnt]);
268
269 // Verify entries are sorted so we can use interpolation search
270 if (hfuzz->blacklistCnt > 1) {
271 if (hfuzz->blacklist[hfuzz->blacklistCnt - 1] > hfuzz->blacklist[hfuzz->blacklistCnt]) {
Robert Swieckid50ed422017-11-13 23:32:26 +0100272 LOG_F(
273 "Blacklist file not sorted. Use 'tools/createStackBlacklist.sh' to sort "
274 "records");
Robert Swiecki47476f22017-09-28 15:45:02 +0200275 return false;
276 }
277 }
278 hfuzz->blacklistCnt += 1;
279 }
280
281 if (hfuzz->blacklistCnt > 0) {
282 LOG_I("Loaded %zu stack hash(es) from the blacklist file", hfuzz->blacklistCnt);
283 } else {
284 LOG_F("Empty stack hashes blacklist file '%s'", hfuzz->blacklistFile);
285 }
286 return true;
287}