1bfd9d262SDmitri Tikhonov/* 2bfd9d262SDmitri Tikhonov * fuzz-decode: special program for fuzzing. It still reads encoded 3bfd9d262SDmitri Tikhonov * files just like interop-decode, but tries to do it faster and 4bfd9d262SDmitri Tikhonov * forgoes several advanced options. 5bfd9d262SDmitri Tikhonov */ 6bfd9d262SDmitri Tikhonov 7205a2804SDmitri Tikhonov#ifdef WIN32 8205a2804SDmitri Tikhonov 9205a2804SDmitri Tikhonov#include <stdio.h> 10205a2804SDmitri Tikhonov 11205a2804SDmitri Tikhonovint 12205a2804SDmitri Tikhonovmain (int argc, char **argv) 13205a2804SDmitri Tikhonov{ 14205a2804SDmitri Tikhonov fprintf(stderr, "%s is not supported on Windows: need mmap(2)\n", argv[0]); 15205a2804SDmitri Tikhonov return 1; 16205a2804SDmitri Tikhonov} 17205a2804SDmitri Tikhonov 18205a2804SDmitri Tikhonov#else 19205a2804SDmitri Tikhonov 20bfd9d262SDmitri Tikhonov#include <assert.h> 21446dba69SDmitri Tikhonov 22446dba69SDmitri Tikhonov#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) 23446dba69SDmitri Tikhonov#include <sys/endian.h> 24446dba69SDmitri Tikhonov#define bswap_16 bswap16 25446dba69SDmitri Tikhonov#define bswap_32 bswap32 26446dba69SDmitri Tikhonov#define bswap_64 bswap64 27446dba69SDmitri Tikhonov#elif defined(__APPLE__) 28446dba69SDmitri Tikhonov#include <libkern/OSByteOrder.h> 29446dba69SDmitri Tikhonov#define bswap_16 OSSwapInt16 30446dba69SDmitri Tikhonov#define bswap_32 OSSwapInt32 31446dba69SDmitri Tikhonov#define bswap_64 OSSwapInt64 32446dba69SDmitri Tikhonov#elif defined(WIN32) 33446dba69SDmitri Tikhonov#define bswap_16 _byteswap_ushort 34446dba69SDmitri Tikhonov#define bswap_32 _byteswap_ulong 35446dba69SDmitri Tikhonov#define bswap_64 _byteswap_uint64 36446dba69SDmitri Tikhonov#else 37bfd9d262SDmitri Tikhonov#include <byteswap.h> 38446dba69SDmitri Tikhonov#endif 39446dba69SDmitri Tikhonov 40bfd9d262SDmitri Tikhonov#include <errno.h> 41bfd9d262SDmitri Tikhonov#include <inttypes.h> 4260620859SDmitri Tikhonov#include <stddef.h> 43bfd9d262SDmitri Tikhonov#include <stdio.h> 44bfd9d262SDmitri Tikhonov#include <stdlib.h> 45bfd9d262SDmitri Tikhonov#include <string.h> 46bfd9d262SDmitri Tikhonov#include <unistd.h> 47bfd9d262SDmitri Tikhonov#include <sys/queue.h> 48bfd9d262SDmitri Tikhonov#include <sys/types.h> 49bfd9d262SDmitri Tikhonov#include <sys/stat.h> 50bfd9d262SDmitri Tikhonov#include <sys/mman.h> 51bfd9d262SDmitri Tikhonov#include <fcntl.h> 52bfd9d262SDmitri Tikhonov 53bfd9d262SDmitri Tikhonov#include "lsqpack.h" 5460620859SDmitri Tikhonov#include "lsxpack_header.h" 55bfd9d262SDmitri Tikhonov 56bfd9d262SDmitri Tikhonov#define MIN(a, b) ((a) < (b) ? (a) : (b)) 57bfd9d262SDmitri Tikhonov 58bfd9d262SDmitri Tikhonovstatic void 59bfd9d262SDmitri Tikhonovusage (const char *name) 60bfd9d262SDmitri Tikhonov{ 61bfd9d262SDmitri Tikhonov fprintf(stderr, 62bfd9d262SDmitri Tikhonov"Usage: %s [options] [-i input] [-o output]\n" 63bfd9d262SDmitri Tikhonov"\n" 64bfd9d262SDmitri Tikhonov"Options:\n" 65bfd9d262SDmitri Tikhonov" -i FILE Input file.\n" 66bfd9d262SDmitri Tikhonov" -f FILE Fuzz file: this is the stuff the fuzzer will change.\n" 67bfd9d262SDmitri Tikhonov" -s NUMBER Maximum number of risked streams. Defaults to %u.\n" 68bfd9d262SDmitri Tikhonov" -t NUMBER Dynamic table size. Defaults to %u.\n" 69bfd9d262SDmitri Tikhonov"\n" 70bfd9d262SDmitri Tikhonov" -h Print this help screen and exit\n" 71bfd9d262SDmitri Tikhonov , name, LSQPACK_DEF_MAX_RISKED_STREAMS, LSQPACK_DEF_DYN_TABLE_SIZE); 72bfd9d262SDmitri Tikhonov} 73bfd9d262SDmitri Tikhonov 74bfd9d262SDmitri Tikhonov 75bfd9d262SDmitri Tikhonovstatic void 76bfd9d262SDmitri Tikhonovhblock_unblocked (void *buf_p) 77bfd9d262SDmitri Tikhonov{ 78bfd9d262SDmitri Tikhonov exit(1); 79bfd9d262SDmitri Tikhonov} 80bfd9d262SDmitri Tikhonov 81bfd9d262SDmitri Tikhonov 8260620859SDmitri Tikhonovstruct header 8360620859SDmitri Tikhonov{ 8460620859SDmitri Tikhonov LIST_ENTRY(header) next_header; 8560620859SDmitri Tikhonov struct lsxpack_header xhdr; 8660620859SDmitri Tikhonov char buf[0x10000]; 8760620859SDmitri Tikhonov}; 8860620859SDmitri Tikhonov 8960620859SDmitri Tikhonov 9060620859SDmitri TikhonovLIST_HEAD(, header) s_headers; 9160620859SDmitri Tikhonov 9260620859SDmitri Tikhonov 9360620859SDmitri Tikhonovstatic struct lsxpack_header * 9460620859SDmitri Tikhonovprepare_decode (void *hblock_ctx, struct lsxpack_header *xhdr, size_t space) 9560620859SDmitri Tikhonov{ 9660620859SDmitri Tikhonov struct header *header; 9760620859SDmitri Tikhonov 9860620859SDmitri Tikhonov if (xhdr) 9960620859SDmitri Tikhonov { 10060620859SDmitri Tikhonov /* If the original buffer is not enough, we don't reallocate */ 10160620859SDmitri Tikhonov header = (struct header *) ((char *) xhdr 10260620859SDmitri Tikhonov - offsetof(struct header, xhdr)); 10360620859SDmitri Tikhonov LIST_REMOVE(header, next_header); 10460620859SDmitri Tikhonov free(header); 10560620859SDmitri Tikhonov return NULL; 10660620859SDmitri Tikhonov } 10760620859SDmitri Tikhonov else if (space <= LSXPACK_MAX_STRLEN) 10860620859SDmitri Tikhonov { 10960620859SDmitri Tikhonov header = malloc(sizeof(*header)); 11060620859SDmitri Tikhonov if (!header) 11160620859SDmitri Tikhonov return NULL; 11260620859SDmitri Tikhonov LIST_INSERT_HEAD(&s_headers, header, next_header); 11360620859SDmitri Tikhonov lsxpack_header_prepare_decode(&header->xhdr, header->buf, 11460620859SDmitri Tikhonov 0, sizeof(header->buf)); 11560620859SDmitri Tikhonov return &header->xhdr; 11660620859SDmitri Tikhonov } 11760620859SDmitri Tikhonov else 11860620859SDmitri Tikhonov return NULL; 11960620859SDmitri Tikhonov} 12060620859SDmitri Tikhonov 12160620859SDmitri Tikhonov 12260620859SDmitri Tikhonovstatic int 12360620859SDmitri Tikhonovprocess_header (void *hblock_ctx, struct lsxpack_header *xhdr) 12460620859SDmitri Tikhonov{ 12560620859SDmitri Tikhonov struct header *header; 12660620859SDmitri Tikhonov 12760620859SDmitri Tikhonov header = (struct header *) ((char *) xhdr - offsetof(struct header, xhdr)); 12860620859SDmitri Tikhonov LIST_REMOVE(header, next_header); 12960620859SDmitri Tikhonov free(header); 13060620859SDmitri Tikhonov return 0; 13160620859SDmitri Tikhonov} 13260620859SDmitri Tikhonov 13360620859SDmitri Tikhonov 13460620859SDmitri Tikhonovstatic const struct lsqpack_dec_hset_if hset_if = { 13560620859SDmitri Tikhonov .dhi_unblocked = hblock_unblocked, 13660620859SDmitri Tikhonov .dhi_prepare_decode = prepare_decode, 13760620859SDmitri Tikhonov .dhi_process_header = process_header, 13860620859SDmitri Tikhonov}; 13960620859SDmitri Tikhonov 14060620859SDmitri Tikhonov 141bfd9d262SDmitri Tikhonovint 142bfd9d262SDmitri Tikhonovmain (int argc, char **argv) 143bfd9d262SDmitri Tikhonov{ 144bfd9d262SDmitri Tikhonov int in_fd = -1, fuzz_fd = STDIN_FILENO; 145bfd9d262SDmitri Tikhonov int opt; 146bfd9d262SDmitri Tikhonov unsigned dyn_table_size = LSQPACK_DEF_DYN_TABLE_SIZE, 147bfd9d262SDmitri Tikhonov max_risked_streams = LSQPACK_DEF_MAX_RISKED_STREAMS; 148bfd9d262SDmitri Tikhonov struct lsqpack_dec decoder; 149bfd9d262SDmitri Tikhonov const unsigned char *p, *end; 150bfd9d262SDmitri Tikhonov unsigned char *begin; 151bfd9d262SDmitri Tikhonov struct stat st; 152bfd9d262SDmitri Tikhonov uint64_t stream_id; 153bfd9d262SDmitri Tikhonov uint32_t size; 154bfd9d262SDmitri Tikhonov int r; 15560620859SDmitri Tikhonov struct header *header; 156bfd9d262SDmitri Tikhonov 157bfd9d262SDmitri Tikhonov while (-1 != (opt = getopt(argc, argv, "i:f:s:t:h"))) 158bfd9d262SDmitri Tikhonov { 159bfd9d262SDmitri Tikhonov switch (opt) 160bfd9d262SDmitri Tikhonov { 161bfd9d262SDmitri Tikhonov case 'i': 162bfd9d262SDmitri Tikhonov in_fd = open(optarg, O_RDONLY); 163bfd9d262SDmitri Tikhonov if (in_fd < 0) 164bfd9d262SDmitri Tikhonov { 165bfd9d262SDmitri Tikhonov fprintf(stderr, "cannot open `%s' for reading: %s\n", 166bfd9d262SDmitri Tikhonov optarg, strerror(errno)); 167bfd9d262SDmitri Tikhonov exit(EXIT_FAILURE); 168bfd9d262SDmitri Tikhonov } 169bfd9d262SDmitri Tikhonov break; 170bfd9d262SDmitri Tikhonov case 'f': 171bfd9d262SDmitri Tikhonov fuzz_fd = open(optarg, O_RDONLY); 172bfd9d262SDmitri Tikhonov if (fuzz_fd < 0) 173bfd9d262SDmitri Tikhonov { 174bfd9d262SDmitri Tikhonov fprintf(stderr, "cannot open `%s' for reading: %s\n", 175bfd9d262SDmitri Tikhonov optarg, strerror(errno)); 176bfd9d262SDmitri Tikhonov exit(EXIT_FAILURE); 177bfd9d262SDmitri Tikhonov } 178bfd9d262SDmitri Tikhonov break; 179bfd9d262SDmitri Tikhonov case 's': 180bfd9d262SDmitri Tikhonov max_risked_streams = atoi(optarg); 181bfd9d262SDmitri Tikhonov break; 182bfd9d262SDmitri Tikhonov case 't': 183bfd9d262SDmitri Tikhonov dyn_table_size = atoi(optarg); 184bfd9d262SDmitri Tikhonov break; 185bfd9d262SDmitri Tikhonov case 'h': 186bfd9d262SDmitri Tikhonov usage(argv[0]); 187bfd9d262SDmitri Tikhonov exit(EXIT_SUCCESS); 188bfd9d262SDmitri Tikhonov default: 189bfd9d262SDmitri Tikhonov exit(EXIT_FAILURE); 190bfd9d262SDmitri Tikhonov } 191bfd9d262SDmitri Tikhonov } 192bfd9d262SDmitri Tikhonov 19360620859SDmitri Tikhonov LIST_INIT(&s_headers); 194bfd9d262SDmitri Tikhonov lsqpack_dec_init(&decoder, NULL, dyn_table_size, max_risked_streams, 19560620859SDmitri Tikhonov &hset_if, 0 /* TODO: add command-line option */); 196bfd9d262SDmitri Tikhonov 197197b1c6fSDmitri Tikhonov if (in_fd < 0) 198197b1c6fSDmitri Tikhonov { 199197b1c6fSDmitri Tikhonov fprintf(stderr, "Specify input using `-i' option\n"); 200197b1c6fSDmitri Tikhonov exit(1); 201197b1c6fSDmitri Tikhonov } 202197b1c6fSDmitri Tikhonov 203bfd9d262SDmitri Tikhonov if (0 != fstat(in_fd, &st)) 204bfd9d262SDmitri Tikhonov { 205bfd9d262SDmitri Tikhonov perror("fstat"); 206bfd9d262SDmitri Tikhonov exit(1); 207bfd9d262SDmitri Tikhonov } 208bfd9d262SDmitri Tikhonov 209bfd9d262SDmitri Tikhonov begin = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in_fd, 0); 210bfd9d262SDmitri Tikhonov if (!begin) 211bfd9d262SDmitri Tikhonov { 212bfd9d262SDmitri Tikhonov perror("mmap"); 213bfd9d262SDmitri Tikhonov exit(1); 214bfd9d262SDmitri Tikhonov } 215bfd9d262SDmitri Tikhonov 216bfd9d262SDmitri Tikhonov p = begin; 217bfd9d262SDmitri Tikhonov end = begin + st.st_size; 218bfd9d262SDmitri Tikhonov while (p + sizeof(stream_id) + sizeof(size) < end) 219bfd9d262SDmitri Tikhonov { 220bfd9d262SDmitri Tikhonov stream_id = * (uint64_t *) p; 221bfd9d262SDmitri Tikhonov p += sizeof(uint64_t); 222bfd9d262SDmitri Tikhonov size = * (uint32_t *) p; 223bfd9d262SDmitri Tikhonov p += sizeof(uint32_t); 224bfd9d262SDmitri Tikhonov#if __BYTE_ORDER == __LITTLE_ENDIAN 225bfd9d262SDmitri Tikhonov stream_id = bswap_64(stream_id); 226bfd9d262SDmitri Tikhonov size = bswap_32(size); 227bfd9d262SDmitri Tikhonov#endif 228bfd9d262SDmitri Tikhonov if (p + size > end) 229bfd9d262SDmitri Tikhonov { 230bfd9d262SDmitri Tikhonov fprintf(stderr, "truncated input at offset %u", 231bfd9d262SDmitri Tikhonov (unsigned) (p - begin)); 232bfd9d262SDmitri Tikhonov abort(); 233bfd9d262SDmitri Tikhonov } 234bfd9d262SDmitri Tikhonov if (stream_id == 0) 235bfd9d262SDmitri Tikhonov { 236bfd9d262SDmitri Tikhonov r = lsqpack_dec_enc_in(&decoder, p, size); 237bfd9d262SDmitri Tikhonov if (r != 0) 238bfd9d262SDmitri Tikhonov abort(); 239bfd9d262SDmitri Tikhonov } 240bfd9d262SDmitri Tikhonov else 241bfd9d262SDmitri Tikhonov { 242bfd9d262SDmitri Tikhonov const unsigned char *cur = p; 243bfd9d262SDmitri Tikhonov enum lsqpack_read_header_status rhs; 244bfd9d262SDmitri Tikhonov rhs = lsqpack_dec_header_in(&decoder, NULL, stream_id, 24560620859SDmitri Tikhonov size, &cur, size, NULL, NULL); 246446dba69SDmitri Tikhonov if (rhs != LQRHS_DONE || (uint32_t) (cur - p) != size) 247bfd9d262SDmitri Tikhonov abort(); 248bfd9d262SDmitri Tikhonov } 249bfd9d262SDmitri Tikhonov p += size; 250bfd9d262SDmitri Tikhonov } 251bfd9d262SDmitri Tikhonov 252bfd9d262SDmitri Tikhonov munmap(begin, st.st_size); 253bfd9d262SDmitri Tikhonov (void) close(in_fd); 254bfd9d262SDmitri Tikhonov 255bfd9d262SDmitri Tikhonov /* Now let's read the fuzzed part */ 256bfd9d262SDmitri Tikhonov 257bfd9d262SDmitri Tikhonov if (0 != fstat(fuzz_fd, &st)) 258bfd9d262SDmitri Tikhonov { 259bfd9d262SDmitri Tikhonov perror("fstat"); 260bfd9d262SDmitri Tikhonov exit(1); 261bfd9d262SDmitri Tikhonov } 262bfd9d262SDmitri Tikhonov 263bfd9d262SDmitri Tikhonov begin = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fuzz_fd, 0); 264bfd9d262SDmitri Tikhonov if (!begin) 265bfd9d262SDmitri Tikhonov { 266bfd9d262SDmitri Tikhonov perror("mmap"); 267bfd9d262SDmitri Tikhonov exit(1); 268bfd9d262SDmitri Tikhonov } 269bfd9d262SDmitri Tikhonov 270bfd9d262SDmitri Tikhonov p = begin; 271bfd9d262SDmitri Tikhonov end = begin + st.st_size; 272bfd9d262SDmitri Tikhonov while (p + sizeof(stream_id) + sizeof(size) < end) 273bfd9d262SDmitri Tikhonov { 274bfd9d262SDmitri Tikhonov stream_id = * (uint64_t *) p; 275bfd9d262SDmitri Tikhonov p += sizeof(uint64_t); 276bfd9d262SDmitri Tikhonov size = * (uint32_t *) p; 277bfd9d262SDmitri Tikhonov p += sizeof(uint32_t); 278bfd9d262SDmitri Tikhonov#if __BYTE_ORDER == __LITTLE_ENDIAN 279bfd9d262SDmitri Tikhonov stream_id = bswap_64(stream_id); 280bfd9d262SDmitri Tikhonov size = bswap_32(size); 281bfd9d262SDmitri Tikhonov#endif 282bfd9d262SDmitri Tikhonov if (stream_id == 0) 283bfd9d262SDmitri Tikhonov { 284446dba69SDmitri Tikhonov r = lsqpack_dec_enc_in(&decoder, p, MIN(size, (uint32_t) (end - p))); 285bfd9d262SDmitri Tikhonov (void) r; 286bfd9d262SDmitri Tikhonov } 287bfd9d262SDmitri Tikhonov else 288bfd9d262SDmitri Tikhonov { 289bfd9d262SDmitri Tikhonov const unsigned char *cur = p; 290bfd9d262SDmitri Tikhonov enum lsqpack_read_header_status rhs; 291446dba69SDmitri Tikhonov size = MIN(size, (uint32_t) (end - p)); 292bfd9d262SDmitri Tikhonov rhs = lsqpack_dec_header_in(&decoder, NULL, stream_id, 29360620859SDmitri Tikhonov size, &cur, size, NULL, NULL); 294bfd9d262SDmitri Tikhonov (void) rhs; 295bfd9d262SDmitri Tikhonov } 296bfd9d262SDmitri Tikhonov break; 297bfd9d262SDmitri Tikhonov } 298bfd9d262SDmitri Tikhonov 299bfd9d262SDmitri Tikhonov munmap(begin, st.st_size); 300bfd9d262SDmitri Tikhonov (void) close(fuzz_fd); 301bfd9d262SDmitri Tikhonov 302bfd9d262SDmitri Tikhonov lsqpack_dec_cleanup(&decoder); 30360620859SDmitri Tikhonov while (!LIST_EMPTY(&s_headers)) 30460620859SDmitri Tikhonov { 30560620859SDmitri Tikhonov header = LIST_FIRST(&s_headers); 30660620859SDmitri Tikhonov LIST_REMOVE(header, next_header); 30760620859SDmitri Tikhonov free(header); 30860620859SDmitri Tikhonov } 309bfd9d262SDmitri Tikhonov 310bfd9d262SDmitri Tikhonov exit(0); 311bfd9d262SDmitri Tikhonov} 312205a2804SDmitri Tikhonov 313205a2804SDmitri Tikhonov#endif 314