blob: b08cc08cefc2f838621cc3d29ac6c3f6f8030370 [file] [log] [blame]
robert.swiecki3bb518c2010-10-14 00:48:24 +00001/*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00002 *
robert.swiecki@gmail.com81189852015-02-14 23:44:55 +00003 * honggfuzz - file operations
4 * -----------------------------------------
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00005 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00006 * Author: Robert Swiecki <swiecki@google.com>
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00007 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00008 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00009 *
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
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000012 * a copy of the License at
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000013 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000014 * http://www.apache.org/licenses/LICENSE-2.0
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000015 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000016 * 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.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000021 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000022 */
robert.swiecki3bb518c2010-10-14 00:48:24 +000023
robert.swiecki3bb518c2010-10-14 00:48:24 +000024#include "common.h"
25#include "files.h"
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000026
27#include <dirent.h>
28#include <errno.h>
29#include <fcntl.h>
robert.swiecki@gmail.com86941cb2015-02-22 15:15:08 +000030#include <inttypes.h>
robert.swiecki@gmail.comba85c3e2015-02-02 14:55:16 +000031#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/mman.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include <unistd.h>
39
robert.swiecki3bb518c2010-10-14 00:48:24 +000040#include "log.h"
Robert Swiecki0fc5e942016-03-15 15:49:12 +010041#include "util.h"
robert.swiecki3bb518c2010-10-14 00:48:24 +000042
Robert Swieckidecf14b2016-03-31 15:09:28 +020043ssize_t files_readFileToBufMax(char *fileName, uint8_t * buf, size_t fileMaxSz)
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000044{
Robert Swieckia95854a2016-11-14 17:55:43 +010045 int fd = open(fileName, O_RDONLY | O_CLOEXEC);
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000046 if (fd == -1) {
Robert Swieckibc7532e2016-08-20 00:34:17 +020047 PLOG_W("Couldn't open '%s' for R/O", fileName);
Robert Swieckidecf14b2016-03-31 15:09:28 +020048 return -1;
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000049 }
Jagger4fe18692016-04-22 23:15:07 +020050 defer {
51 close(fd);
52 };
Robert Swieckia9db9dd2016-03-09 16:29:37 +010053
Robert Swieckidecf14b2016-03-31 15:09:28 +020054 ssize_t readSz = files_readFromFd(fd, buf, fileMaxSz);
55 if (readSz < 0) {
Robert Swieckibc7532e2016-08-20 00:34:17 +020056 LOG_W("Couldn't read '%s' to a buf", fileName);
Jagger1aa94d72016-04-02 02:37:35 +020057 return -1;
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000058 }
59
Jagger4d109852016-02-04 02:28:44 +010060 LOG_D("Read '%zu' bytes from '%s'", readSz, fileName);
Jagger4d109852016-02-04 02:28:44 +010061 return readSz;
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000062}
63
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000064bool files_writeBufToFile(char *fileName, uint8_t * buf, size_t fileSz, int flags)
65{
66 int fd = open(fileName, flags, 0644);
67 if (fd == -1) {
Robert Swiecki731f2952017-01-30 23:30:22 +010068 PLOG_W("Couldn't open '%s' for R/W", fileName);
robert.swiecki@gmail.com276f9f12015-03-01 01:39:47 +000069 return false;
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000070 }
Jagger4fe18692016-04-22 23:15:07 +020071 defer {
72 close(fd);
73 };
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000074
75 if (files_writeToFd(fd, buf, fileSz) == false) {
Robert Swieckibc7532e2016-08-20 00:34:17 +020076 PLOG_W("Couldn't write '%zu' bytes to file '%s' (fd='%d')", fileSz, fileName, fd);
robert.swiecki@gmail.com9be63de2015-03-02 07:08:45 +000077 unlink(fileName);
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000078 return false;
79 }
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000080
Robert Swieckic8c32db2015-10-09 18:06:22 +020081 LOG_D("Written '%zu' bytes to '%s'", fileSz, fileName);
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000082 return true;
83}
84
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000085bool files_writeToFd(int fd, uint8_t * buf, size_t fileSz)
robert.swiecki3bb518c2010-10-14 00:48:24 +000086{
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000087 size_t writtenSz = 0;
88 while (writtenSz < fileSz) {
89 ssize_t sz = write(fd, &buf[writtenSz], fileSz - writtenSz);
robert.swiecki3bb518c2010-10-14 00:48:24 +000090 if (sz < 0 && errno == EINTR)
91 continue;
92
93 if (sz < 0)
94 return false;
95
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000096 writtenSz += sz;
robert.swiecki3bb518c2010-10-14 00:48:24 +000097 }
robert.swiecki3bb518c2010-10-14 00:48:24 +000098 return true;
99}
100
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +0000101bool files_writeStrToFd(int fd, char *str)
102{
103 return files_writeToFd(fd, (uint8_t *) str, strlen(str));
104}
105
Robert Swieckidecf14b2016-03-31 15:09:28 +0200106ssize_t files_readFromFd(int fd, uint8_t * buf, size_t fileSz)
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +0000107{
108 size_t readSz = 0;
109 while (readSz < fileSz) {
110 ssize_t sz = read(fd, &buf[readSz], fileSz - readSz);
111 if (sz < 0 && errno == EINTR)
112 continue;
113
Robert Swieckidecf14b2016-03-31 15:09:28 +0200114 if (sz == 0)
Jagger4d109852016-02-04 02:28:44 +0100115 break;
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +0000116
Robert Swieckidecf14b2016-03-31 15:09:28 +0200117 if (sz < 0)
118 return -1;
119
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +0000120 readSz += sz;
121 }
Robert Swieckidecf14b2016-03-31 15:09:28 +0200122 return (ssize_t) readSz;
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +0000123}
124
groebert@google.com1bd4c212013-06-19 11:13:56 +0000125bool files_exists(char *fileName)
126{
127 return (access(fileName, F_OK) != -1);
128}
129
robert.swiecki3bb518c2010-10-14 00:48:24 +0000130bool files_writePatternToFd(int fd, off_t size, unsigned char p)
131{
132 void *buf = malloc(size);
133 if (!buf) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200134 PLOG_W("Couldn't allocate memory");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000135 return false;
136 }
Jagger4fe18692016-04-22 23:15:07 +0200137 defer {
138 free(buf);
139 };
robert.swiecki3bb518c2010-10-14 00:48:24 +0000140
141 memset(buf, p, (size_t) size);
142 int ret = files_writeToFd(fd, buf, size);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000143
144 return ret;
145}
146
robert.swiecki3bb518c2010-10-14 00:48:24 +0000147static bool files_readdir(honggfuzz_t * hfuzz)
148{
Jagger1b2d4822016-09-25 16:19:45 +0200149 DIR *dir = opendir(hfuzz->inputDir);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000150 if (!dir) {
Jagger1b2d4822016-09-25 16:19:45 +0200151 PLOG_W("Couldn't open dir '%s'", hfuzz->inputDir);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000152 return false;
153 }
Jagger4fe18692016-04-22 23:15:07 +0200154 defer {
155 closedir(dir);
156 };
robert.swiecki3bb518c2010-10-14 00:48:24 +0000157
Jaggerf4a60562016-09-25 15:40:23 +0200158 size_t maxSize = 0UL;
159 unsigned count = 0;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000160 for (;;) {
Jaggerad076932016-08-24 02:40:19 +0200161 errno = 0;
Jaggerf2723e12016-08-23 23:47:19 +0200162 struct dirent *res = readdir(dir);
163 if (res == NULL && errno != 0) {
Jagger1b2d4822016-09-25 16:19:45 +0200164 PLOG_W("Couldn't read the '%s' dir", hfuzz->inputDir);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000165 return false;
166 }
167
Jaggerf4a60562016-09-25 15:40:23 +0200168 if (res == NULL) {
169 break;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000170 }
171
172 char path[PATH_MAX];
Jagger1b2d4822016-09-25 16:19:45 +0200173 snprintf(path, sizeof(path), "%s/%s", hfuzz->inputDir, res->d_name);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000174 struct stat st;
175 if (stat(path, &st) == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200176 LOG_W("Couldn't stat() the '%s' file", path);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000177 continue;
178 }
179
180 if (!S_ISREG(st.st_mode)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200181 LOG_D("'%s' is not a regular file, skipping", path);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000182 continue;
183 }
184
robert.swiecki@gmail.comc1b759b2015-03-01 18:41:15 +0000185 if (st.st_size == 0ULL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200186 LOG_D("'%s' is empty", path);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000187 continue;
188 }
189
Jaggerf4a60562016-09-25 15:40:23 +0200190 if (hfuzz->maxFileSz != 0UL && st.st_size > (off_t) hfuzz->maxFileSz) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200191 LOG_W("File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %"
192 PRId64, path, (int64_t) st.st_size, (int64_t) hfuzz->maxFileSz);
robert.swiecki@gmail.com86941cb2015-02-22 15:15:08 +0000193 continue;
194 }
195
Jaggerf4a60562016-09-25 15:40:23 +0200196 if ((size_t) st.st_size > maxSize) {
197 maxSize = st.st_size;
198 }
Robert Swieckie8f8e8d2016-10-03 23:51:32 +0200199
200 struct paths_t *file = (struct paths_t *)util_Malloc(sizeof(struct paths_t));
201 snprintf(file->path, sizeof(file->path), "%s", path);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000202 hfuzz->fileCnt = ++count;
Robert Swieckie8f8e8d2016-10-03 23:51:32 +0200203 TAILQ_INSERT_TAIL(&hfuzz->fileq, file, pointers);
204
Robert Swieckic8c32db2015-10-09 18:06:22 +0200205 LOG_D("Added '%s' to the list of input files", path);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000206 }
207
Jaggerf4a60562016-09-25 15:40:23 +0200208 if (count == 0) {
Jagger1b2d4822016-09-25 16:19:45 +0200209 LOG_W("Directory '%s' doesn't contain any regular files", hfuzz->inputDir);
Jaggerf4a60562016-09-25 15:40:23 +0200210 return false;
211 }
212
213 if (hfuzz->maxFileSz == 0UL) {
Robert Swieckia81f3172016-11-22 21:31:40 +0100214 if (maxSize < 128U) {
215 hfuzz->maxFileSz = 128U;
216 } else {
217 hfuzz->maxFileSz = maxSize;
218 }
Jaggerf4a60562016-09-25 15:40:23 +0200219 }
220 LOG_I("%zu input files have been added to the list. Max file size: %zu", hfuzz->fileCnt,
221 hfuzz->maxFileSz);
222 return true;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000223}
224
225bool files_init(honggfuzz_t * hfuzz)
226{
Jaggera34b3022016-04-02 02:20:40 +0200227 if (hfuzz->externalCommand) {
Robert Swieckie8f8e8d2016-10-03 23:51:32 +0200228 struct paths_t *file = (struct paths_t *)util_Malloc(sizeof(struct paths_t));
229 snprintf(file->path, sizeof(file->path), "NONE");
230 hfuzz->fileCnt = 1;
231 TAILQ_INSERT_TAIL(&hfuzz->fileq, file, pointers);
232
Robert Swieckic8c32db2015-10-09 18:06:22 +0200233 LOG_I
Jaggera34b3022016-04-02 02:20:40 +0200234 ("No input file corpus loaded, the external command '%s' is responsible for creating the fuzz files",
Robert Swieckic8c32db2015-10-09 18:06:22 +0200235 hfuzz->externalCommand);
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000236 return true;
237 }
238
Jagger1b2d4822016-09-25 16:19:45 +0200239 if (!hfuzz->inputDir) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200240 LOG_W("No input file/dir specified");
robert.swiecki3bb518c2010-10-14 00:48:24 +0000241 return false;
242 }
243
244 struct stat st;
Jagger1b2d4822016-09-25 16:19:45 +0200245 if (stat(hfuzz->inputDir, &st) == -1) {
246 PLOG_W("Couldn't stat the input dir '%s'", hfuzz->inputDir);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000247 return false;
248 }
249
Robert Swieckie8f8e8d2016-10-03 23:51:32 +0200250 if (!S_ISDIR(st.st_mode)) {
251 LOG_W("The initial corpus directory '%s' is not a directory", hfuzz->inputDir);
252 return false;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000253 }
254
Robert Swieckie8f8e8d2016-10-03 23:51:32 +0200255 return files_readdir(hfuzz);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000256}
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000257
Robert Swieckidecf14b2016-03-31 15:09:28 +0200258const char *files_basename(char *path)
groebert@google.com1bd4c212013-06-19 11:13:56 +0000259{
Robert Swieckidecf14b2016-03-31 15:09:28 +0200260 const char *base = strrchr(path, '/');
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000261 return base ? base + 1 : path;
262}
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000263
264bool files_parseDictionary(honggfuzz_t * hfuzz)
265{
266 FILE *fDict = fopen(hfuzz->dictionaryFile, "rb");
267 if (fDict == NULL) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200268 PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->dictionaryFile);
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000269 return false;
270 }
Jagger4fe18692016-04-22 23:15:07 +0200271 defer {
272 fclose(fDict);
273 };
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000274
robert.swiecki@gmail.com0440c532015-04-21 17:27:08 +0000275 for (;;) {
Robert Swieckicaf9d762016-03-10 16:13:18 +0100276 char *lineptr = NULL;
277 size_t n = 0;
Jaggerc64c9eb2016-09-22 04:04:34 +0200278 ssize_t len = getdelim(&lineptr, &n, '\n', fDict);
279 if (len == -1) {
robert.swiecki@gmail.com0440c532015-04-21 17:27:08 +0000280 break;
281 }
Jaggerc64c9eb2016-09-22 04:04:34 +0200282 if (n > 1 && lineptr[len - 1] == '\n') {
Robert Swieckidfef8542016-09-13 18:06:46 +0200283 lineptr[len - 1] = '\0';
Jaggerc64c9eb2016-09-22 04:04:34 +0200284 len--;
Robert Swieckidfef8542016-09-13 18:06:46 +0200285 }
Robert Swiecki531438a2016-09-13 19:05:11 +0200286
287 struct strings_t *str = (struct strings_t *)util_Malloc(sizeof(struct strings_t));
Jaggerd619ed12016-09-22 04:08:49 +0200288 str->len = util_decodeCString(lineptr);
289 str->s = lineptr;
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000290 hfuzz->dictionaryCnt += 1;
Robert Swiecki3a572262016-10-04 01:48:34 +0200291 TAILQ_INSERT_TAIL(&hfuzz->dictq, str, pointers);
Robert Swiecki531438a2016-09-13 19:05:11 +0200292
Jaggerc64c9eb2016-09-22 04:04:34 +0200293 LOG_D("Dictionary: loaded word: '%s' (len=%zu)", str->s, str->len);
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000294 }
Robert Swieckic8c32db2015-10-09 18:06:22 +0200295 LOG_I("Loaded %zu words from the dictionary", hfuzz->dictionaryCnt);
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000296 return true;
297}
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300298
299/*
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300300 * dstExists argument can be used by caller for cases where existing destination
301 * file requires special handling (e.g. save unique crashes)
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300302 */
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300303bool files_copyFile(const char *source, const char *destination, bool * dstExists)
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300304{
Anestis Bechtsoudis38773212015-09-08 23:34:28 +0300305 if (dstExists)
306 *dstExists = false;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300307 if (link(source, destination) == 0) {
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300308 return true;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300309 } else {
310 if (errno == EEXIST) {
311 // Should kick-in before MAC, so avoid the hassle
Anestis Bechtsoudis38773212015-09-08 23:34:28 +0300312 if (dstExists)
313 *dstExists = true;
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300314 return false;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300315 } else {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200316 PLOG_D("Couldn't link '%s' as '%s'", source, destination);
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300317 /*
318 * Don't fail yet as we might have a running env which doesn't allow
319 * hardlinks (e.g. SELinux)
320 */
321 }
322 }
323
324 // Now try with a verbose POSIX alternative
325 int inFD, outFD, dstOpenFlags;
326 mode_t dstFilePerms;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300327
328 // O_EXCL is important for saving unique crashes
Robert Swieckia95854a2016-11-14 17:55:43 +0100329 dstOpenFlags = O_CREAT | O_WRONLY | O_EXCL | O_CLOEXEC;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300330 dstFilePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
331
Robert Swieckia95854a2016-11-14 17:55:43 +0100332 inFD = open(source, O_RDONLY | O_CLOEXEC);
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300333 if (inFD == -1) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200334 PLOG_D("Couldn't open '%s' source", source);
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300335 return false;
336 }
Jagger4fe18692016-04-22 23:15:07 +0200337 defer {
338 close(inFD);
339 };
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300340
341 struct stat inSt;
342 if (fstat(inFD, &inSt) == -1) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200343 PLOG_W("Couldn't fstat(fd='%d' fileName='%s')", inFD, source);
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300344 return false;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300345 }
346
347 outFD = open(destination, dstOpenFlags, dstFilePerms);
348 if (outFD == -1) {
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300349 if (errno == EEXIST) {
Anestis Bechtsoudis38773212015-09-08 23:34:28 +0300350 if (dstExists)
351 *dstExists = true;
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300352 }
Robert Swieckic8c32db2015-10-09 18:06:22 +0200353 PLOG_D("Couldn't open '%s' destination", destination);
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300354 return false;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300355 }
Jagger4fe18692016-04-22 23:15:07 +0200356 defer {
357 close(outFD);
358 };
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300359
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300360 uint8_t *inFileBuf = malloc(inSt.st_size);
361 if (!inFileBuf) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200362 PLOG_W("malloc(%zu) failed", (size_t) inSt.st_size);
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300363 return false;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300364 }
Jagger4fe18692016-04-22 23:15:07 +0200365 defer {
366 free(inFileBuf);
367 };
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300368
Robert Swieckidecf14b2016-03-31 15:09:28 +0200369 ssize_t readSz = files_readFromFd(inFD, inFileBuf, (size_t) inSt.st_size);
370 if (readSz < 0) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200371 PLOG_W("Couldn't read '%s' to a buf", source);
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300372 return false;
373 }
374
Jagger4d109852016-02-04 02:28:44 +0100375 if (files_writeToFd(outFD, inFileBuf, readSz) == false) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200376 PLOG_W("Couldn't write '%zu' bytes to file '%s' (fd='%d')", (size_t) readSz,
Robert Swieckic8c32db2015-10-09 18:06:22 +0200377 destination, outFD);
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300378 unlink(destination);
379 return false;
380 }
381
Anestis Bechtsoudis1ae1ce12015-09-06 23:43:48 +0300382 return true;
Anestis Bechtsoudis7d42f9d2015-09-06 14:30:20 +0300383}
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300384
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300385bool files_parseBlacklist(honggfuzz_t * hfuzz)
386{
387 FILE *fBl = fopen(hfuzz->blacklistFile, "rb");
388 if (fBl == NULL) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200389 PLOG_W("Couldn't open '%s' - R/O mode", hfuzz->blacklistFile);
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300390 return false;
391 }
Jagger4fe18692016-04-22 23:15:07 +0200392 defer {
393 fclose(fBl);
394 };
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300395
Anestis Bechtsoudis3a8e16f2016-01-10 15:06:09 +0200396 char *lineptr = NULL;
Jagger1dad1822016-03-29 23:56:14 +0200397 /* lineptr can be NULL, but it's fine for free() */
Jagger4fe18692016-04-22 23:15:07 +0200398 defer {
399 free(lineptr);
400 };
Anestis Bechtsoudis3a8e16f2016-01-10 15:06:09 +0200401 size_t n = 0;
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300402 for (;;) {
Anestis Bechtsoudis7d6185c2015-09-21 15:59:56 +0300403 if (getline(&lineptr, &n, fBl) == -1) {
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300404 break;
405 }
Anestis Bechtsoudis99db8742015-09-23 11:37:26 +0300406
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300407 if ((hfuzz->blacklist =
Jaggerf49962d2016-07-21 22:49:54 +0200408 util_Realloc(hfuzz->blacklist,
409 (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]))) == NULL) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200410 PLOG_W("realloc failed (sz=%zu)",
Robert Swieckic8c32db2015-10-09 18:06:22 +0200411 (hfuzz->blacklistCnt + 1) * sizeof(hfuzz->blacklist[0]));
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300412 return false;
413 }
Anestis Bechtsoudis99db8742015-09-23 11:37:26 +0300414
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300415 hfuzz->blacklist[hfuzz->blacklistCnt] = strtoull(lineptr, 0, 16);
Anestis Bechtsoudis07e14ce2015-12-30 14:15:42 +0200416 LOG_D("Blacklist: loaded %'" PRIu64 "'", hfuzz->blacklist[hfuzz->blacklistCnt]);
Anestis Bechtsoudis99db8742015-09-23 11:37:26 +0300417
418 // Verify entries are sorted so we can use interpolation search
419 if (hfuzz->blacklistCnt > 1) {
420 if (hfuzz->blacklist[hfuzz->blacklistCnt - 1] > hfuzz->blacklist[hfuzz->blacklistCnt]) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200421 LOG_F
422 ("Blacklist file not sorted. Use 'tools/createStackBlacklist.sh' to sort records");
Anestis Bechtsoudis99db8742015-09-23 11:37:26 +0300423 return false;
424 }
425 }
Anestis Bechtsoudis612baa52015-09-23 18:21:43 +0300426 hfuzz->blacklistCnt += 1;
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300427 }
Anestis Bechtsoudis99db8742015-09-23 11:37:26 +0300428
Anestis Bechtsoudisebf879e2015-09-27 18:11:25 +0300429 if (hfuzz->blacklistCnt > 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200430 LOG_I("Loaded %zu stack hash(es) from the blacklist file", hfuzz->blacklistCnt);
Anestis Bechtsoudis99db8742015-09-23 11:37:26 +0300431 } else {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200432 LOG_F("Empty stack hashes blacklist file '%s'", hfuzz->blacklistFile);
Anestis Bechtsoudis99db8742015-09-23 11:37:26 +0300433 }
Anestis Bechtsoudisd59af692015-09-21 15:15:05 +0300434 return true;
435}
Anestis Bechtsoudisee5316d2015-09-27 19:11:48 +0300436
Anestis Bechtsoudis3dce6ac2016-10-31 08:51:14 +0200437/*
438 * Reads symbols from src file (one per line) and append them to filterList. The
439 * total number of added symbols is returned.
440 *
441 * Simple wildcard strings are also supported (e.g. mem*)
442 */
443size_t files_parseSymbolFilter(const char *srcFile, char ***filterList)
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300444{
Anestis Bechtsoudis3dce6ac2016-10-31 08:51:14 +0200445 FILE *f = fopen(srcFile, "rb");
446 if (f == NULL) {
447 PLOG_W("Couldn't open '%s' - R/O mode", srcFile);
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300448 return 0;
449 }
450 defer {
Anestis Bechtsoudis3dce6ac2016-10-31 08:51:14 +0200451 fclose(f);
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300452 };
453
454 char *lineptr = NULL;
455 defer {
456 free(lineptr);
457 };
458
459 size_t symbolsRead = 0, n = 0;
460 for (;;) {
Anestis Bechtsoudis3dce6ac2016-10-31 08:51:14 +0200461 if (getline(&lineptr, &n, f) == -1) {
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300462 break;
463 }
464
465 if (strlen(lineptr) < 3) {
466 LOG_F("Input symbol '%s' too short (strlen < 3)", lineptr);
467 return 0;
468 }
469
470 if ((*filterList =
Anestis Bechtsoudis710c8562016-10-31 09:24:49 +0200471 (char **)util_Realloc(*filterList,
472 (symbolsRead + 1) * sizeof((*filterList)[0]))) == NULL) {
473 PLOG_W("realloc failed (sz=%zu)", (symbolsRead + 1) * sizeof((*filterList)[0]));
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300474 return 0;
475 }
Anestis Bechtsoudis710c8562016-10-31 09:24:49 +0200476 (*filterList)[symbolsRead] = malloc(strlen(lineptr));
477 if (!(*filterList)[symbolsRead]) {
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300478 PLOG_E("malloc(%zu) failed", strlen(lineptr));
479 return 0;
480 }
Anestis Bechtsoudis710c8562016-10-31 09:24:49 +0200481 strncpy((*filterList)[symbolsRead], lineptr, strlen(lineptr));
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300482 symbolsRead++;
483 }
484
485 LOG_I("%zu filter symbols added to list", symbolsRead);
486 return symbolsRead;
487}
488
Anestis Bechtsoudisecb0a662015-09-27 18:19:46 +0300489uint8_t *files_mapFile(char *fileName, off_t * fileSz, int *fd, bool isWritable)
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300490{
491 int mmapProt = PROT_READ;
492 if (isWritable) {
493 mmapProt |= PROT_WRITE;
494 }
495
496 if ((*fd = open(fileName, O_RDONLY)) == -1) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200497 PLOG_W("Couldn't open() '%s' file in R/O mode", fileName);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300498 return NULL;
499 }
500
501 struct stat st;
502 if (fstat(*fd, &st) == -1) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200503 PLOG_W("Couldn't stat() the '%s' file", fileName);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300504 close(*fd);
505 return NULL;
506 }
507
508 uint8_t *buf;
509 if ((buf = mmap(NULL, st.st_size, mmapProt, MAP_PRIVATE, *fd, 0)) == MAP_FAILED) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200510 PLOG_W("Couldn't mmap() the '%s' file", fileName);
Anestis Bechtsoudis5c86ebc2015-09-27 18:06:43 +0300511 close(*fd);
512 return NULL;
513 }
514
515 *fileSz = st.st_size;
516 return buf;
517}
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200518
Jagger41e7ffc2016-07-23 03:50:32 +0200519uint8_t *files_mapFileShared(char *fileName, off_t * fileSz, int *fd)
520{
521 if ((*fd = open(fileName, O_RDONLY)) == -1) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200522 PLOG_W("Couldn't open() '%s' file in R/O mode", fileName);
Jagger41e7ffc2016-07-23 03:50:32 +0200523 return NULL;
524 }
525
526 struct stat st;
527 if (fstat(*fd, &st) == -1) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200528 PLOG_W("Couldn't stat() the '%s' file", fileName);
Jagger41e7ffc2016-07-23 03:50:32 +0200529 close(*fd);
530 return NULL;
531 }
532
533 uint8_t *buf;
534 if ((buf = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, *fd, 0)) == MAP_FAILED) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200535 PLOG_W("Couldn't mmap() the '%s' file", fileName);
Jagger41e7ffc2016-07-23 03:50:32 +0200536 close(*fd);
537 return NULL;
538 }
539
540 *fileSz = st.st_size;
541 return buf;
542}
543
Jagger5b81a502016-09-07 20:48:32 +0200544void *files_mapSharedMem(size_t sz, int *fd, const char *dir)
Jagger08a7e272016-08-28 17:25:41 +0200545{
Jagger5b81a502016-09-07 20:48:32 +0200546 char template[PATH_MAX];
547 snprintf(template, sizeof(template), "%s/hfuzz.XXXXXX", dir);
Jagger08a7e272016-08-28 17:25:41 +0200548 if ((*fd = mkstemp(template)) == -1) {
549 PLOG_W("mkstemp('%s')", template);
550 return MAP_FAILED;
551 }
552 unlink(template);
553 if (ftruncate(*fd, sz) == -1) {
554 PLOG_W("ftruncate(%d, %zu)", *fd, sz);
555 close(*fd);
Robert Swiecki19fa37a2016-10-27 19:20:13 +0200556 *fd = -1;
Jagger08a7e272016-08-28 17:25:41 +0200557 return MAP_FAILED;
558 }
559 void *ret = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
560 if (ret == MAP_FAILED) {
561 PLOG_W("mmap(sz=%zu, fd=%d)", sz, *fd);
Robert Swiecki19fa37a2016-10-27 19:20:13 +0200562 *fd = -1;
Jagger08a7e272016-08-28 17:25:41 +0200563 close(*fd);
564 return MAP_FAILED;
565 }
566 return ret;
567}
568
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200569bool files_readPidFromFile(const char *fileName, pid_t * pidPtr)
570{
Jaggerff2d20c2016-09-10 03:38:58 +0200571 FILE *fPID = fopen(fileName, "rbe");
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200572 if (fPID == NULL) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200573 PLOG_W("Couldn't open '%s' - R/O mode", fileName);
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200574 return false;
575 }
Jagger4fe18692016-04-22 23:15:07 +0200576 defer {
577 fclose(fPID);
578 };
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200579
580 char *lineptr = NULL;
581 size_t lineSz = 0;
Jaggerebaf01e2016-05-15 15:13:34 +0200582 defer {
583 free(lineptr);
584 };
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200585 if (getline(&lineptr, &lineSz, fPID) == -1) {
586 if (lineSz == 0) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200587 LOG_W("Empty PID file (%s)", fileName);
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100588 return false;
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200589 }
590 }
591
592 *pidPtr = atoi(lineptr);
593 if (*pidPtr < 1) {
Robert Swieckibc7532e2016-08-20 00:34:17 +0200594 LOG_W("Invalid PID read from '%s' file", fileName);
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100595 return false;
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200596 }
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200597
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100598 return true;
Anestis Bechtsoudis413cb132016-02-07 12:59:00 +0200599}
Robert Swieckie8f8e8d2016-10-03 23:51:32 +0200600
601struct paths_t *files_getFileFromFileq(honggfuzz_t * hfuzz, size_t index)
602{
603 if (index >= hfuzz->fileCnt) {
604 LOG_F("File index: %zu >= fileCnt: %zu", index, hfuzz->fileCnt);
605 }
606
607 struct paths_t *file;
608 size_t i = 0;
609 TAILQ_FOREACH(file, &hfuzz->fileq, pointers) {
610 if (i++ == index) {
611 return file;
612 }
613 }
614
615 LOG_F("File index: %zu bigger than fileq size", index);
616 return NULL;
617}