1/* 2 * fuzz-decode: special program for fuzzing. It still reads encoded 3 * files just like interop-decode, but tries to do it faster and 4 * forgoes several advanced options. 5 */ 6 7#ifdef WIN32 8 9#include <stdio.h> 10 11int 12main (int argc, char **argv) 13{ 14 fprintf(stderr, "%s is not supported on Windows: need mmap(2)\n", argv[0]); 15 return 1; 16} 17 18#else 19 20#include <assert.h> 21 22#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) 23#include <sys/endian.h> 24#define bswap_16 bswap16 25#define bswap_32 bswap32 26#define bswap_64 bswap64 27#elif defined(__APPLE__) 28#include <libkern/OSByteOrder.h> 29#define bswap_16 OSSwapInt16 30#define bswap_32 OSSwapInt32 31#define bswap_64 OSSwapInt64 32#elif defined(WIN32) 33#define bswap_16 _byteswap_ushort 34#define bswap_32 _byteswap_ulong 35#define bswap_64 _byteswap_uint64 36#else 37#include <byteswap.h> 38#endif 39 40#include <errno.h> 41#include <inttypes.h> 42#include <stddef.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <unistd.h> 47#include <sys/queue.h> 48#include <sys/types.h> 49#include <sys/stat.h> 50#include <sys/mman.h> 51#include <fcntl.h> 52 53#include "lsqpack.h" 54#include "lsxpack_header.h" 55 56#define MIN(a, b) ((a) < (b) ? (a) : (b)) 57 58static void 59usage (const char *name) 60{ 61 fprintf(stderr, 62"Usage: %s [options] [-i input] [-o output]\n" 63"\n" 64"Options:\n" 65" -i FILE Input file.\n" 66" -f FILE Fuzz file: this is the stuff the fuzzer will change.\n" 67" -s NUMBER Maximum number of risked streams. Defaults to %u.\n" 68" -t NUMBER Dynamic table size. Defaults to %u.\n" 69"\n" 70" -h Print this help screen and exit\n" 71 , name, LSQPACK_DEF_MAX_RISKED_STREAMS, LSQPACK_DEF_DYN_TABLE_SIZE); 72} 73 74 75static void 76hblock_unblocked (void *buf_p) 77{ 78 exit(1); 79} 80 81 82struct header 83{ 84 LIST_ENTRY(header) next_header; 85 struct lsxpack_header xhdr; 86 char buf[0x10000]; 87}; 88 89 90LIST_HEAD(, header) s_headers; 91 92 93static struct lsxpack_header * 94prepare_decode (void *hblock_ctx, struct lsxpack_header *xhdr, size_t space) 95{ 96 struct header *header; 97 98 if (xhdr) 99 { 100 /* If the original buffer is not enough, we don't reallocate */ 101 header = (struct header *) ((char *) xhdr 102 - offsetof(struct header, xhdr)); 103 LIST_REMOVE(header, next_header); 104 free(header); 105 return NULL; 106 } 107 else if (space <= LSXPACK_MAX_STRLEN) 108 { 109 header = malloc(sizeof(*header)); 110 if (!header) 111 return NULL; 112 LIST_INSERT_HEAD(&s_headers, header, next_header); 113 lsxpack_header_prepare_decode(&header->xhdr, header->buf, 114 0, sizeof(header->buf)); 115 return &header->xhdr; 116 } 117 else 118 return NULL; 119} 120 121 122static int 123process_header (void *hblock_ctx, struct lsxpack_header *xhdr) 124{ 125 struct header *header; 126 127 header = (struct header *) ((char *) xhdr - offsetof(struct header, xhdr)); 128 LIST_REMOVE(header, next_header); 129 free(header); 130 return 0; 131} 132 133 134static const struct lsqpack_dec_hset_if hset_if = { 135 .dhi_unblocked = hblock_unblocked, 136 .dhi_prepare_decode = prepare_decode, 137 .dhi_process_header = process_header, 138}; 139 140 141int 142main (int argc, char **argv) 143{ 144 int in_fd = -1, fuzz_fd = STDIN_FILENO; 145 int opt; 146 unsigned dyn_table_size = LSQPACK_DEF_DYN_TABLE_SIZE, 147 max_risked_streams = LSQPACK_DEF_MAX_RISKED_STREAMS; 148 struct lsqpack_dec decoder; 149 const unsigned char *p, *end; 150 unsigned char *begin; 151 struct stat st; 152 uint64_t stream_id; 153 uint32_t size; 154 int r; 155 struct header *header; 156 157 while (-1 != (opt = getopt(argc, argv, "i:f:s:t:h"))) 158 { 159 switch (opt) 160 { 161 case 'i': 162 in_fd = open(optarg, O_RDONLY); 163 if (in_fd < 0) 164 { 165 fprintf(stderr, "cannot open `%s' for reading: %s\n", 166 optarg, strerror(errno)); 167 exit(EXIT_FAILURE); 168 } 169 break; 170 case 'f': 171 fuzz_fd = open(optarg, O_RDONLY); 172 if (fuzz_fd < 0) 173 { 174 fprintf(stderr, "cannot open `%s' for reading: %s\n", 175 optarg, strerror(errno)); 176 exit(EXIT_FAILURE); 177 } 178 break; 179 case 's': 180 max_risked_streams = atoi(optarg); 181 break; 182 case 't': 183 dyn_table_size = atoi(optarg); 184 break; 185 case 'h': 186 usage(argv[0]); 187 exit(EXIT_SUCCESS); 188 default: 189 exit(EXIT_FAILURE); 190 } 191 } 192 193 LIST_INIT(&s_headers); 194 lsqpack_dec_init(&decoder, NULL, dyn_table_size, max_risked_streams, 195 &hset_if, 0 /* TODO: add command-line option */); 196 197 if (in_fd < 0) 198 { 199 fprintf(stderr, "Specify input using `-i' option\n"); 200 exit(1); 201 } 202 203 if (0 != fstat(in_fd, &st)) 204 { 205 perror("fstat"); 206 exit(1); 207 } 208 209 begin = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in_fd, 0); 210 if (!begin) 211 { 212 perror("mmap"); 213 exit(1); 214 } 215 216 p = begin; 217 end = begin + st.st_size; 218 while (p + sizeof(stream_id) + sizeof(size) < end) 219 { 220 stream_id = * (uint64_t *) p; 221 p += sizeof(uint64_t); 222 size = * (uint32_t *) p; 223 p += sizeof(uint32_t); 224#if __BYTE_ORDER == __LITTLE_ENDIAN 225 stream_id = bswap_64(stream_id); 226 size = bswap_32(size); 227#endif 228 if (p + size > end) 229 { 230 fprintf(stderr, "truncated input at offset %u", 231 (unsigned) (p - begin)); 232 abort(); 233 } 234 if (stream_id == 0) 235 { 236 r = lsqpack_dec_enc_in(&decoder, p, size); 237 if (r != 0) 238 abort(); 239 } 240 else 241 { 242 const unsigned char *cur = p; 243 enum lsqpack_read_header_status rhs; 244 rhs = lsqpack_dec_header_in(&decoder, NULL, stream_id, 245 size, &cur, size, NULL, NULL); 246 if (rhs != LQRHS_DONE || (uint32_t) (cur - p) != size) 247 abort(); 248 } 249 p += size; 250 } 251 252 munmap(begin, st.st_size); 253 (void) close(in_fd); 254 255 /* Now let's read the fuzzed part */ 256 257 if (0 != fstat(fuzz_fd, &st)) 258 { 259 perror("fstat"); 260 exit(1); 261 } 262 263 begin = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fuzz_fd, 0); 264 if (!begin) 265 { 266 perror("mmap"); 267 exit(1); 268 } 269 270 p = begin; 271 end = begin + st.st_size; 272 while (p + sizeof(stream_id) + sizeof(size) < end) 273 { 274 stream_id = * (uint64_t *) p; 275 p += sizeof(uint64_t); 276 size = * (uint32_t *) p; 277 p += sizeof(uint32_t); 278#if __BYTE_ORDER == __LITTLE_ENDIAN 279 stream_id = bswap_64(stream_id); 280 size = bswap_32(size); 281#endif 282 if (stream_id == 0) 283 { 284 r = lsqpack_dec_enc_in(&decoder, p, MIN(size, (uint32_t) (end - p))); 285 (void) r; 286 } 287 else 288 { 289 const unsigned char *cur = p; 290 enum lsqpack_read_header_status rhs; 291 size = MIN(size, (uint32_t) (end - p)); 292 rhs = lsqpack_dec_header_in(&decoder, NULL, stream_id, 293 size, &cur, size, NULL, NULL); 294 (void) rhs; 295 } 296 break; 297 } 298 299 munmap(begin, st.st_size); 300 (void) close(fuzz_fd); 301 302 lsqpack_dec_cleanup(&decoder); 303 while (!LIST_EMPTY(&s_headers)) 304 { 305 header = LIST_FIRST(&s_headers); 306 LIST_REMOVE(header, next_header); 307 free(header); 308 } 309 310 exit(0); 311} 312 313#endif 314