1/* 2 * Copyright (c) 2013 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2013 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include <sys/errno.h> 37#include <sys/stat.h> 38 39#include <ctype.h> 40#include <dirent.h> 41#include <dlfcn.h> 42#include <err.h> 43#include <fcntl.h> 44#include <limits.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <unistd.h> 49 50#include "check-common.h" 51#include "fuzzer.h" 52 53static char *leak_cmd = NULL; 54static void *dso; 55 56unsigned long count = 0; 57 58static void 59runTestcase(const char *name, const unsigned char *p, size_t length, heim_fuzz_type_t type) 60{ 61 int (*decode_item)(const unsigned char *, size_t, void *, size_t *); 62 int (*free_item)(void *); 63 size_t (*size_item)(void); 64 char *decode_name, *free_name, *size_name; 65 size_t size; 66 void *data; 67 int ret; 68 unsigned char *copy; 69 unsigned long tcount = 1; 70 unsigned long lcount = 0; 71 size_t datasize = 10000; 72 struct map_page *data_map, *copy_map; 73 void *ctx = NULL; 74 75 if (type) { 76 printf("fuzzing using: %s\n", heim_fuzzer_name(type)); 77 tcount = 10000000; 78 } else { 79 printf("non fuzzings\n"); 80 } 81 82 asprintf(&decode_name, "decode_%s", name); 83 asprintf(&free_name, "free_%s", name); 84 asprintf(&size_name, "size_%s", name); 85 86 decode_item = dlsym(dso, decode_name); 87 free_item = dlsym(dso, free_name); 88 size_item = dlsym(dso, size_name); 89 90 free(decode_name); 91 free(free_name); 92 93 if (decode_item == NULL) 94 errx(1, "no decode_%s", name); 95 if (free_item == NULL) 96 errx(1, "no free_%s", name); 97 98 /* should export size_encoder */ 99 if (size_item) 100 datasize = size_item(); 101 else 102 datasize = 10000; 103 104 105 data = map_alloc(OVERRUN, NULL, datasize, &data_map); 106 memset(data, 0, datasize); 107 108 copy = map_alloc(OVERRUN, NULL, length, ©_map); 109 memset(copy, 0, length); 110 111 /* 112 * Main fuzzer loop, keep modifying the input stream as long as it 113 * parses clearly. 114 */ 115 116 memcpy(copy, p, length); 117 while (tcount > 0) { 118 119 if (type) { 120 if (heim_fuzzer(type, &ctx, lcount, copy, length)) { 121 heim_fuzzer_free(type, ctx); 122 ctx = NULL; 123 break; 124 } 125 } 126 127 ret = decode_item(copy, length, data, &size); 128 if (ret) { 129 memcpy(copy, p, length); 130 } else { 131 free_item(data); 132 } 133 134 tcount--; 135 count++; 136 lcount++; 137 if ((count & 0xffff) == 0) { 138 printf("%lu...\n", (unsigned long)lcount); 139 140 if (leak_cmd) { 141 memset(data, 0, datasize); 142 if (system(leak_cmd)) 143 abort(); 144 } 145 } 146 } 147 148 map_free(copy_map, "fuzzer", "copy"); 149 map_free(data_map, "fuzzer", "data"); 150} 151 152static void 153parseTestcase(const char *filename) 154{ 155 struct stat sb; 156 char *p, *buf; 157 ssize_t sret; 158 size_t size; 159 int fd; 160 161 fd = open(filename, O_RDONLY, 0); 162 if (fd < 0) { 163 warn("failed to open: %s", filename); 164 return; 165 } 166 if (fstat(fd, &sb) != 0) 167 err(1, "failed to stat: %s", filename); 168 if (!S_ISREG(sb.st_mode)) { 169 close(fd); 170 return; 171 } 172 173 if (sb.st_size > (off_t)(SIZE_T_MAX >> 1)) 174 errx(1, "%s to larger", filename); 175 176 buf = malloc((size_t)sb.st_size); 177 if (buf == NULL) 178 err(1, "malloc"); 179 size = (size_t)sb.st_size; 180 181 sret = read(fd, buf, size); 182 if (sret < 0) 183 err(1, "read"); 184 else if (sret != (ssize_t)size) 185 errx(1, "short read"); 186 187 close(fd); 188 189 p = memchr(buf, '\0', size); 190 if (p && p != buf) { 191 p++; 192 193 runTestcase(buf, (const void *)p, size - (p - buf), NULL); 194 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_RANDOM); 195 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_BITFLIP); 196 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_BYTEFLIP); 197 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_SHORTFLIP); 198 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_WORDFLIP); 199 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_INTERESTING8); 200 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_INTERESTING16); 201 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_INTERESTING32); 202#if 0 203 runTestcase(buf, (const void *)p, size - (p - buf), HEIM_FUZZ_ASN1); 204#endif 205 206 } else { 207 warnx("file '%s' not a valid test case", filename); 208 } 209 210 free(buf); 211} 212 213int 214main(int argc, char **argv) 215{ 216 const char *cmd; 217 218 if (getenv("MallocStackLogging") || getenv("MallocStackLoggingNoCompact")) 219 asprintf(&leak_cmd, "leaks %d > /tmp/leaks-log-pid-%d", (int)getpid(), (int)getpid()); 220 221 dso = dlopen("/usr/local/lib/libheimdal-asn1-all-templates.dylib", RTLD_LAZY); 222 if (dso == NULL) 223 errx(1, "dlopen: %s", dlerror()); 224 225 if (argc < 3) 226 errx(1, "missing command[fuzz-random-|][file|dir] and argument"); 227 228 229 cmd = argv[1]; 230 231 if (strcasecmp("dir", cmd) == 0) { 232 const char *dir = argv[2]; 233 struct dirent *de; 234 DIR *d; 235 236 d = opendir(dir); 237 if (d == NULL) 238 err(1, "opendir: %s", dir); 239 240 while ((de = readdir(d)) != NULL) { 241 char *str; 242 asprintf(&str, "%s/%.*s", dir, (int)de->d_namlen, de->d_name); 243 244 parseTestcase(str); 245 free(str); 246 } 247 } else if (strcasecmp("file", cmd) == 0) { 248 parseTestcase(argv[2]); 249 } else { 250 errx(1, "unknown command: %s", cmd); 251 } 252 253 printf("ran %lu test cases\n", count); 254 255 return 0; 256} 257