1 /*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 #include "test.h"
26
27 /*
28 * This was inspired by an ISO fuzz tester written by Michal Zalewski
29 * and posted to the "vulnwatch" mailing list on March 17, 2005:
30 * http://seclists.org/vulnwatch/2005/q1/0088.html
31 *
32 * This test simply reads each archive image into memory, pokes
33 * random values into it and runs it through libarchive. It tries
34 * to damage about 1% of each file and repeats the exercise 100 times
35 * with each file.
36 *
37 * Unlike most other tests, this test does not verify libarchive's
38 * responses other than to ensure that libarchive doesn't crash.
39 *
40 * Due to the deliberately random nature of this test, it may be hard
41 * to reproduce failures. Because this test deliberately attempts to
42 * induce crashes, there's little that can be done in the way of
43 * post-failure diagnostics.
44 */
45
46 /* Because this works for any archive, we can just re-use the archives
47 * developed for other tests. */
48 struct files {
49 int uncompress; /* If 1, decompress the file before fuzzing. */
50 const char **names;
51 };
52
53 static void
test_fuzz(const struct files * filesets)54 test_fuzz(const struct files *filesets)
55 {
56 const void *blk;
57 size_t blk_size;
58 int64_t blk_offset;
59 int n;
60 const char *skip_fuzz_tests;
61
62 skip_fuzz_tests = getenv("SKIP_TEST_FUZZ");
63 if (skip_fuzz_tests != NULL) {
64 skipping("Skipping fuzz tests due to SKIP_TEST_FUZZ "
65 "environment variable");
66 return;
67 }
68
69 for (n = 0; filesets[n].names != NULL; ++n) {
70 const size_t buffsize = 30000000;
71 struct archive_entry *ae;
72 struct archive *a;
73 char *rawimage = NULL, *image = NULL, *tmp = NULL;
74 size_t size = 0, oldsize = 0;
75 int i, q;
76
77 extract_reference_files(filesets[n].names);
78 if (filesets[n].uncompress) {
79 int r;
80 /* Use format_raw to decompress the data. */
81 assert((a = archive_read_new()) != NULL);
82 assertEqualIntA(a, ARCHIVE_OK,
83 archive_read_support_filter_all(a));
84 assertEqualIntA(a, ARCHIVE_OK,
85 archive_read_support_format_raw(a));
86 r = archive_read_open_filenames(a, filesets[n].names, 16384);
87 if (r != ARCHIVE_OK) {
88 archive_read_free(a);
89 if (filesets[n].names[0] == NULL || filesets[n].names[1] == NULL) {
90 skipping("Cannot uncompress fileset");
91 } else {
92 skipping("Cannot uncompress %s", filesets[n].names[0]);
93 }
94 continue;
95 }
96 assertEqualIntA(a, ARCHIVE_OK,
97 archive_read_next_header(a, &ae));
98 rawimage = malloc(buffsize);
99 size = archive_read_data(a, rawimage, buffsize);
100 assertEqualIntA(a, ARCHIVE_EOF,
101 archive_read_next_header(a, &ae));
102 assertEqualInt(ARCHIVE_OK,
103 archive_read_free(a));
104 assert(size > 0);
105 if (filesets[n].names[0] == NULL || filesets[n].names[1] == NULL) {
106 failure("Internal buffer is not big enough for "
107 "uncompressed test files");
108 } else {
109 failure("Internal buffer is not big enough for "
110 "uncompressed test file: %s", filesets[n].names[0]);
111 }
112 if (!assert(size < buffsize)) {
113 free(rawimage);
114 rawimage = NULL;
115 continue;
116 }
117 } else {
118 for (i = 0; filesets[n].names[i] != NULL; ++i)
119 {
120 char *newraw;
121 tmp = slurpfile(&size, "%s",
122 filesets[n].names[i]);
123 newraw = realloc(rawimage, oldsize + size);
124 if (newraw == NULL)
125 {
126 free(tmp);
127 size = 0;
128 break;
129 }
130 rawimage = newraw;
131 memcpy(rawimage + oldsize, tmp, size);
132 oldsize += size;
133 size = oldsize;
134 free(tmp);
135 }
136 }
137 if (size == 0) {
138 free(rawimage);
139 rawimage = NULL;
140 continue;
141 }
142 image = malloc(size);
143 assert(image != NULL);
144 if (image == NULL) {
145 free(rawimage);
146 rawimage = NULL;
147 return;
148 }
149
150 assert(rawimage != NULL);
151
152 srand((unsigned)time(NULL));
153
154 for (i = 0; i < 1000; ++i) {
155 FILE *f;
156 int j, numbytes, trycnt;
157
158 /* Fuzz < 1% of the bytes in the archive. */
159 memcpy(image, rawimage, size);
160 q = (int)size / 100;
161 if (q < 4)
162 q = 4;
163 numbytes = (int)(rand() % q);
164 for (j = 0; j < numbytes; ++j)
165 image[rand() % size] = (char)rand();
166
167 /* Save the messed-up image to a file.
168 * If we crash, that file will be useful. */
169 for (trycnt = 0; trycnt < 3; trycnt++) {
170 f = fopen("after.test.failure.send.this.file."
171 "to.libarchive.maintainers.with.system.details", "wb");
172 if (f != NULL)
173 break;
174 #if defined(_WIN32) && !defined(__CYGWIN__)
175 /*
176 * Sometimes previous close operation does not completely
177 * end at this time. So we should take a wait while
178 * the operation running.
179 */
180 Sleep(100);
181 #endif
182 }
183 assert(f != NULL);
184 assertEqualInt((size_t)size, fwrite(image, 1, (size_t)size, f));
185 fclose(f);
186
187 // Try to read all headers and bodies.
188 assert((a = archive_read_new()) != NULL);
189 assertEqualIntA(a, ARCHIVE_OK,
190 archive_read_support_filter_all(a));
191 assertEqualIntA(a, ARCHIVE_OK,
192 archive_read_support_format_all(a));
193
194 if (0 == archive_read_open_memory(a, image, size)) {
195 while(0 == archive_read_next_header(a, &ae)) {
196 while (0 == archive_read_data_block(a,
197 &blk, &blk_size, &blk_offset))
198 continue;
199 }
200 archive_read_close(a);
201 }
202 archive_read_free(a);
203
204 // Just list headers, skip bodies.
205 assert((a = archive_read_new()) != NULL);
206 assertEqualIntA(a, ARCHIVE_OK,
207 archive_read_support_filter_all(a));
208 assertEqualIntA(a, ARCHIVE_OK,
209 archive_read_support_format_all(a));
210
211 if (0 == archive_read_open_memory(a, image, size)) {
212 while(0 == archive_read_next_header(a, &ae)) {
213 }
214 archive_read_close(a);
215 }
216 archive_read_free(a);
217 }
218 free(image);
219 free(rawimage);
220 }
221 }
222
DEFINE_TEST(test_fuzz_ar)223 DEFINE_TEST(test_fuzz_ar)
224 {
225 static const char *fileset1[] = {
226 "test_read_format_ar.ar",
227 NULL
228 };
229 static const struct files filesets[] = {
230 {0, fileset1},
231 {1, NULL}
232 };
233 test_fuzz(filesets);
234 }
235
DEFINE_TEST(test_fuzz_cab)236 DEFINE_TEST(test_fuzz_cab)
237 {
238 static const char *fileset1[] = {
239 "test_fuzz.cab",
240 NULL
241 };
242 static const struct files filesets[] = {
243 {0, fileset1},
244 {1, NULL}
245 };
246 test_fuzz(filesets);
247 }
248
DEFINE_TEST(test_fuzz_cpio)249 DEFINE_TEST(test_fuzz_cpio)
250 {
251 static const char *fileset1[] = {
252 "test_read_format_cpio_bin_be.cpio",
253 NULL
254 };
255 static const char *fileset2[] = {
256 "test_read_format_cpio_bin_le.cpio",
257 NULL
258 };
259 static const char *fileset3[] = {
260 /* Test RPM unwrapper */
261 "test_read_format_cpio_svr4_gzip_rpm.rpm",
262 NULL
263 };
264 static const struct files filesets[] = {
265 {0, fileset1},
266 {0, fileset2},
267 {0, fileset3},
268 {1, NULL}
269 };
270 test_fuzz(filesets);
271 }
272
DEFINE_TEST(test_fuzz_iso9660)273 DEFINE_TEST(test_fuzz_iso9660)
274 {
275 static const char *fileset1[] = {
276 "test_fuzz_1.iso.Z",
277 NULL
278 };
279 static const struct files filesets[] = {
280 {0, fileset1}, /* Exercise compress decompressor. */
281 {1, fileset1},
282 {1, NULL}
283 };
284 test_fuzz(filesets);
285 }
286
DEFINE_TEST(test_fuzz_lzh)287 DEFINE_TEST(test_fuzz_lzh)
288 {
289 static const char *fileset1[] = {
290 "test_fuzz.lzh",
291 NULL
292 };
293 static const struct files filesets[] = {
294 {0, fileset1},
295 {1, NULL}
296 };
297 test_fuzz(filesets);
298 }
299
DEFINE_TEST(test_fuzz_mtree)300 DEFINE_TEST(test_fuzz_mtree)
301 {
302 static const char *fileset1[] = {
303 "test_read_format_mtree.mtree",
304 NULL
305 };
306 static const struct files filesets[] = {
307 {0, fileset1},
308 {1, NULL}
309 };
310 test_fuzz(filesets);
311 }
312
DEFINE_TEST(test_fuzz_rar)313 DEFINE_TEST(test_fuzz_rar)
314 {
315 static const char *fileset1[] = {
316 /* Uncompressed RAR test */
317 "test_read_format_rar.rar",
318 NULL
319 };
320 static const char *fileset2[] = {
321 /* RAR file with binary data */
322 "test_read_format_rar_binary_data.rar",
323 NULL
324 };
325 static const char *fileset3[] = {
326 /* Best Compressed RAR test */
327 "test_read_format_rar_compress_best.rar",
328 NULL
329 };
330 static const char *fileset4[] = {
331 /* Normal Compressed RAR test */
332 "test_read_format_rar_compress_normal.rar",
333 NULL
334 };
335 static const char *fileset5[] = {
336 /* Normal Compressed Multi LZSS blocks RAR test */
337 "test_read_format_rar_multi_lzss_blocks.rar",
338 NULL
339 };
340 static const char *fileset6[] = {
341 /* RAR with no EOF header */
342 "test_read_format_rar_noeof.rar",
343 NULL
344 };
345 static const char *fileset7[] = {
346 /* Best Compressed RAR file with both PPMd and LZSS blocks */
347 "test_read_format_rar_ppmd_lzss_conversion.rar",
348 NULL
349 };
350 static const char *fileset8[] = {
351 /* RAR with subblocks */
352 "test_read_format_rar_subblock.rar",
353 NULL
354 };
355 static const char *fileset9[] = {
356 /* RAR with Unicode filenames */
357 "test_read_format_rar_unicode.rar",
358 NULL
359 };
360 static const char *fileset10[] = {
361 "test_read_format_rar_multivolume.part0001.rar",
362 "test_read_format_rar_multivolume.part0002.rar",
363 "test_read_format_rar_multivolume.part0003.rar",
364 "test_read_format_rar_multivolume.part0004.rar",
365 NULL
366 };
367 static const struct files filesets[] = {
368 {0, fileset1},
369 {0, fileset2},
370 {0, fileset3},
371 {0, fileset4},
372 {0, fileset5},
373 {0, fileset6},
374 {0, fileset7},
375 {0, fileset8},
376 {0, fileset9},
377 {0, fileset10},
378 {1, NULL}
379 };
380 test_fuzz(filesets);
381 }
382
DEFINE_TEST(test_fuzz_tar)383 DEFINE_TEST(test_fuzz_tar)
384 {
385 static const char *fileset1[] = {
386 "test_compat_bzip2_1.tbz",
387 NULL
388 };
389 static const char *fileset2[] = {
390 "test_compat_gtar_1.tar",
391 NULL
392 };
393 static const char *fileset3[] = {
394 "test_compat_gzip_1.tgz",
395 NULL
396 };
397 static const char *fileset4[] = {
398 "test_compat_gzip_2.tgz",
399 NULL
400 };
401 static const char *fileset5[] = {
402 "test_compat_tar_hardlink_1.tar",
403 NULL
404 };
405 static const char *fileset6[] = {
406 "test_compat_xz_1.txz",
407 NULL
408 };
409 static const char *fileset7[] = {
410 "test_read_format_gtar_sparse_1_17_posix10_modified.tar",
411 NULL
412 };
413 static const char *fileset8[] = {
414 "test_read_format_tar_empty_filename.tar",
415 NULL
416 };
417 #if HAVE_LIBLZO2 && HAVE_LZO_LZO1X_H && HAVE_LZO_LZOCONF_H
418 static const char *fileset9[] = {
419 "test_compat_lzop_1.tar.lzo",
420 NULL
421 };
422 #endif
423 #if HAVE_ZSTD_H && HAVE_LIBZSTD
424 static const char *fileset10[] = {
425 "test_compat_zstd_1.tar.zst",
426 NULL
427 };
428 #endif
429 static const char *fileset11[] = {
430 "test_compat_tar_directory_1.tar",
431 NULL
432 };
433 static const struct files filesets[] = {
434 {0, fileset1}, /* Exercise bzip2 decompressor. */
435 {1, fileset1},
436 {0, fileset2},
437 {0, fileset3}, /* Exercise gzip decompressor. */
438 {0, fileset4}, /* Exercise gzip decompressor. */
439 {0, fileset5},
440 {0, fileset6}, /* Exercise xz decompressor. */
441 {0, fileset7},
442 {0, fileset8},
443 #if HAVE_LIBLZO2 && HAVE_LZO_LZO1X_H && HAVE_LZO_LZOCONF_H
444 {0, fileset9}, /* Exercise lzo decompressor. */
445 #endif
446 #if HAVE_ZSTD_H && HAVE_LIBZSTD
447 {0, fileset10}, /* Exercise zstd decompressor. */
448 #endif
449 {0, fileset11},
450 {1, NULL}
451 };
452 test_fuzz(filesets);
453 }
454
DEFINE_TEST(test_fuzz_zip)455 DEFINE_TEST(test_fuzz_zip)
456 {
457 static const char *fileset1[] = {
458 "test_compat_zip_1.zip",
459 NULL
460 };
461 static const char *fileset2[] = {
462 "test_compat_zip_2.zip",
463 NULL
464 };
465 static const char *fileset3[] = {
466 "test_compat_zip_3.zip",
467 NULL
468 };
469 static const char *fileset4[] = {
470 "test_compat_zip_4.zip",
471 NULL
472 };
473 static const char *fileset5[] = {
474 "test_compat_zip_5.zip",
475 NULL
476 };
477 static const char *fileset6[] = {
478 "test_compat_zip_6.zip",
479 NULL
480 };
481 static const char *fileset7[] = {
482 "test_read_format_zip.zip",
483 NULL
484 };
485 static const char *fileset8[] = {
486 "test_read_format_zip_comment_stored_1.zip",
487 NULL
488 };
489 static const char *fileset9[] = {
490 "test_read_format_zip_comment_stored_2.zip",
491 NULL
492 };
493 static const char *fileset10[] = {
494 "test_read_format_zip_encryption_data.zip",
495 NULL
496 };
497 static const char *fileset11[] = {
498 "test_read_format_zip_encryption_header.zip",
499 NULL
500 };
501 static const char *fileset12[] = {
502 "test_read_format_zip_encryption_partially.zip",
503 NULL
504 };
505 static const char *fileset13[] = {
506 "test_read_format_zip_filename_cp866.zip",
507 NULL
508 };
509 static const char *fileset14[] = {
510 "test_read_format_zip_filename_cp932.zip",
511 NULL
512 };
513 static const char *fileset15[] = {
514 "test_read_format_zip_filename_koi8r.zip",
515 NULL
516 };
517 static const char *fileset16[] = {
518 "test_read_format_zip_filename_utf8_jp.zip",
519 NULL
520 };
521 static const char *fileset17[] = {
522 "test_read_format_zip_filename_utf8_ru.zip",
523 NULL
524 };
525 static const char *fileset18[] = {
526 "test_read_format_zip_filename_utf8_ru2.zip",
527 NULL
528 };
529 static const char *fileset19[] = {
530 "test_read_format_zip_length_at_end.zip",
531 NULL
532 };
533 static const char *fileset20[] = {
534 "test_read_format_zip_mac_metadata.zip",
535 NULL
536 };
537 static const char *fileset21[] = {
538 "test_read_format_zip_malformed1.zip",
539 NULL
540 };
541 static const char *fileset22[] = {
542 "test_read_format_zip_msdos.zip",
543 NULL
544 };
545 static const char *fileset23[] = {
546 "test_read_format_zip_nested.zip",
547 NULL
548 };
549 static const char *fileset24[] = {
550 "test_read_format_zip_nofiletype.zip",
551 NULL
552 };
553 static const char *fileset25[] = {
554 "test_read_format_zip_padded1.zip",
555 NULL
556 };
557 static const char *fileset26[] = {
558 "test_read_format_zip_padded2.zip",
559 NULL
560 };
561 static const char *fileset27[] = {
562 "test_read_format_zip_padded3.zip",
563 NULL
564 };
565 static const char *fileset28[] = {
566 "test_read_format_zip_symlink.zip",
567 NULL
568 };
569 static const char *fileset29[] = {
570 "test_read_format_zip_traditional_encryption_data.zip",
571 NULL
572 };
573 static const char *fileset30[] = {
574 "test_read_format_zip_ux.zip",
575 NULL
576 };
577 static const char *fileset31[] = {
578 "test_read_format_zip_winzip_aes128.zip",
579 NULL
580 };
581 static const char *fileset32[] = {
582 "test_read_format_zip_winzip_aes256.zip",
583 NULL
584 };
585 static const char *fileset33[] = {
586 "test_read_format_zip_winzip_aes256_large.zip",
587 NULL
588 };
589 static const char *fileset34[] = {
590 "test_read_format_zip_winzip_aes256_stored.zip",
591 NULL
592 };
593 static const char *fileset35[] = {
594 "test_read_format_zip_zip64a.zip",
595 NULL
596 };
597 static const char *fileset36[] = {
598 "test_read_format_zip_zip64b.zip",
599 NULL
600 };
601
602 static const struct files filesets[] = {
603 {0, fileset1},
604 {0, fileset2},
605 {0, fileset3},
606 {0, fileset4},
607 {0, fileset5},
608 {0, fileset6},
609 {0, fileset7},
610 {0, fileset8},
611 {0, fileset9},
612 {0, fileset10},
613 {0, fileset11},
614 {0, fileset12},
615 {0, fileset13},
616 {0, fileset14},
617 {0, fileset15},
618 {0, fileset16},
619 {0, fileset17},
620 {0, fileset18},
621 {0, fileset19},
622 {0, fileset20},
623 {0, fileset21},
624 {0, fileset22},
625 {0, fileset23},
626 {0, fileset24},
627 {0, fileset25},
628 {0, fileset26},
629 {0, fileset27},
630 {0, fileset28},
631 {0, fileset29},
632 {0, fileset30},
633 {0, fileset31},
634 {0, fileset32},
635 {0, fileset33},
636 {0, fileset34},
637 {0, fileset35},
638 {0, fileset36},
639 {1, NULL}
640 };
641 test_fuzz(filesets);
642 }
643
644