blob: 48f1e55293e8f6d7dc5d3144565ea174cf1ea2f9 [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
57 if ((size_t) st.st_size > fileMaxSz) {
58 LOGMSG(l_ERROR, "File '%s' size to big (%zu > %zu)", fileName, (size_t) st.st_size,
59 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 }
69
70 return (size_t) st.st_size;
71}
72
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000073bool files_writeToFd(int fd, uint8_t * buf, size_t fileSz)
robert.swiecki3bb518c2010-10-14 00:48:24 +000074{
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000075 size_t writtenSz = 0;
76 while (writtenSz < fileSz) {
77 ssize_t sz = write(fd, &buf[writtenSz], fileSz - writtenSz);
robert.swiecki3bb518c2010-10-14 00:48:24 +000078 if (sz < 0 && errno == EINTR)
79 continue;
80
81 if (sz < 0)
82 return false;
83
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000084 writtenSz += sz;
robert.swiecki3bb518c2010-10-14 00:48:24 +000085 }
robert.swiecki3bb518c2010-10-14 00:48:24 +000086 return true;
87}
88
robert.swiecki@gmail.comad6af222015-02-14 01:56:08 +000089bool files_writeStrToFd(int fd, char *str)
90{
91 return files_writeToFd(fd, (uint8_t *) str, strlen(str));
92}
93
robert.swiecki@gmail.com26a9ab72015-02-22 13:41:18 +000094bool files_readFromFd(int fd, uint8_t * buf, size_t fileSz)
95{
96 size_t readSz = 0;
97 while (readSz < fileSz) {
98 ssize_t sz = read(fd, &buf[readSz], fileSz - readSz);
99 if (sz < 0 && errno == EINTR)
100 continue;
101
102 if (sz < 0)
103 return false;
104
105 readSz += sz;
106 }
107 return true;
108}
109
groebert@google.com1bd4c212013-06-19 11:13:56 +0000110bool files_exists(char *fileName)
111{
112 return (access(fileName, F_OK) != -1);
113}
114
robert.swiecki3bb518c2010-10-14 00:48:24 +0000115bool files_writePatternToFd(int fd, off_t size, unsigned char p)
116{
117 void *buf = malloc(size);
118 if (!buf) {
119 LOGMSG_P(l_WARN, "Couldn't allocate memory");
120 return false;
121 }
122
123 memset(buf, p, (size_t) size);
124 int ret = files_writeToFd(fd, buf, size);
125 free(buf);
126
127 return ret;
128}
129
robert.swiecki@gmail.com0a7eabe2015-02-22 14:47:45 +0000130void files_unmapFileCloseFd(void *ptr, size_t fileSz, int fd)
robert.swiecki@gmail.com4e3f76f2015-02-16 19:34:54 +0000131{
robert.swiecki@gmail.com9f559a92015-02-17 20:36:51 +0000132 munmap(ptr, _HF_PAGE_ALIGN_UP(fileSz));
robert.swiecki@gmail.com5d86dd12015-02-17 14:18:43 +0000133 close(fd);
robert.swiecki@gmail.com4e3f76f2015-02-16 19:34:54 +0000134}
135
robert.swiecki@gmail.com0a7eabe2015-02-22 14:47:45 +0000136uint8_t *files_mapFileToRead(char *fileName, size_t * fileSz, int *fd)
robert.swiecki3bb518c2010-10-14 00:48:24 +0000137{
138 if ((*fd = open(fileName, O_RDONLY)) == -1) {
139 LOGMSG_P(l_WARN, "Couldn't open() '%s' file in R/O mode", fileName);
140 return NULL;
141 }
142
143 struct stat st;
144 if (fstat(*fd, &st) == -1) {
145 LOGMSG_P(l_WARN, "Couldn't stat() the '%s' file", fileName);
146 close(*fd);
147 return NULL;
148 }
149
150 uint8_t *buf;
robert.swiecki@gmail.com66ee2752015-02-16 20:49:44 +0000151 if ((buf =
robert.swiecki@gmail.com9f559a92015-02-17 20:36:51 +0000152 mmap(NULL, _HF_PAGE_ALIGN_UP(st.st_size), PROT_READ | PROT_WRITE, MAP_PRIVATE, *fd,
robert.swiecki@gmail.com66ee2752015-02-16 20:49:44 +0000153 0)) == MAP_FAILED) {
robert.swiecki3bb518c2010-10-14 00:48:24 +0000154 LOGMSG_P(l_WARN, "Couldn't mmap() the '%s' file", fileName);
155 close(*fd);
156 return NULL;
157 }
158
robert.swiecki@gmail.com011981f2015-02-17 19:06:44 +0000159 LOGMSG(l_DEBUG, "mmap()'d '%llu' bytes for the file '%s' (original size: '%llu') at 0x%p",
robert.swiecki@gmail.com9f559a92015-02-17 20:36:51 +0000160 (unsigned long long)_HF_PAGE_ALIGN_UP(st.st_size), fileName,
161 (unsigned long long)st.st_size, buf);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000162 *fileSz = st.st_size;
163 return buf;
164}
165
robert.swiecki@gmail.com3109d0a2015-02-25 18:12:45 +0000166uint8_t *files_mapFileToWriteIni(char *fileName, size_t fileSz, int *fd, uint8_t * iniBuf)
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +0000167{
robert.swiecki@gmail.com3109d0a2015-02-25 18:12:45 +0000168 if ((*fd = open(fileName, O_CREAT | O_EXCL | O_RDWR, 0644)) == -1) {
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +0000169 LOGMSG_P(l_WARN, "Couldn't open() '%s' file in R/W mode", fileName);
170 return NULL;
171 }
172 if (ftruncate(*fd, fileSz) == -1) {
173 LOGMSG_P(l_ERROR, "Couldn't ftruncate(fd='%d', size='%zu')", *fd, fileSz);
174 close(*fd);
175 return NULL;
176 }
177
178 uint8_t *buf;
179 if ((buf =
180 mmap(NULL, _HF_PAGE_ALIGN_UP(fileSz), PROT_READ | PROT_WRITE, MAP_SHARED, *fd,
181 0)) == MAP_FAILED) {
robert.swiecki@gmail.coma56173d2015-02-26 00:46:24 +0000182 LOGMSG_P(l_WARN, "Couldn't mmap() the '%s' file, size '%zu'", fileName, fileSz);
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +0000183 close(*fd);
184 return NULL;
185 }
186
187 LOGMSG(l_DEBUG, "mmap()'d '%llu' bytes for the file '%s' (original size: '%llu') at 0x%p",
robert.swiecki@gmail.combb5d2642015-02-25 20:00:00 +0000188 (unsigned long long)_HF_PAGE_ALIGN_UP(fileSz), fileName, (unsigned long long)fileSz,
189 buf);
robert.swiecki@gmail.com0988d282015-02-25 18:04:18 +0000190
191 memcpy(buf, iniBuf, fileSz);
192 return buf;
193}
194
robert.swiecki3bb518c2010-10-14 00:48:24 +0000195static bool files_readdir(honggfuzz_t * hfuzz)
196{
197 DIR *dir = opendir(hfuzz->inputFile);
198 if (!dir) {
199 LOGMSG_P(l_ERROR, "Couldn't open dir '%s'", hfuzz->inputFile);
200 return false;
201 }
202
203 int count = 0;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000204 for (;;) {
205 struct dirent de, *res;
206 if (readdir_r(dir, &de, &res) > 0) {
207 LOGMSG_P(l_ERROR, "Couldn't read the '%s' dir", hfuzz->inputFile);
208 closedir(dir);
209 return false;
210 }
211
212 if (res == NULL && count > 0) {
213 LOGMSG(l_INFO, "%d input files have been added to the list", hfuzz->fileCnt);
214 closedir(dir);
215 return true;
216 }
217
218 if (res == NULL && count == 0) {
219 LOGMSG(l_ERROR, "Directory '%s' doesn't contain any regular files", hfuzz->inputFile);
220 closedir(dir);
221 return false;
222 }
223
224 char path[PATH_MAX];
225 snprintf(path, sizeof(path), "%s/%s", hfuzz->inputFile, res->d_name);
robert.swiecki3bb518c2010-10-14 00:48:24 +0000226 struct stat st;
227 if (stat(path, &st) == -1) {
228 LOGMSG(l_WARN, "Couldn't stat() the '%s' file", path);
229 continue;
230 }
231
232 if (!S_ISREG(st.st_mode)) {
233 LOGMSG(l_DEBUG, "'%s' is not a regular file, skipping", path);
234 continue;
235 }
236
237 if (st.st_size == 0) {
238 LOGMSG(l_DEBUG, "'%s' is empty", path);
239 continue;
240 }
241
robert.swiecki@gmail.com86941cb2015-02-22 15:15:08 +0000242 if (st.st_size > (off_t) hfuzz->maxFileSz) {
243 LOGMSG(l_WARN,
244 "File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %"
245 PRId64, path, (int64_t) st.st_size, (int64_t) hfuzz->maxFileSz);
246 continue;
247 }
248
robert.swiecki3bb518c2010-10-14 00:48:24 +0000249 if (!(hfuzz->files = realloc(hfuzz->files, sizeof(char *) * (count + 1)))) {
250 LOGMSG_P(l_ERROR, "Couldn't allocate memory");
251 closedir(dir);
252 return false;
253 }
254
255 hfuzz->files[count] = strdup(path);
256 if (!hfuzz->files[count]) {
257 LOGMSG_P(l_ERROR, "Couldn't allocate memory");
258 closedir(dir);
259 return false;
260 }
261 hfuzz->fileCnt = ++count;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000262 LOGMSG(l_DEBUG, "Added '%s' to the list of input files", path);
263 }
264
265 abort(); /* NOTREACHED */
266 return false;
267}
268
269bool files_init(honggfuzz_t * hfuzz)
270{
robert.swiecki@gmail.comea1be292014-07-21 17:36:50 +0000271 hfuzz->files = malloc(sizeof(char *));
robert.swiecki@gmail.comcac22fd2015-02-19 14:03:28 +0000272 if (hfuzz->dynFileMethod != _HF_DYNFILE_NONE && !hfuzz->inputFile) {
robert.swiecki@gmail.comcfff7592015-02-18 00:06:19 +0000273 hfuzz->fileCnt = 1;
robert.swiecki@gmail.comcac22fd2015-02-19 14:03:28 +0000274 hfuzz->files[0] = "DYNAMIC_FILE";
robert.swiecki@gmail.com6d6f7562015-02-17 22:18:51 +0000275 return true;
276 }
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000277 if (hfuzz->externalCommand && !hfuzz->inputFile) {
robert.swiecki@gmail.comc6deb6f2014-06-03 18:17:55 +0000278 hfuzz->fileCnt = 1;
robert.swiecki@gmail.com73df4252015-02-18 00:09:48 +0000279 hfuzz->files[0] = "CREATED";
robert.swiecki@gmail.comebc1cac2011-07-02 03:15:51 +0000280 LOGMSG(l_INFO,
281 "No input file corpus specified, the external command '%s' is responsible for creating the fuzz files",
282 hfuzz->externalCommand);
283 return true;
284 }
285
robert.swiecki3bb518c2010-10-14 00:48:24 +0000286 if (!hfuzz->files) {
287 LOGMSG_P(l_ERROR, "Couldn't allocate memory");
288 return false;
289 }
290
291 if (!hfuzz->inputFile) {
292 LOGMSG(l_ERROR, "No input file/dir specified");
293 return false;
294 }
295
296 struct stat st;
297 if (stat(hfuzz->inputFile, &st) == -1) {
298 LOGMSG_P(l_ERROR, "Couldn't stat the input file/dir '%s'", hfuzz->inputFile);
299 return false;
300 }
301
robert.swiecki@gmail.com86941cb2015-02-22 15:15:08 +0000302 if (st.st_size > (off_t) hfuzz->maxFileSz) {
303 LOGMSG(l_ERROR,
304 "File '%s' is bigger than maximal defined file size (-F): %" PRId64 " > %" PRId64,
305 hfuzz->inputFile, (int64_t) st.st_size, (int64_t) hfuzz->maxFileSz);
306 return false;
307 }
308
robert.swiecki3bb518c2010-10-14 00:48:24 +0000309 if (S_ISDIR(st.st_mode)) {
310 return files_readdir(hfuzz);
311 }
312
313 if (!S_ISREG(st.st_mode)) {
314 LOGMSG(l_ERROR, "'%s' is not a regular file, nor a directory", hfuzz->inputFile);
315 return false;
316 }
317
318 hfuzz->files[0] = hfuzz->inputFile;
319 hfuzz->fileCnt = 1;
robert.swiecki3bb518c2010-10-14 00:48:24 +0000320 return true;
321}
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000322
groebert@google.com1bd4c212013-06-19 11:13:56 +0000323char *files_basename(char *path)
324{
groebert@google.com1c7e3b02013-06-19 09:27:38 +0000325 char *base = strrchr(path, '/');
326 return base ? base + 1 : path;
327}