xref: /freebsd/contrib/xz/src/liblzma/common/block_decoder.c (revision af6a5351a1fdb1130f18be6c782c4d48916eb971)
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       block_decoder.c
4 /// \brief      Decodes .xz Blocks
5 //
6 //  Author:     Lasse Collin
7 //
8 //  This file has been put into the public domain.
9 //  You can do whatever you want with this file.
10 //
11 ///////////////////////////////////////////////////////////////////////////////
12 
13 #include "block_decoder.h"
14 #include "filter_decoder.h"
15 #include "check.h"
16 
17 
18 typedef struct {
19 	enum {
20 		SEQ_CODE,
21 		SEQ_PADDING,
22 		SEQ_CHECK,
23 	} sequence;
24 
25 	/// The filters in the chain; initialized with lzma_raw_decoder_init().
26 	lzma_next_coder next;
27 
28 	/// Decoding options; we also write Compressed Size and Uncompressed
29 	/// Size back to this structure when the decoding has been finished.
30 	lzma_block *block;
31 
32 	/// Compressed Size calculated while decoding
33 	lzma_vli compressed_size;
34 
35 	/// Uncompressed Size calculated while decoding
36 	lzma_vli uncompressed_size;
37 
38 	/// Maximum allowed Compressed Size; this takes into account the
39 	/// size of the Block Header and Check fields when Compressed Size
40 	/// is unknown.
41 	lzma_vli compressed_limit;
42 
43 	/// Position when reading the Check field
44 	size_t check_pos;
45 
46 	/// Check of the uncompressed data
47 	lzma_check_state check;
48 
49 	/// True if the integrity check won't be calculated and verified.
50 	bool ignore_check;
51 } lzma_block_coder;
52 
53 
54 static inline bool
55 update_size(lzma_vli *size, lzma_vli add, lzma_vli limit)
56 {
57 	if (limit > LZMA_VLI_MAX)
58 		limit = LZMA_VLI_MAX;
59 
60 	if (limit < *size || limit - *size < add)
61 		return true;
62 
63 	*size += add;
64 
65 	return false;
66 }
67 
68 
69 static inline bool
70 is_size_valid(lzma_vli size, lzma_vli reference)
71 {
72 	return reference == LZMA_VLI_UNKNOWN || reference == size;
73 }
74 
75 
76 static lzma_ret
77 block_decode(void *coder_ptr, const lzma_allocator *allocator,
78 		const uint8_t *restrict in, size_t *restrict in_pos,
79 		size_t in_size, uint8_t *restrict out,
80 		size_t *restrict out_pos, size_t out_size, lzma_action action)
81 {
82 	lzma_block_coder *coder = coder_ptr;
83 
84 	switch (coder->sequence) {
85 	case SEQ_CODE: {
86 		const size_t in_start = *in_pos;
87 		const size_t out_start = *out_pos;
88 
89 		const lzma_ret ret = coder->next.code(coder->next.coder,
90 				allocator, in, in_pos, in_size,
91 				out, out_pos, out_size, action);
92 
93 		const size_t in_used = *in_pos - in_start;
94 		const size_t out_used = *out_pos - out_start;
95 
96 		// NOTE: We compare to compressed_limit here, which prevents
97 		// the total size of the Block growing past LZMA_VLI_MAX.
98 		if (update_size(&coder->compressed_size, in_used,
99 					coder->compressed_limit)
100 				|| update_size(&coder->uncompressed_size,
101 					out_used,
102 					coder->block->uncompressed_size))
103 			return LZMA_DATA_ERROR;
104 
105 		if (!coder->ignore_check)
106 			lzma_check_update(&coder->check, coder->block->check,
107 					out + out_start, out_used);
108 
109 		if (ret != LZMA_STREAM_END)
110 			return ret;
111 
112 		// Compressed and Uncompressed Sizes are now at their final
113 		// values. Verify that they match the values given to us.
114 		if (!is_size_valid(coder->compressed_size,
115 					coder->block->compressed_size)
116 				|| !is_size_valid(coder->uncompressed_size,
117 					coder->block->uncompressed_size))
118 			return LZMA_DATA_ERROR;
119 
120 		// Copy the values into coder->block. The caller
121 		// may use this information to construct Index.
122 		coder->block->compressed_size = coder->compressed_size;
123 		coder->block->uncompressed_size = coder->uncompressed_size;
124 
125 		coder->sequence = SEQ_PADDING;
126 	}
127 
128 	// Fall through
129 
130 	case SEQ_PADDING:
131 		// Compressed Data is padded to a multiple of four bytes.
132 		while (coder->compressed_size & 3) {
133 			if (*in_pos >= in_size)
134 				return LZMA_OK;
135 
136 			// We use compressed_size here just get the Padding
137 			// right. The actual Compressed Size was stored to
138 			// coder->block already, and won't be modified by
139 			// us anymore.
140 			++coder->compressed_size;
141 
142 			if (in[(*in_pos)++] != 0x00)
143 				return LZMA_DATA_ERROR;
144 		}
145 
146 		if (coder->block->check == LZMA_CHECK_NONE)
147 			return LZMA_STREAM_END;
148 
149 		if (!coder->ignore_check)
150 			lzma_check_finish(&coder->check, coder->block->check);
151 
152 		coder->sequence = SEQ_CHECK;
153 
154 	// Fall through
155 
156 	case SEQ_CHECK: {
157 		const size_t check_size = lzma_check_size(coder->block->check);
158 		lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
159 				&coder->check_pos, check_size);
160 		if (coder->check_pos < check_size)
161 			return LZMA_OK;
162 
163 		// Validate the Check only if we support it.
164 		// coder->check.buffer may be uninitialized
165 		// when the Check ID is not supported.
166 		if (!coder->ignore_check
167 				&& lzma_check_is_supported(coder->block->check)
168 				&& memcmp(coder->block->raw_check,
169 					coder->check.buffer.u8,
170 					check_size) != 0)
171 			return LZMA_DATA_ERROR;
172 
173 		return LZMA_STREAM_END;
174 	}
175 	}
176 
177 	return LZMA_PROG_ERROR;
178 }
179 
180 
181 static void
182 block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
183 {
184 	lzma_block_coder *coder = coder_ptr;
185 	lzma_next_end(&coder->next, allocator);
186 	lzma_free(coder, allocator);
187 	return;
188 }
189 
190 
191 extern lzma_ret
192 lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
193 		lzma_block *block)
194 {
195 	lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
196 
197 	// Validate the options. lzma_block_unpadded_size() does that for us
198 	// except for Uncompressed Size and filters. Filters are validated
199 	// by the raw decoder.
200 	if (lzma_block_unpadded_size(block) == 0
201 			|| !lzma_vli_is_valid(block->uncompressed_size))
202 		return LZMA_PROG_ERROR;
203 
204 	// Allocate *next->coder if needed.
205 	lzma_block_coder *coder = next->coder;
206 	if (coder == NULL) {
207 		coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
208 		if (coder == NULL)
209 			return LZMA_MEM_ERROR;
210 
211 		next->coder = coder;
212 		next->code = &block_decode;
213 		next->end = &block_decoder_end;
214 		coder->next = LZMA_NEXT_CODER_INIT;
215 	}
216 
217 	// Basic initializations
218 	coder->sequence = SEQ_CODE;
219 	coder->block = block;
220 	coder->compressed_size = 0;
221 	coder->uncompressed_size = 0;
222 
223 	// If Compressed Size is not known, we calculate the maximum allowed
224 	// value so that encoded size of the Block (including Block Padding)
225 	// is still a valid VLI and a multiple of four.
226 	coder->compressed_limit
227 			= block->compressed_size == LZMA_VLI_UNKNOWN
228 				? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
229 					- block->header_size
230 					- lzma_check_size(block->check)
231 				: block->compressed_size;
232 
233 	// Initialize the check. It's caller's problem if the Check ID is not
234 	// supported, and the Block decoder cannot verify the Check field.
235 	// Caller can test lzma_check_is_supported(block->check).
236 	coder->check_pos = 0;
237 	lzma_check_init(&coder->check, block->check);
238 
239 	coder->ignore_check = block->version >= 1
240 			? block->ignore_check : false;
241 
242 	// Initialize the filter chain.
243 	return lzma_raw_decoder_init(&coder->next, allocator,
244 			block->filters);
245 }
246 
247 
248 extern LZMA_API(lzma_ret)
249 lzma_block_decoder(lzma_stream *strm, lzma_block *block)
250 {
251 	lzma_next_strm_init(lzma_block_decoder_init, strm, block);
252 
253 	strm->internal->supported_actions[LZMA_RUN] = true;
254 	strm->internal->supported_actions[LZMA_FINISH] = true;
255 
256 	return LZMA_OK;
257 }
258