xref: /freebsd/contrib/libarchive/libarchive/test/test_write_format_xar_bugs.c (revision 185becb1e1bd2657c156f78aeb52edac05ba5fb5)
1 /*-
2  * Copyright (c) 2025 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 #include "test_fuzz_consumer.h"
27 
28 #include <stdlib.h>
29 
30 /*
31  * Replay a fuzzer binary through the XAR writer, matching the protocol
32  * in fuzzers/custom/fuzz_writer_xar.cc.
33  */
34 static void
replay_xar_writer(const char * refname)35 replay_xar_writer(const char *refname)
36 {
37 	FILE *f;
38 	uint8_t raw[16384];
39 	size_t rawsize;
40 	struct fuzz_consumer consumer;
41 	uint8_t opts, num_entries;
42 	struct archive *a;
43 	struct archive_entry *entry;
44 	size_t used;
45 	char *out_buf;
46 	int i;
47 
48 	extract_reference_file(refname);
49 	f = fopen(refname, "rb");
50 	if (!assert(f != NULL))
51 		return;
52 	rawsize = fread(raw, 1, sizeof(raw), f);
53 	fclose(f);
54 	if (!assert(rawsize >= 6))
55 		return;
56 
57 	fuzz_consumer_init(&consumer, raw, rawsize);
58 	opts = fuzz_consume_byte(&consumer);
59 	num_entries = (fuzz_consume_byte(&consumer) % 5) + 1;
60 
61 	a = archive_write_new();
62 	if (!assert(a != NULL))
63 		return;
64 
65 	archive_write_set_format_xar(a);
66 	archive_write_add_filter_none(a);
67 
68 	if (opts & 0x01)
69 		archive_write_set_options(a, "xar:compression=gzip");
70 	if (opts & 0x02)
71 		archive_write_set_options(a, "xar:compression=bzip2");
72 	if (opts & 0x04)
73 		archive_write_set_options(a, "xar:checksum=sha1");
74 	if (opts & 0x08)
75 		archive_write_set_options(a, "xar:checksum=md5");
76 
77 	out_buf = (char *)malloc(512 * 1024);
78 	if (!assert(out_buf != NULL)) {
79 		archive_write_free(a);
80 		return;
81 	}
82 	if (archive_write_open_memory(a, out_buf, 512 * 1024, &used)
83 	    != ARCHIVE_OK) {
84 		archive_write_free(a);
85 		free(out_buf);
86 		return;
87 	}
88 
89 	entry = archive_entry_new();
90 	if (!assert(entry != NULL)) {
91 		archive_write_free(a);
92 		free(out_buf);
93 		return;
94 	}
95 
96 	for (i = 0; i < num_entries && fuzz_consumer_remaining(&consumer) > 4;
97 	    i++) {
98 		const char *path;
99 		uint8_t ftype;
100 		uint16_t raw_mode;
101 		int64_t file_size = 0;
102 
103 		archive_entry_clear(entry);
104 
105 		path = fuzz_consume_string(&consumer, 200);
106 		if (path[0] == '\0')
107 			path = "file.txt";
108 		archive_entry_set_pathname(entry, path);
109 
110 		ftype = fuzz_consume_byte(&consumer) % 4;
111 		raw_mode = fuzz_consume_u16(&consumer) & 07777;
112 		switch (ftype) {
113 		case 0: archive_entry_set_filetype(entry, AE_IFREG); break;
114 		case 1: archive_entry_set_filetype(entry, AE_IFDIR); break;
115 		case 2: archive_entry_set_filetype(entry, AE_IFLNK); break;
116 		default: archive_entry_set_filetype(entry, AE_IFCHR); break;
117 		}
118 		archive_entry_set_perm(entry, raw_mode);
119 
120 		archive_entry_set_uname(entry,
121 		    fuzz_consume_string(&consumer, 32));
122 		archive_entry_set_gname(entry,
123 		    fuzz_consume_string(&consumer, 32));
124 		archive_entry_set_uid(entry, fuzz_consume_u32(&consumer));
125 		archive_entry_set_gid(entry, fuzz_consume_u32(&consumer));
126 		archive_entry_set_mtime(entry,
127 		    fuzz_consume_i64(&consumer), fuzz_consume_u32(&consumer));
128 		archive_entry_set_atime(entry,
129 		    fuzz_consume_i64(&consumer), 0);
130 		archive_entry_set_ctime(entry,
131 		    fuzz_consume_i64(&consumer), 0);
132 
133 		if (ftype == 0) {
134 			file_size = fuzz_consume_byte(&consumer) % 200;
135 			archive_entry_set_size(entry, file_size);
136 		}
137 
138 		if (ftype == 2)
139 			archive_entry_set_symlink(entry,
140 			    fuzz_consume_string(&consumer, 64));
141 
142 		if (archive_write_header(a, entry) == ARCHIVE_OK
143 		    && file_size > 0) {
144 			size_t write_len = (size_t)file_size;
145 			if (write_len > fuzz_consumer_remaining(&consumer))
146 				write_len = fuzz_consumer_remaining(&consumer);
147 			if (write_len > 0) {
148 				uint8_t file_data[200];
149 				fuzz_consume_bytes(&consumer, file_data,
150 				    write_len);
151 				archive_write_data(a, file_data, write_len);
152 			}
153 		}
154 	}
155 
156 	archive_entry_free(entry);
157 	archive_write_close(a);
158 	archive_write_free(a);
159 	free(out_buf);
160 }
161 
DEFINE_TEST(test_write_format_xar_strcpy_overlap)162 DEFINE_TEST(test_write_format_xar_strcpy_overlap)
163 {
164 	replay_xar_writer("test_write_format_xar_strcpy_overlap.bin");
165 }
166 
DEFINE_TEST(test_write_format_xar_underflow)167 DEFINE_TEST(test_write_format_xar_underflow)
168 {
169 	replay_xar_writer("test_write_format_xar_underflow.bin");
170 }
171