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