blob: 8c653ddb1cc9d207c7167acf6bc99d942c671e3a [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"
41
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000042size_t files_readFileToBufMax(char *fileName, uint8_t * buf, size_t fileMaxSz)
43{
44 int fd = open(fileName, O_RDONLY);
45 if (fd == -1) {
46 LOGMSG_P(l_ERROR, "Couldn't open '%s' for R/O", fileName);
47 return 0UL;
48 }
49
50 struct stat st;
51 if (fstat(fd, &st) == -1) {
52 LOGMSG_P(l_ERROR, "Couldn't fstat(fd='%d' fileName='%s')", fd, fileName);
53 close(fd);
54 return 0UL;
55 }
56
robert.swiecki@gmail.comc1b759b2015-03-01 18:41:15 +000057 if (st.st_size > (off_t) fileMaxSz) {
58 LOGMSG(l_ERROR, "File '%s' size to big (%zu > %" PRId64 ")", fileName, (int64_t) st.st_size,
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000059 fileMaxSz);
60 close(fd);
61 return 0UL;
62 }
63
64 if (files_readFromFd(fd, buf, (size_t) st.st_size) == false) {
65 LOGMSG(l_ERROR, "Couldn't read '%s' to a buf", fileName);
66 close(fd);
67 return 0UL;
68 }
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000069 close(fd);
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000070
robert.swiecki@gmail.com276f9f12015-03-01 01:39:47 +000071 LOGMSG(l_DEBUG, "Read '%zu' bytes (max: '%zu') from '%s'", (size_t) st.st_size, fileMaxSz,
72 fileName);
73
robert.swiecki@gmail.com4a7a9d82015-03-01 01:25:16 +000074 return (size_t) st.st_size;
75}
76
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000077bool files_writeBufToFile(char *fileName, uint8_t * buf, size_t fileSz, int flags)
78{
79 int fd = open(fileName, flags, 0644);
80 if (fd == -1) {
81 LOGMSG_P(l_ERROR, "Couldn't open '%s' for R/O", fileName);
robert.swiecki@gmail.com276f9f12015-03-01 01:39:47 +000082 return false;
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000083 }
84
85 if (files_writeToFd(fd, buf, fileSz) == false) {
robert.swiecki@gmail.com276f9f12015-03-01 01:39:47 +000086 LOGMSG(l_ERROR, "Couldn't write '%zu' bytes to file '%s' (fd='%d')", fileSz, fileName, fd);
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000087 close(fd);
robert.swiecki@gmail.com9be63de2015-03-02 07:08:45 +000088 unlink(fileName);
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000089 return false;
90 }
91 close(fd);
92
robert.swiecki@gmail.com276f9f12015-03-01 01:39:47 +000093 LOGMSG(l_DEBUG, "Written '%zu' bytes to '%s'", fileSz, fileName);
94
robert.swiecki@gmail.comdc8403e2015-03-01 01:33:00 +000095 return true;
96}
97
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000098bool files_writeToFd(int fd, uint8_t * buf, size_t fileSz)
robert.swiecki3bb518c2010-10-14 00:48:24 +000099{
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +0000100 size_t writtenSz = 0;
101 while (writtenSz < fileSz) {
102 ssize_t sz = write(fd, &buf[writtenSz], fileSz - writtenSz);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000103 if (sz < 0 && errno == EINTR)
104 continue;
105
106 if (sz < 0)
107 return false;
108
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +0000109 writtenSz += sz;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000110 }
robert.swiecki3bb518c2010-10-14 00:48:24 +0000111 return true;
112}
113
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +0000114bool files_writeStrToFd(int fd, char *str)
115{
116 return files_writeToFd(fd, (uint8_t *) str, strlen(str));
117}
118
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +0000119bool files_readFromFd(int fd, uint8_t * buf, size_t fileSz)
120{
121 size_t readSz = 0;
122 while (readSz < fileSz) {
123 ssize_t sz = read(fd, &buf[readSz], fileSz - readSz);
124 if (sz < 0 && errno == EINTR)
125 continue;
126
127 if (sz < 0)
128 return false;
129
130 readSz += sz;
131 }
132 return true;
133}
134
groebert@google.com1bd4c212013-06-19 11:13:56 +0000135bool files_exists(char *fileName)
136{
137 return (access(fileName, F_OK) != -1);
138}
139
robert.swiecki3bb518c2010-10-14 00:48:24 +0000140bool files_writePatternToFd(int fd, off_t size, unsigned char p)
141{
142 void *buf = malloc(size);
143 if (!buf) {
144 LOGMSG_P(l_WARN, "Couldn't allocate memory");
145 return false;
146 }
147
148 memset(buf, p, (size_t) size);
149 int ret = files_writeToFd(fd, buf, size);
150 free(buf);
151
152 return ret;
153}
154
robert.swiecki3bb518c2010-10-14 00:48:24 +0000155static bool files_readdir(honggfuzz_t * hfuzz)
156{
157 DIR *dir = opendir(hfuzz->inputFile);
158 if (!dir) {
159 LOGMSG_P(l_ERROR, "Couldn't open dir '%s'", hfuzz->inputFile);
160 return false;
161 }
162
163 int count = 0;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000164 for (;;) {
165 struct dirent de, *res;
166 if (readdir_r(dir, &de, &res) > 0) {
167 LOGMSG_P(l_ERROR, "Couldn't read the '%s' dir", hfuzz->inputFile);
168 closedir(dir);
169 return false;
170 }
171
172 if (res == NULL && count > 0) {
173 LOGMSG(l_INFO, "%d input files have been added to the list", hfuzz->fileCnt);
174 closedir(dir);
175 return true;
176 }
177
178 if (res == NULL && count == 0) {
179 LOGMSG(l_ERROR, "Directory '%s' doesn't contain any regular files", hfuzz->inputFile);
180 closedir(dir);
181 return false;
182 }
183
184 char path[PATH_MAX];
185 snprintf(path, sizeof(path), "%s/%s", hfuzz->inputFile, res->d_name);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000186 struct stat st;
187 if (stat(path, &st) == -1) {
188 LOGMSG(l_WARN, "Couldn't stat() the '%s' file", path);
189 continue;
190 }
191
192 if (!S_ISREG(st.st_mode)) {
193 LOGMSG(l_DEBUG, "'%s' is not a regular file, skipping", path);
194 continue;
195 }
196
robert.swiecki@gmail.comc1b759b2015-03-01 18:41:15 +0000197 if (st.st_size == 0ULL) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000198 LOGMSG(l_DEBUG, "'%s' is empty", path);
199 continue;
200 }
201
robert.swiecki@gmail.com86941cb2015-02-22 15:15:08 +0000202 if (st.st_size > (off_t) hfuzz->maxFileSz) {
203 LOGMSG(l_WARN,
204 "File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %"
205 PRId64, path, (int64_t) st.st_size, (int64_t) hfuzz->maxFileSz);
206 continue;
207 }
208
robert.swiecki3bb518c2010-10-14 00:48:24 +0000209 if (!(hfuzz->files = realloc(hfuzz->files, sizeof(char *) * (count + 1)))) {
210 LOGMSG_P(l_ERROR, "Couldn't allocate memory");
211 closedir(dir);
212 return false;
213 }
214
215 hfuzz->files[count] = strdup(path);
216 if (!hfuzz->files[count]) {
217 LOGMSG_P(l_ERROR, "Couldn't allocate memory");
218 closedir(dir);
219 return false;
220 }
221 hfuzz->fileCnt = ++count;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000222 LOGMSG(l_DEBUG, "Added '%s' to the list of input files", path);
223 }
224
225 abort(); /* NOTREACHED */
226 return false;
227}
228
229bool files_init(honggfuzz_t * hfuzz)
230{
robert.swiecki@gmail.comea1be292014-07-21 17:36:50 +0000231 hfuzz->files = malloc(sizeof(char *));
robert.swiecki@gmail.comcac22fd2015-02-19 14:03:28 +0000232 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE && !hfuzz->inputFile) {
robert.swiecki@gmail.comcfff7592015-02-18 00:06:19 +0000233 hfuzz->fileCnt = 1;
robert.swiecki@gmail.comcac22fd2015-02-19 14:03:28 +0000234 hfuzz->files[0] = "DYNAMIC_FILE";
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000235 return true;
236 }
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000237 if (hfuzz->externalCommand && !hfuzz->inputFile) {
robert.swiecki@gmail.comc6deb6f2014-06-03 18:17:55 +0000238 hfuzz->fileCnt = 1;
robert.swiecki@gmail.com73df4252015-02-18 00:09:48 +0000239 hfuzz->files[0] = "CREATED";
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000240 LOGMSG(l_INFO,
241 "No input file corpus specified, the external command '%s' is responsible for creating the fuzz files",
242 hfuzz->externalCommand);
243 return true;
244 }
245
robert.swiecki3bb518c2010-10-14 00:48:24 +0000246 if (!hfuzz->files) {
247 LOGMSG_P(l_ERROR, "Couldn't allocate memory");
248 return false;
249 }
250
251 if (!hfuzz->inputFile) {
252 LOGMSG(l_ERROR, "No input file/dir specified");
253 return false;
254 }
255
256 struct stat st;
257 if (stat(hfuzz->inputFile, &st) == -1) {
258 LOGMSG_P(l_ERROR, "Couldn't stat the input file/dir '%s'", hfuzz->inputFile);
259 return false;
260 }
261
262 if (S_ISDIR(st.st_mode)) {
263 return files_readdir(hfuzz);
264 }
265
266 if (!S_ISREG(st.st_mode)) {
267 LOGMSG(l_ERROR, "'%s' is not a regular file, nor a directory", hfuzz->inputFile);
268 return false;
269 }
270
robert.swiecki@gmail.com2e0103f2015-03-30 01:38:12 +0000271 if (st.st_size > (off_t) hfuzz->maxFileSz) {
272 LOGMSG(l_ERROR,
273 "File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %" PRId64,
274 hfuzz->inputFile, (int64_t) st.st_size, (int64_t) hfuzz->maxFileSz);
275 return false;
276 }
277
robert.swiecki3bb518c2010-10-14 00:48:24 +0000278 hfuzz->files[0] = hfuzz->inputFile;
279 hfuzz->fileCnt = 1;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000280 return true;
281}
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000282
groebert@google.com1bd4c212013-06-19 11:13:56 +0000283char *files_basename(char *path)
284{
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000285 char *base = strrchr(path, '/');
286 return base ? base + 1 : path;
287}
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000288
289bool files_parseDictionary(honggfuzz_t * hfuzz)
290{
291 FILE *fDict = fopen(hfuzz->dictionaryFile, "rb");
292 if (fDict == NULL) {
293 LOGMSG_P(l_ERROR, "Couldn't open '%s' - R/O mode", hfuzz->dictionaryFile);
294 return false;
295 }
296
robert.swiecki@gmail.com0440c532015-04-21 17:27:08 +0000297 for (;;) {
298 char *lineptr = NULL;
299 size_t n = 0;
300 if (getdelim(&lineptr, &n, '\0', fDict) == -1) {
301 break;
302 }
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000303 if ((hfuzz->dictionary =
304 realloc(hfuzz->dictionary,
robert.swiecki@gmail.comd9363be2015-04-21 17:24:02 +0000305 (hfuzz->dictionaryCnt + 1) * sizeof(hfuzz->dictionary[0]))) == NULL) {
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000306 LOGMSG_P(l_ERROR, "Realloc failed (sz=%zu)",
robert.swiecki@gmail.comd9363be2015-04-21 17:24:02 +0000307 (hfuzz->dictionaryCnt + 1) * sizeof(hfuzz->dictionary[0]));
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000308 fclose(fDict);
309 return false;
310 }
311 hfuzz->dictionary[hfuzz->dictionaryCnt] = lineptr;
robert.swiecki@gmail.comd9363be2015-04-21 17:24:02 +0000312 LOGMSG(l_DEBUG, "Dictionary: loaded word: '%s' (len=%zu)",
313 hfuzz->dictionary[hfuzz->dictionaryCnt],
robert.swiecki@gmail.com4f1124f2015-04-21 17:12:22 +0000314 strlen(hfuzz->dictionary[hfuzz->dictionaryCnt]));
315 hfuzz->dictionaryCnt += 1;
316 }
317 LOGMSG(l_INFO, "Loaded %zu words from the dictionary", hfuzz->dictionaryCnt);
318 fclose(fDict);
319 return true;
320}