1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm#include "test.h" 26228763Smm__FBSDID("$FreeBSD$"); 27228753Smm 28228753Smm/* 29228753Smm * This was inspired by an ISO fuzz tester written by Michal Zalewski 30228753Smm * and posted to the "vulnwatch" mailing list on March 17, 2005: 31228753Smm * http://seclists.org/vulnwatch/2005/q1/0088.html 32228753Smm * 33228753Smm * This test simply reads each archive image into memory, pokes 34228753Smm * random values into it and runs it through libarchive. It tries 35228753Smm * to damage about 1% of each file and repeats the exercise 100 times 36228753Smm * with each file. 37228753Smm * 38228753Smm * Unlike most other tests, this test does not verify libarchive's 39228753Smm * responses other than to ensure that libarchive doesn't crash. 40228753Smm * 41228753Smm * Due to the deliberately random nature of this test, it may be hard 42228753Smm * to reproduce failures. Because this test deliberately attempts to 43228753Smm * induce crashes, there's little that can be done in the way of 44228753Smm * post-failure diagnostics. 45228753Smm */ 46228753Smm 47228753Smm/* Because this works for any archive, we can just re-use the archives 48228753Smm * developed for other tests. */ 49248616Smmstruct files { 50228753Smm int uncompress; /* If 1, decompress the file before fuzzing. */ 51248616Smm const char **names; 52228753Smm}; 53228753Smm 54248616Smmstatic void 55248616Smmtest_fuzz(const struct files *filesets) 56228753Smm{ 57228753Smm const void *blk; 58228753Smm size_t blk_size; 59232153Smm int64_t blk_offset; 60228753Smm int n; 61228753Smm 62248616Smm for (n = 0; filesets[n].names != NULL; ++n) { 63228753Smm const size_t buffsize = 30000000; 64228753Smm struct archive_entry *ae; 65228753Smm struct archive *a; 66248616Smm char *rawimage = NULL, *image = NULL, *tmp = NULL; 67248616Smm size_t size = 0, oldsize = 0; 68232153Smm int i, q; 69228753Smm 70248616Smm extract_reference_files(filesets[n].names); 71248616Smm if (filesets[n].uncompress) { 72228753Smm int r; 73228753Smm /* Use format_raw to decompress the data. */ 74228753Smm assert((a = archive_read_new()) != NULL); 75228753Smm assertEqualIntA(a, ARCHIVE_OK, 76232153Smm archive_read_support_filter_all(a)); 77228753Smm assertEqualIntA(a, ARCHIVE_OK, 78228753Smm archive_read_support_format_raw(a)); 79248616Smm r = archive_read_open_filenames(a, filesets[n].names, 16384); 80228753Smm if (r != ARCHIVE_OK) { 81232153Smm archive_read_free(a); 82248616Smm if (filesets[n].names[0] == NULL || filesets[n].names[1] == NULL) { 83248616Smm skipping("Cannot uncompress fileset"); 84248616Smm } else { 85248616Smm skipping("Cannot uncompress %s", filesets[n].names[0]); 86248616Smm } 87228753Smm continue; 88228753Smm } 89228753Smm assertEqualIntA(a, ARCHIVE_OK, 90228753Smm archive_read_next_header(a, &ae)); 91228753Smm rawimage = malloc(buffsize); 92228753Smm size = archive_read_data(a, rawimage, buffsize); 93228753Smm assertEqualIntA(a, ARCHIVE_EOF, 94228753Smm archive_read_next_header(a, &ae)); 95228753Smm assertEqualInt(ARCHIVE_OK, 96232153Smm archive_read_free(a)); 97228753Smm assert(size > 0); 98248616Smm if (filesets[n].names[0] == NULL || filesets[n].names[1] == NULL) { 99248616Smm failure("Internal buffer is not big enough for " 100248616Smm "uncompressed test files"); 101248616Smm } else { 102248616Smm failure("Internal buffer is not big enough for " 103248616Smm "uncompressed test file: %s", filesets[n].names[0]); 104248616Smm } 105228753Smm if (!assert(size < buffsize)) { 106228753Smm free(rawimage); 107228753Smm continue; 108228753Smm } 109228753Smm } else { 110248616Smm for (i = 0; filesets[n].names[i] != NULL; ++i) 111248616Smm { 112248616Smm tmp = slurpfile(&size, filesets[n].names[i]); 113248616Smm rawimage = (char *)realloc(rawimage, oldsize + size); 114248616Smm memcpy(rawimage + oldsize, tmp, size); 115248616Smm oldsize += size; 116248616Smm size = oldsize; 117248616Smm free(tmp); 118248616Smm if (!assert(rawimage != NULL)) 119248616Smm continue; 120248616Smm } 121228753Smm } 122248616Smm if (size == 0) 123248616Smm continue; 124228753Smm image = malloc(size); 125228753Smm assert(image != NULL); 126248616Smm if (image == NULL) 127248616Smm return; 128228753Smm srand((unsigned)time(NULL)); 129228753Smm 130228753Smm for (i = 0; i < 100; ++i) { 131228753Smm FILE *f; 132232153Smm int j, numbytes, trycnt; 133228753Smm 134228753Smm /* Fuzz < 1% of the bytes in the archive. */ 135228753Smm memcpy(image, rawimage, size); 136248616Smm q = (int)size / 100; 137232153Smm if (!q) q = 1; 138232153Smm numbytes = (int)(rand() % q); 139228753Smm for (j = 0; j < numbytes; ++j) 140228753Smm image[rand() % size] = (char)rand(); 141228753Smm 142228753Smm /* Save the messed-up image to a file. 143228753Smm * If we crash, that file will be useful. */ 144232153Smm for (trycnt = 0; trycnt < 3; trycnt++) { 145232153Smm f = fopen("after.test.failure.send.this.file." 146232153Smm "to.libarchive.maintainers.with.system.details", "wb"); 147232153Smm if (f != NULL) 148232153Smm break; 149232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 150232153Smm /* 151232153Smm * Sometimes previous close operation does not completely 152232153Smm * end at this time. So we should take a wait while 153232153Smm * the operation running. 154232153Smm */ 155232153Smm Sleep(100); 156232153Smm#endif 157232153Smm } 158232153Smm assertEqualInt((size_t)size, fwrite(image, 1, (size_t)size, f)); 159228753Smm fclose(f); 160228753Smm 161228753Smm assert((a = archive_read_new()) != NULL); 162228753Smm assertEqualIntA(a, ARCHIVE_OK, 163232153Smm archive_read_support_filter_all(a)); 164228753Smm assertEqualIntA(a, ARCHIVE_OK, 165228753Smm archive_read_support_format_all(a)); 166228753Smm 167228753Smm if (0 == archive_read_open_memory(a, image, size)) { 168228753Smm while(0 == archive_read_next_header(a, &ae)) { 169228753Smm while (0 == archive_read_data_block(a, 170228753Smm &blk, &blk_size, &blk_offset)) 171228753Smm continue; 172228753Smm } 173228753Smm archive_read_close(a); 174228753Smm } 175232153Smm archive_read_free(a); 176228753Smm } 177228753Smm free(image); 178228753Smm free(rawimage); 179228753Smm } 180228753Smm} 181228753Smm 182248616SmmDEFINE_TEST(test_fuzz_ar) 183248616Smm{ 184248616Smm static const char *fileset1[] = { 185248616Smm "test_read_format_ar.ar", 186248616Smm NULL 187248616Smm }; 188248616Smm static const struct files filesets[] = { 189248616Smm {0, fileset1}, 190248616Smm {1, NULL} 191248616Smm }; 192248616Smm test_fuzz(filesets); 193248616Smm} 194228753Smm 195248616SmmDEFINE_TEST(test_fuzz_cab) 196248616Smm{ 197248616Smm static const char *fileset1[] = { 198248616Smm "test_fuzz.cab", 199248616Smm NULL 200248616Smm }; 201248616Smm static const struct files filesets[] = { 202248616Smm {0, fileset1}, 203248616Smm {1, NULL} 204248616Smm }; 205248616Smm test_fuzz(filesets); 206248616Smm} 207248616Smm 208248616SmmDEFINE_TEST(test_fuzz_cpio) 209248616Smm{ 210248616Smm static const char *fileset1[] = { 211248616Smm "test_read_format_cpio_bin_be.cpio", 212248616Smm NULL 213248616Smm }; 214248616Smm static const char *fileset2[] = { 215248616Smm /* Test RPM unwrapper */ 216248616Smm "test_read_format_cpio_svr4_gzip_rpm.rpm", 217248616Smm NULL 218248616Smm }; 219248616Smm static const struct files filesets[] = { 220248616Smm {0, fileset1}, 221248616Smm {0, fileset2}, 222248616Smm {1, NULL} 223248616Smm }; 224248616Smm test_fuzz(filesets); 225248616Smm} 226248616Smm 227248616SmmDEFINE_TEST(test_fuzz_iso9660) 228248616Smm{ 229248616Smm static const char *fileset1[] = { 230248616Smm "test_fuzz_1.iso.Z", 231248616Smm NULL 232248616Smm }; 233248616Smm static const struct files filesets[] = { 234248616Smm {0, fileset1}, /* Exercise compress decompressor. */ 235248616Smm {1, fileset1}, 236248616Smm {1, NULL} 237248616Smm }; 238248616Smm test_fuzz(filesets); 239248616Smm} 240248616Smm 241248616SmmDEFINE_TEST(test_fuzz_lzh) 242248616Smm{ 243248616Smm static const char *fileset1[] = { 244248616Smm "test_fuzz.lzh", 245248616Smm NULL 246248616Smm }; 247248616Smm static const struct files filesets[] = { 248248616Smm {0, fileset1}, 249248616Smm {1, NULL} 250248616Smm }; 251248616Smm test_fuzz(filesets); 252248616Smm} 253248616Smm 254248616SmmDEFINE_TEST(test_fuzz_mtree) 255248616Smm{ 256248616Smm static const char *fileset1[] = { 257248616Smm "test_read_format_mtree.mtree", 258248616Smm NULL 259248616Smm }; 260248616Smm static const struct files filesets[] = { 261248616Smm {0, fileset1}, 262248616Smm {1, NULL} 263248616Smm }; 264248616Smm test_fuzz(filesets); 265248616Smm} 266248616Smm 267248616SmmDEFINE_TEST(test_fuzz_rar) 268248616Smm{ 269248616Smm static const char *fileset1[] = { 270248616Smm /* Uncompressed RAR test */ 271248616Smm "test_read_format_rar.rar", 272248616Smm NULL 273248616Smm }; 274248616Smm static const char *fileset2[] = { 275248616Smm /* RAR file with binary data */ 276248616Smm "test_read_format_rar_binary_data.rar", 277248616Smm NULL 278248616Smm }; 279248616Smm static const char *fileset3[] = { 280248616Smm /* Best Compressed RAR test */ 281248616Smm "test_read_format_rar_compress_best.rar", 282248616Smm NULL 283248616Smm }; 284248616Smm static const char *fileset4[] = { 285248616Smm /* Normal Compressed RAR test */ 286248616Smm "test_read_format_rar_compress_normal.rar", 287248616Smm NULL 288248616Smm }; 289248616Smm static const char *fileset5[] = { 290248616Smm /* Normal Compressed Multi LZSS blocks RAR test */ 291248616Smm "test_read_format_rar_multi_lzss_blocks.rar", 292248616Smm NULL 293248616Smm }; 294248616Smm static const char *fileset6[] = { 295248616Smm /* RAR with no EOF header */ 296248616Smm "test_read_format_rar_noeof.rar", 297248616Smm NULL 298248616Smm }; 299248616Smm static const char *fileset7[] = { 300248616Smm /* Best Compressed RAR file with both PPMd and LZSS blocks */ 301248616Smm "test_read_format_rar_ppmd_lzss_conversion.rar", 302248616Smm NULL 303248616Smm }; 304248616Smm static const char *fileset8[] = { 305248616Smm /* RAR with subblocks */ 306248616Smm "test_read_format_rar_subblock.rar", 307248616Smm NULL 308248616Smm }; 309248616Smm static const char *fileset9[] = { 310248616Smm /* RAR with Unicode filenames */ 311248616Smm "test_read_format_rar_unicode.rar", 312248616Smm NULL 313248616Smm }; 314248616Smm static const char *fileset10[] = { 315248616Smm "test_read_format_rar_multivolume.part0001.rar", 316248616Smm "test_read_format_rar_multivolume.part0002.rar", 317248616Smm "test_read_format_rar_multivolume.part0003.rar", 318248616Smm "test_read_format_rar_multivolume.part0004.rar", 319248616Smm NULL 320248616Smm }; 321248616Smm static const struct files filesets[] = { 322248616Smm {0, fileset1}, 323248616Smm {0, fileset2}, 324248616Smm {0, fileset3}, 325248616Smm {0, fileset4}, 326248616Smm {0, fileset5}, 327248616Smm {0, fileset6}, 328248616Smm {0, fileset7}, 329248616Smm {0, fileset8}, 330248616Smm {0, fileset9}, 331248616Smm {0, fileset10}, 332248616Smm {1, NULL} 333248616Smm }; 334248616Smm test_fuzz(filesets); 335248616Smm} 336248616Smm 337248616SmmDEFINE_TEST(test_fuzz_tar) 338248616Smm{ 339248616Smm static const char *fileset1[] = { 340248616Smm "test_compat_bzip2_1.tbz", 341248616Smm NULL 342248616Smm }; 343248616Smm static const char *fileset2[] = { 344248616Smm "test_compat_gtar_1.tar", 345248616Smm NULL 346248616Smm }; 347248616Smm static const char *fileset3[] = { 348248616Smm "test_compat_gzip_1.tgz", 349248616Smm NULL 350248616Smm }; 351248616Smm static const char *fileset4[] = { 352248616Smm "test_compat_gzip_2.tgz", 353248616Smm NULL 354248616Smm }; 355248616Smm static const char *fileset5[] = { 356248616Smm "test_compat_tar_hardlink_1.tar", 357248616Smm NULL 358248616Smm }; 359248616Smm static const char *fileset6[] = { 360248616Smm "test_compat_xz_1.txz", 361248616Smm NULL 362248616Smm }; 363248616Smm static const char *fileset7[] = { 364248616Smm "test_read_format_gtar_sparse_1_17_posix10_modified.tar", 365248616Smm NULL 366248616Smm }; 367248616Smm static const char *fileset8[] = { 368248616Smm "test_read_format_tar_empty_filename.tar", 369248616Smm NULL 370248616Smm }; 371248616Smm static const char *fileset9[] = { 372248616Smm "test_compat_lzop_1.tar.lzo", 373248616Smm NULL 374248616Smm }; 375248616Smm static const struct files filesets[] = { 376248616Smm {0, fileset1}, /* Exercise bzip2 decompressor. */ 377248616Smm {1, fileset1}, 378248616Smm {0, fileset2}, 379248616Smm {0, fileset3}, /* Exercise gzip decompressor. */ 380248616Smm {0, fileset4}, /* Exercise gzip decompressor. */ 381248616Smm {0, fileset5}, 382248616Smm {0, fileset6}, /* Exercise xz decompressor. */ 383248616Smm {0, fileset7}, 384248616Smm {0, fileset8}, 385248616Smm {0, fileset9}, /* Exercise lzo decompressor. */ 386248616Smm {1, NULL} 387248616Smm }; 388248616Smm test_fuzz(filesets); 389248616Smm} 390248616Smm 391248616SmmDEFINE_TEST(test_fuzz_zip) 392248616Smm{ 393248616Smm static const char *fileset1[] = { 394248616Smm "test_compat_zip_1.zip", 395248616Smm NULL 396248616Smm }; 397248616Smm static const char *fileset2[] = { 398248616Smm "test_read_format_zip.zip", 399248616Smm NULL 400248616Smm }; 401248616Smm static const struct files filesets[] = { 402248616Smm {0, fileset1}, 403248616Smm {0, fileset2}, 404248616Smm {1, NULL} 405248616Smm }; 406248616Smm test_fuzz(filesets); 407248616Smm} 408248616Smm 409