xref: /freebsd/contrib/xz/src/liblzma/common/block_decoder.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
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 struct lzma_coder_s {
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 };
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(lzma_coder *coder, 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 	switch (coder->sequence) {
83 	case SEQ_CODE: {
84 		const size_t in_start = *in_pos;
85 		const size_t out_start = *out_pos;
86 
87 		const lzma_ret ret = coder->next.code(coder->next.coder,
88 				allocator, in, in_pos, in_size,
89 				out, out_pos, out_size, action);
90 
91 		const size_t in_used = *in_pos - in_start;
92 		const size_t out_used = *out_pos - out_start;
93 
94 		// NOTE: We compare to compressed_limit here, which prevents
95 		// the total size of the Block growing past LZMA_VLI_MAX.
96 		if (update_size(&coder->compressed_size, in_used,
97 					coder->compressed_limit)
98 				|| update_size(&coder->uncompressed_size,
99 					out_used,
100 					coder->block->uncompressed_size))
101 			return LZMA_DATA_ERROR;
102 
103 		if (!coder->ignore_check)
104 			lzma_check_update(&coder->check, coder->block->check,
105 					out + out_start, out_used);
106 
107 		if (ret != LZMA_STREAM_END)
108 			return ret;
109 
110 		// Compressed and Uncompressed Sizes are now at their final
111 		// values. Verify that they match the values given to us.
112 		if (!is_size_valid(coder->compressed_size,
113 					coder->block->compressed_size)
114 				|| !is_size_valid(coder->uncompressed_size,
115 					coder->block->uncompressed_size))
116 			return LZMA_DATA_ERROR;
117 
118 		// Copy the values into coder->block. The caller
119 		// may use this information to construct Index.
120 		coder->block->compressed_size = coder->compressed_size;
121 		coder->block->uncompressed_size = coder->uncompressed_size;
122 
123 		coder->sequence = SEQ_PADDING;
124 	}
125 
126 	// Fall through
127 
128 	case SEQ_PADDING:
129 		// Compressed Data is padded to a multiple of four bytes.
130 		while (coder->compressed_size & 3) {
131 			if (*in_pos >= in_size)
132 				return LZMA_OK;
133 
134 			// We use compressed_size here just get the Padding
135 			// right. The actual Compressed Size was stored to
136 			// coder->block already, and won't be modified by
137 			// us anymore.
138 			++coder->compressed_size;
139 
140 			if (in[(*in_pos)++] != 0x00)
141 				return LZMA_DATA_ERROR;
142 		}
143 
144 		if (coder->block->check == LZMA_CHECK_NONE)
145 			return LZMA_STREAM_END;
146 
147 		if (!coder->ignore_check)
148 			lzma_check_finish(&coder->check, coder->block->check);
149 
150 		coder->sequence = SEQ_CHECK;
151 
152 	// Fall through
153 
154 	case SEQ_CHECK: {
155 		const size_t check_size = lzma_check_size(coder->block->check);
156 		lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
157 				&coder->check_pos, check_size);
158 		if (coder->check_pos < check_size)
159 			return LZMA_OK;
160 
161 		// Validate the Check only if we support it.
162 		// coder->check.buffer may be uninitialized
163 		// when the Check ID is not supported.
164 		if (!coder->ignore_check
165 				&& lzma_check_is_supported(coder->block->check)
166 				&& memcmp(coder->block->raw_check,
167 					coder->check.buffer.u8,
168 					check_size) != 0)
169 			return LZMA_DATA_ERROR;
170 
171 		return LZMA_STREAM_END;
172 	}
173 	}
174 
175 	return LZMA_PROG_ERROR;
176 }
177 
178 
179 static void
180 block_decoder_end(lzma_coder *coder, const lzma_allocator *allocator)
181 {
182 	lzma_next_end(&coder->next, allocator);
183 	lzma_free(coder, allocator);
184 	return;
185 }
186 
187 
188 extern lzma_ret
189 lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
190 		lzma_block *block)
191 {
192 	lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
193 
194 	// Validate the options. lzma_block_unpadded_size() does that for us
195 	// except for Uncompressed Size and filters. Filters are validated
196 	// by the raw decoder.
197 	if (lzma_block_unpadded_size(block) == 0
198 			|| !lzma_vli_is_valid(block->uncompressed_size))
199 		return LZMA_PROG_ERROR;
200 
201 	// Allocate and initialize *next->coder if needed.
202 	if (next->coder == NULL) {
203 		next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
204 		if (next->coder == NULL)
205 			return LZMA_MEM_ERROR;
206 
207 		next->code = &block_decode;
208 		next->end = &block_decoder_end;
209 		next->coder->next = LZMA_NEXT_CODER_INIT;
210 	}
211 
212 	// Basic initializations
213 	next->coder->sequence = SEQ_CODE;
214 	next->coder->block = block;
215 	next->coder->compressed_size = 0;
216 	next->coder->uncompressed_size = 0;
217 
218 	// If Compressed Size is not known, we calculate the maximum allowed
219 	// value so that encoded size of the Block (including Block Padding)
220 	// is still a valid VLI and a multiple of four.
221 	next->coder->compressed_limit
222 			= block->compressed_size == LZMA_VLI_UNKNOWN
223 				? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
224 					- block->header_size
225 					- lzma_check_size(block->check)
226 				: block->compressed_size;
227 
228 	// Initialize the check. It's caller's problem if the Check ID is not
229 	// supported, and the Block decoder cannot verify the Check field.
230 	// Caller can test lzma_check_is_supported(block->check).
231 	next->coder->check_pos = 0;
232 	lzma_check_init(&next->coder->check, block->check);
233 
234 	next->coder->ignore_check = block->version >= 1
235 			? block->ignore_check : false;
236 
237 	// Initialize the filter chain.
238 	return lzma_raw_decoder_init(&next->coder->next, allocator,
239 			block->filters);
240 }
241 
242 
243 extern LZMA_API(lzma_ret)
244 lzma_block_decoder(lzma_stream *strm, lzma_block *block)
245 {
246 	lzma_next_strm_init(lzma_block_decoder_init, strm, block);
247 
248 	strm->internal->supported_actions[LZMA_RUN] = true;
249 	strm->internal->supported_actions[LZMA_FINISH] = true;
250 
251 	return LZMA_OK;
252 }
253