blob: a9d44fdefbafd05ea0916348dc15fdd38deae083 [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 Swiecki4e595fb2017-10-11 17:26:51 +020053static bool input_getDirStatsAndRewind(honggfuzz_t* hfuzz)
Robert Swiecki47476f22017-09-28 15:45:02 +020054{
55 rewinddir(hfuzz->inputDirP);
56
57 size_t maxSize = 0U;
58 size_t fileCnt = 0U;
59 for (;;) {
60 errno = 0;
Robert Swiecki4e595fb2017-10-11 17:26:51 +020061 struct dirent* entry = readdir(hfuzz->inputDirP);
Robert Swiecki47476f22017-09-28 15:45:02 +020062 if (entry == NULL && errno == EINTR) {
63 continue;
64 }
65 if (entry == NULL && errno != 0) {
66 PLOG_W("readdir('%s')", hfuzz->inputDir);
67 return false;
68 }
69 if (entry == NULL) {
70 break;
71 }
72
73 char fname[PATH_MAX];
74 snprintf(fname, sizeof(fname), "%s/%s", hfuzz->inputDir, entry->d_name);
75 LOG_D("Analyzing file '%s'", fname);
76
77 struct stat st;
78 if (stat(fname, &st) == -1) {
79 LOG_W("Couldn't stat() the '%s' file", fname);
80 continue;
81 }
82 if (!S_ISREG(st.st_mode)) {
83 LOG_D("'%s' is not a regular file, skipping", fname);
84 continue;
85 }
Robert Swiecki4e595fb2017-10-11 17:26:51 +020086 if (hfuzz->maxFileSz != 0UL && st.st_size > (off_t)hfuzz->maxFileSz) {
Robert Swieckid0fa62c2017-09-28 18:11:05 +020087 LOG_W("File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %" PRId64,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020088 fname, (int64_t)st.st_size, (int64_t)hfuzz->maxFileSz);
Robert Swiecki47476f22017-09-28 15:45:02 +020089 }
90 if (st.st_size == 0U) {
91 LOG_W("File '%s' is empty", fname);
92 continue;
93 }
Robert Swiecki4e595fb2017-10-11 17:26:51 +020094 if ((size_t)st.st_size > maxSize) {
Robert Swiecki47476f22017-09-28 15:45:02 +020095 maxSize = st.st_size;
96 }
97 fileCnt++;
98 }
99
100 ATOMIC_SET(hfuzz->fileCnt, fileCnt);
101 if (hfuzz->maxFileSz == 0U) {
102 if (maxSize < 8192) {
103 hfuzz->maxFileSz = 8192;
104 } else {
105 hfuzz->maxFileSz = maxSize;
106 }
107 }
108 if (hfuzz->persistent && hfuzz->maxFileSz > (1024U * 128)) {
109 LOG_D("Persistent mode enabled, lowering maximum input size to 128KiB");
110 hfuzz->maxFileSz = 1024U * 128;
111 }
112
113 if (hfuzz->fileCnt == 0U) {
114 LOG_W("No usable files in the input directory '%s'", hfuzz->inputDir);
115 return false;
116 }
117
118 LOG_D("Re-read the '%s', maxFileSz:%zu, number of usable files:%zu", hfuzz->inputDir,
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200119 hfuzz->maxFileSz, hfuzz->fileCnt);
Robert Swiecki47476f22017-09-28 15:45:02 +0200120
121 rewinddir(hfuzz->inputDirP);
122
123 return true;
124}
125
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200126bool input_getNext(honggfuzz_t* hfuzz, char* fname, bool rewind)
Robert Swiecki47476f22017-09-28 15:45:02 +0200127{
128 static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER;
129 MX_SCOPED_LOCK(&input_mutex);
130
131 if (hfuzz->fileCnt == 0U) {
132 return false;
133 }
134
135 for (;;) {
136 errno = 0;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200137 struct dirent* entry = readdir(hfuzz->inputDirP);
Robert Swiecki47476f22017-09-28 15:45:02 +0200138 if (entry == NULL && errno == EINTR) {
139 continue;
140 }
141 if (entry == NULL && errno != 0) {
142 PLOG_W("readdir_r('%s')", hfuzz->inputDir);
143 return false;
144 }
145 if (entry == NULL && rewind == false) {
146 return false;
147 }
148 if (entry == NULL && rewind == true) {
149 if (input_getDirStatsAndRewind(hfuzz) == false) {
150 LOG_E("input_getDirStatsAndRewind('%s')", hfuzz->inputDir);
151 return false;
152 }
153 continue;
154 }
155
156 snprintf(fname, PATH_MAX, "%s/%s", hfuzz->inputDir, entry->d_name);
157
158 struct stat st;
159 if (stat(fname, &st) == -1) {
160 LOG_W("Couldn't stat() the '%s' file", fname);
161 continue;
162 }
163 if (!S_ISREG(st.st_mode)) {
164 LOG_D("'%s' is not a regular file, skipping", fname);
165 continue;
166 }
167 if (st.st_size == 0U) {
168 LOG_D("File '%s' is empty", fname);
169 continue;
170 }
171 return true;
172 }
173}
174
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200175bool input_init(honggfuzz_t* hfuzz)
Robert Swiecki47476f22017-09-28 15:45:02 +0200176{
177 hfuzz->fileCnt = 0U;
178
179 if (!hfuzz->inputDir) {
180 LOG_W("No input file/dir specified");
181 return false;
182 }
183
184 int dir_fd = open(hfuzz->inputDir, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
185 if (dir_fd == -1) {
186 PLOG_W("open('%s', O_DIRECTORY|O_RDONLY|O_CLOEXEC)", hfuzz->inputDir);
187 return false;
188 }
189 if ((hfuzz->inputDirP = fdopendir(dir_fd)) == NULL) {
190 close(dir_fd);
191 PLOG_W("opendir('%s')", hfuzz->inputDir);
192 return false;
193 }
194 if (input_getDirStatsAndRewind(hfuzz) == false) {
195 hfuzz->fileCnt = 0U;
196 LOG_W("input_getDirStatsAndRewind('%s')", hfuzz->inputDir);
197 return false;
198 }
199
200 return true;
201}
202
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200203bool input_parseDictionary(honggfuzz_t* hfuzz)
Robert Swiecki47476f22017-09-28 15:45:02 +0200204{
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200205 FILE* fDict = fopen(hfuzz->dictionaryFile, "rb");
Robert Swiecki47476f22017-09-28 15:45:02 +0200206 if (fDict == NULL) {
207 PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->dictionaryFile);
208 return false;
209 }
Robert Swiecki0b566112017-10-17 17:39:07 +0200210 defer { fclose(fDict); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200211
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200212 char* lineptr = NULL;
Robert Swiecki47476f22017-09-28 15:45:02 +0200213 size_t n = 0;
Robert Swiecki0b566112017-10-17 17:39:07 +0200214 defer { free(lineptr); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200215 for (;;) {
216 ssize_t len = getdelim(&lineptr, &n, '\n', fDict);
217 if (len == -1) {
218 break;
219 }
220 if (len > 1 && lineptr[len - 1] == '\n') {
221 lineptr[len - 1] = '\0';
222 len--;
223 }
224 if (lineptr[0] == '#') {
225 continue;
226 }
227 if (lineptr[0] == '\n') {
228 continue;
229 }
230 if (lineptr[0] == '\0') {
231 continue;
232 }
233 char bufn[1025] = { 0 };
234 char bufv[1025] = { 0 };
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200235 if (sscanf(lineptr, "\"%1024s", bufv) != 1
236 && sscanf(lineptr, "%1024[^=]=\"%1024s", bufn, bufv) != 2) {
Robert Swiecki47476f22017-09-28 15:45:02 +0200237 LOG_W("Incorrect dictionary entry: '%s'. Skipping", lineptr);
238 continue;
239 }
240
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200241 char* s = util_StrDup(bufv);
242 struct strings_t* str = (struct strings_t*)util_Malloc(sizeof(struct strings_t));
Robert Swiecki47476f22017-09-28 15:45:02 +0200243 str->len = util_decodeCString(s);
244 str->s = s;
245 hfuzz->dictionaryCnt += 1;
246 TAILQ_INSERT_TAIL(&hfuzz->dictq, str, pointers);
247
248 LOG_D("Dictionary: loaded word: '%s' (len=%zu)", str->s, str->len);
249 }
250 LOG_I("Loaded %zu words from the dictionary", hfuzz->dictionaryCnt);
251 return true;
252}
253
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200254bool input_parseBlacklist(honggfuzz_t* hfuzz)
Robert Swiecki47476f22017-09-28 15:45:02 +0200255{
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200256 FILE* fBl = fopen(hfuzz->blacklistFile, "rb");
Robert Swiecki47476f22017-09-28 15:45:02 +0200257 if (fBl == NULL) {
258 PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->blacklistFile);
259 return false;
260 }
Robert Swiecki0b566112017-10-17 17:39:07 +0200261 defer { fclose(fBl); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200262
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200263 char* lineptr = NULL;
Robert Swiecki47476f22017-09-28 15:45:02 +0200264 /* lineptr can be NULL, but it's fine for free() */
Robert Swiecki0b566112017-10-17 17:39:07 +0200265 defer { free(lineptr); };
Robert Swiecki47476f22017-09-28 15:45:02 +0200266 size_t n = 0;
267 for (;;) {
268 if (getline(&lineptr, &n, fBl) == -1) {
269 break;
270 }
271
Robert Swiecki0b566112017-10-17 17:39:07 +0200272 if ((hfuzz->blacklist = util_Realloc(
273 hfuzz->blacklist, (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0])))
Robert Swieckid0fa62c2017-09-28 18:11:05 +0200274 == NULL) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200275 PLOG_W(
276 "realloc failed (sz=%zu)", (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]));
Robert Swiecki47476f22017-09-28 15:45:02 +0200277 return false;
278 }
279
280 hfuzz->blacklist[hfuzz->blacklistCnt] = strtoull(lineptr, 0, 16);
281 LOG_D("Blacklist: loaded %'" PRIu64 "'", hfuzz->blacklist[hfuzz->blacklistCnt]);
282
283 // Verify entries are sorted so we can use interpolation search
284 if (hfuzz->blacklistCnt > 1) {
285 if (hfuzz->blacklist[hfuzz->blacklistCnt - 1] > hfuzz->blacklist[hfuzz->blacklistCnt]) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200286 LOG_F("Blacklist file not sorted. Use 'tools/createStackBlacklist.sh' to sort "
287 "records");
Robert Swiecki47476f22017-09-28 15:45:02 +0200288 return false;
289 }
290 }
291 hfuzz->blacklistCnt += 1;
292 }
293
294 if (hfuzz->blacklistCnt > 0) {
295 LOG_I("Loaded %zu stack hash(es) from the blacklist file", hfuzz->blacklistCnt);
296 } else {
297 LOG_F("Empty stack hashes blacklist file '%s'", hfuzz->blacklistFile);
298 }
299 return true;
300}