1 /*
2 * Copyright(c) 2017 Tim Ruehsen
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23 #include <config.h>
24
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33
34 #include "fuzzer.h"
35
36 #ifdef TEST_RUN
37
38 #include <dirent.h>
39
40 #ifdef _WIN32
41 # define SLASH '\\'
42 #else
43 # define SLASH '/'
44 #endif
45
test_single_file(const char * fname)46 static int test_single_file(const char *fname)
47 {
48 int fd, ret;
49 struct stat st;
50 uint8_t *data;
51 ssize_t n;
52
53 if ((fd = open(fname, O_RDONLY)) == -1) {
54 fprintf(stderr, "Failed to open %s (%d)\n", fname, errno);
55 return -1;
56 }
57
58 if (fstat(fd, &st) != 0) {
59 fprintf(stderr, "Failed to stat %d (%d)\n", fd, errno);
60 close(fd);
61 return -1;
62 }
63
64 data = malloc(st.st_size);
65 if ((n = read(fd, data, st.st_size)) == st.st_size) {
66 printf("testing %llu bytes from '%s'\n", (unsigned long long) st.st_size, fname);
67 fflush(stdout);
68 LLVMFuzzerTestOneInput(data, st.st_size);
69 fflush(stderr);
70 ret = 0;
71 } else {
72 fprintf(stderr, "Failed to read %llu bytes from %s (%d), got %zd\n", (unsigned long long) st.st_size, fname, errno, n);
73 ret = -1;
74 }
75
76 free(data);
77 close(fd);
78 return ret;
79 }
80
test_all_from(const char * dirname)81 static int test_all_from(const char *dirname)
82 {
83 DIR *dirp;
84 struct dirent *dp;
85
86 if ((dirp = opendir(dirname))) {
87 while ((dp = readdir(dirp))) {
88 if (*dp->d_name == '.') continue;
89
90 char fname[strlen(dirname) + strlen(dp->d_name) + 2];
91 snprintf(fname, sizeof(fname), "%s/%s", dirname, dp->d_name);
92
93 if (test_single_file(fname) < 0)
94 continue;
95 }
96 closedir(dirp);
97 return 0;
98 }
99
100 return 1;
101 }
102
main(int argc,char ** argv)103 int main(int argc, char **argv)
104 {
105 const char *target;
106 size_t target_len;
107
108 if ((target = strrchr(argv[0], SLASH)))
109 target = strrchr(target, '/');
110 else
111 target = strrchr(argv[0], '/');
112 target = target ? target + 1 : argv[0];
113
114 if (strncmp(target, "lt-", 3) == 0)
115 target += 3;
116
117 target_len = strlen(target);
118
119 #ifdef _WIN32
120 target_len -= 4; // ignore .exe
121 #endif
122
123 if (argc > 1) { /* test a single file */
124 test_single_file(argv[1]);
125 } else { /* test the target directory */
126 int rc;
127 char corporadir[sizeof(SRCDIR) + 1 + target_len + 8];
128 snprintf(corporadir, sizeof(corporadir), SRCDIR "/%.*s.in", (int) target_len, target);
129
130 rc = test_all_from(corporadir);
131 if (rc)
132 fprintf(stderr, "Failed to find %s\n", corporadir);
133
134 snprintf(corporadir, sizeof(corporadir), SRCDIR "/%.*s.repro", (int) target_len, target);
135
136 if (test_all_from(corporadir) && rc)
137 return 77;
138 }
139
140 return 0;
141 }
142
143 #else
144
145 #ifndef __AFL_LOOP
__AFL_LOOP(int n)146 static int __AFL_LOOP(int n)
147 {
148 static int first = 1;
149
150 if (first) {
151 first = 0;
152 return 1;
153 }
154
155 return 0;
156 }
157 #endif
158
main(int argc,char ** argv)159 int main(int argc, char **argv)
160 {
161 int ret;
162 unsigned char buf[64 * 1024];
163
164 while (__AFL_LOOP(10000)) { // only works with afl-clang-fast
165 ret = fread(buf, 1, sizeof(buf), stdin);
166 if (ret < 0)
167 return 0;
168
169 LLVMFuzzerTestOneInput(buf, ret);
170 }
171
172 return 0;
173 }
174
175 #endif /* TEST_RUN */
176