/src/xz/src/liblzma/common/block_decoder.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: 0BSD |
2 | | |
3 | | /////////////////////////////////////////////////////////////////////////////// |
4 | | // |
5 | | /// \file block_decoder.c |
6 | | /// \brief Decodes .xz Blocks |
7 | | // |
8 | | // Author: Lasse Collin |
9 | | // |
10 | | /////////////////////////////////////////////////////////////////////////////// |
11 | | |
12 | | #include "block_decoder.h" |
13 | | #include "filter_decoder.h" |
14 | | #include "check.h" |
15 | | |
16 | | |
17 | | typedef struct { |
18 | | enum { |
19 | | SEQ_CODE, |
20 | | SEQ_PADDING, |
21 | | SEQ_CHECK, |
22 | | } sequence; |
23 | | |
24 | | /// The filters in the chain; initialized with lzma_raw_decoder_init(). |
25 | | lzma_next_coder next; |
26 | | |
27 | | /// Decoding options; we also write Compressed Size and Uncompressed |
28 | | /// Size back to this structure when the decoding has been finished. |
29 | | lzma_block *block; |
30 | | |
31 | | /// Compressed Size calculated while decoding |
32 | | lzma_vli compressed_size; |
33 | | |
34 | | /// Uncompressed Size calculated while decoding |
35 | | lzma_vli uncompressed_size; |
36 | | |
37 | | /// Maximum allowed Compressed Size; this takes into account the |
38 | | /// size of the Block Header and Check fields when Compressed Size |
39 | | /// is unknown. |
40 | | lzma_vli compressed_limit; |
41 | | |
42 | | /// Maximum allowed Uncompressed Size. |
43 | | lzma_vli uncompressed_limit; |
44 | | |
45 | | /// Position when reading the Check field |
46 | | size_t check_pos; |
47 | | |
48 | | /// Check of the uncompressed data |
49 | | lzma_check_state check; |
50 | | |
51 | | /// True if the integrity check won't be calculated and verified. |
52 | | bool ignore_check; |
53 | | } lzma_block_coder; |
54 | | |
55 | | |
56 | | static inline bool |
57 | | is_size_valid(lzma_vli size, lzma_vli reference) |
58 | 8.56k | { |
59 | 8.56k | return reference == LZMA_VLI_UNKNOWN || reference == size; |
60 | 8.56k | } |
61 | | |
62 | | |
63 | | static lzma_ret |
64 | | block_decode(void *coder_ptr, const lzma_allocator *allocator, |
65 | | const uint8_t *restrict in, size_t *restrict in_pos, |
66 | | size_t in_size, uint8_t *restrict out, |
67 | | size_t *restrict out_pos, size_t out_size, lzma_action action) |
68 | 302k | { |
69 | 302k | lzma_block_coder *coder = coder_ptr; |
70 | | |
71 | 302k | switch (coder->sequence) { |
72 | 301k | case SEQ_CODE: { |
73 | 301k | const size_t in_start = *in_pos; |
74 | 301k | const size_t out_start = *out_pos; |
75 | | |
76 | | // Limit the amount of input and output space that we give |
77 | | // to the raw decoder based on the information we have |
78 | | // (or don't have) from Block Header. |
79 | 301k | const size_t in_stop = *in_pos + (size_t)my_min( |
80 | 301k | in_size - *in_pos, |
81 | 301k | coder->compressed_limit - coder->compressed_size); |
82 | 301k | const size_t out_stop = *out_pos + (size_t)my_min( |
83 | 301k | out_size - *out_pos, |
84 | 301k | coder->uncompressed_limit - coder->uncompressed_size); |
85 | | |
86 | 301k | const lzma_ret ret = coder->next.code(coder->next.coder, |
87 | 301k | allocator, in, in_pos, in_stop, |
88 | 301k | out, out_pos, out_stop, action); |
89 | | |
90 | 301k | const size_t in_used = *in_pos - in_start; |
91 | 301k | const size_t out_used = *out_pos - out_start; |
92 | | |
93 | | // Because we have limited the input and output sizes, |
94 | | // we know that these cannot grow too big or overflow. |
95 | 301k | coder->compressed_size += in_used; |
96 | 301k | coder->uncompressed_size += out_used; |
97 | | |
98 | 301k | if (ret == LZMA_OK) { |
99 | 291k | const bool comp_done = coder->compressed_size |
100 | 291k | == coder->block->compressed_size; |
101 | 291k | const bool uncomp_done = coder->uncompressed_size |
102 | 291k | == coder->block->uncompressed_size; |
103 | | |
104 | | // If both input and output amounts match the sizes |
105 | | // in Block Header but we still got LZMA_OK instead |
106 | | // of LZMA_STREAM_END, the file is broken. |
107 | 291k | if (comp_done && uncomp_done) |
108 | 23 | return LZMA_DATA_ERROR; |
109 | | |
110 | | // If the decoder has consumed all the input that it |
111 | | // needs but it still couldn't fill the output buffer |
112 | | // or return LZMA_STREAM_END, the file is broken. |
113 | 291k | if (comp_done && *out_pos < out_size) |
114 | 164 | return LZMA_DATA_ERROR; |
115 | | |
116 | | // If the decoder has produced all the output but |
117 | | // it still didn't return LZMA_STREAM_END or consume |
118 | | // more input (for example, detecting an end of |
119 | | // payload marker may need more input but produce |
120 | | // no output) the file is broken. |
121 | 291k | if (uncomp_done && *in_pos < in_size) |
122 | 66 | return LZMA_DATA_ERROR; |
123 | 291k | } |
124 | | |
125 | | // Don't waste time updating the integrity check if it will be |
126 | | // ignored. Also skip it if no new output was produced. This |
127 | | // avoids null pointer + 0 (undefined behavior) when out == 0. |
128 | 301k | if (!coder->ignore_check && out_used > 0) |
129 | 285k | lzma_check_update(&coder->check, coder->block->check, |
130 | 285k | out + out_start, out_used); |
131 | | |
132 | 301k | if (ret != LZMA_STREAM_END) |
133 | 297k | return ret; |
134 | | |
135 | | // Compressed and Uncompressed Sizes are now at their final |
136 | | // values. Verify that they match the values given to us. |
137 | 4.45k | if (!is_size_valid(coder->compressed_size, |
138 | 4.45k | coder->block->compressed_size) |
139 | 4.45k | || !is_size_valid(coder->uncompressed_size, |
140 | 4.11k | coder->block->uncompressed_size)) |
141 | 573 | return LZMA_DATA_ERROR; |
142 | | |
143 | | // Copy the values into coder->block. The caller |
144 | | // may use this information to construct Index. |
145 | 3.87k | coder->block->compressed_size = coder->compressed_size; |
146 | 3.87k | coder->block->uncompressed_size = coder->uncompressed_size; |
147 | | |
148 | 3.87k | coder->sequence = SEQ_PADDING; |
149 | 3.87k | FALLTHROUGH; |
150 | 3.87k | } |
151 | | |
152 | 4.07k | case SEQ_PADDING: |
153 | | // Compressed Data is padded to a multiple of four bytes. |
154 | 10.1k | while (coder->compressed_size & 3) { |
155 | 6.57k | if (*in_pos >= in_size) |
156 | 290 | return LZMA_OK; |
157 | | |
158 | | // We use compressed_size here just get the Padding |
159 | | // right. The actual Compressed Size was stored to |
160 | | // coder->block already, and won't be modified by |
161 | | // us anymore. |
162 | 6.28k | ++coder->compressed_size; |
163 | | |
164 | 6.28k | if (in[(*in_pos)++] != 0x00) |
165 | 175 | return LZMA_DATA_ERROR; |
166 | 6.28k | } |
167 | | |
168 | 3.60k | if (coder->block->check == LZMA_CHECK_NONE) |
169 | 1.23k | return LZMA_STREAM_END; |
170 | | |
171 | 2.37k | if (!coder->ignore_check) |
172 | 2.37k | lzma_check_finish(&coder->check, coder->block->check); |
173 | | |
174 | 2.37k | coder->sequence = SEQ_CHECK; |
175 | 2.37k | FALLTHROUGH; |
176 | | |
177 | 2.63k | case SEQ_CHECK: { |
178 | 2.63k | const size_t check_size = lzma_check_size(coder->block->check); |
179 | 2.63k | lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check, |
180 | 2.63k | &coder->check_pos, check_size); |
181 | 2.63k | if (coder->check_pos < check_size) |
182 | 386 | return LZMA_OK; |
183 | | |
184 | | // Validate the Check only if we support it. |
185 | | // coder->check.buffer may be uninitialized |
186 | | // when the Check ID is not supported. |
187 | 2.24k | if (!coder->ignore_check |
188 | 2.24k | && lzma_check_is_supported(coder->block->check) |
189 | 2.24k | && memcmp(coder->block->raw_check, |
190 | 498 | coder->check.buffer.u8, |
191 | 498 | check_size) != 0) |
192 | 306 | return LZMA_DATA_ERROR; |
193 | | |
194 | 1.93k | return LZMA_STREAM_END; |
195 | 2.24k | } |
196 | 302k | } |
197 | | |
198 | 0 | return LZMA_PROG_ERROR; |
199 | 302k | } |
200 | | |
201 | | |
202 | | static void |
203 | | block_decoder_end(void *coder_ptr, const lzma_allocator *allocator) |
204 | 11.2k | { |
205 | 11.2k | lzma_block_coder *coder = coder_ptr; |
206 | 11.2k | lzma_next_end(&coder->next, allocator); |
207 | 11.2k | lzma_free(coder, allocator); |
208 | 11.2k | return; |
209 | 11.2k | } |
210 | | |
211 | | |
212 | | extern lzma_ret |
213 | | lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, |
214 | | lzma_block *block) |
215 | 25.1k | { |
216 | 25.1k | lzma_next_coder_init(&lzma_block_decoder_init, next, allocator); |
217 | | |
218 | | // Validate the options. lzma_block_unpadded_size() does that for us |
219 | | // except for Uncompressed Size and filters. Filters are validated |
220 | | // by the raw decoder. |
221 | 25.1k | if (lzma_block_unpadded_size(block) == 0 |
222 | 25.1k | || !lzma_vli_is_valid(block->uncompressed_size)) |
223 | 0 | return LZMA_PROG_ERROR; |
224 | | |
225 | | // Allocate *next->coder if needed. |
226 | 25.1k | lzma_block_coder *coder = next->coder; |
227 | 25.1k | if (coder == NULL) { |
228 | 11.2k | coder = lzma_alloc(sizeof(lzma_block_coder), allocator); |
229 | 11.2k | if (coder == NULL) |
230 | 0 | return LZMA_MEM_ERROR; |
231 | | |
232 | 11.2k | next->coder = coder; |
233 | 11.2k | next->code = &block_decode; |
234 | 11.2k | next->end = &block_decoder_end; |
235 | 11.2k | coder->next = LZMA_NEXT_CODER_INIT; |
236 | 11.2k | } |
237 | | |
238 | | // Basic initializations |
239 | 25.1k | coder->sequence = SEQ_CODE; |
240 | 25.1k | coder->block = block; |
241 | 25.1k | coder->compressed_size = 0; |
242 | 25.1k | coder->uncompressed_size = 0; |
243 | | |
244 | | // If Compressed Size is not known, we calculate the maximum allowed |
245 | | // value so that encoded size of the Block (including Block Padding) |
246 | | // is still a valid VLI and a multiple of four. |
247 | 25.1k | coder->compressed_limit |
248 | 25.1k | = block->compressed_size == LZMA_VLI_UNKNOWN |
249 | 25.1k | ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3)) |
250 | 20.6k | - block->header_size |
251 | 20.6k | - lzma_check_size(block->check) |
252 | 25.1k | : block->compressed_size; |
253 | | |
254 | | // With Uncompressed Size this is simpler. If Block Header lacks |
255 | | // the size info, then LZMA_VLI_MAX is the maximum possible |
256 | | // Uncompressed Size. |
257 | 25.1k | coder->uncompressed_limit |
258 | 25.1k | = block->uncompressed_size == LZMA_VLI_UNKNOWN |
259 | 25.1k | ? LZMA_VLI_MAX |
260 | 25.1k | : block->uncompressed_size; |
261 | | |
262 | | // Initialize the check. It's caller's problem if the Check ID is not |
263 | | // supported, and the Block decoder cannot verify the Check field. |
264 | | // Caller can test lzma_check_is_supported(block->check). |
265 | 25.1k | coder->check_pos = 0; |
266 | 25.1k | lzma_check_init(&coder->check, block->check); |
267 | | |
268 | 25.1k | coder->ignore_check = block->version >= 1 |
269 | 25.1k | ? block->ignore_check : false; |
270 | | |
271 | | // Initialize the filter chain. |
272 | 25.1k | return lzma_raw_decoder_init(&coder->next, allocator, |
273 | 25.1k | block->filters); |
274 | 25.1k | } |
275 | | |
276 | | |
277 | | extern LZMA_API(lzma_ret) |
278 | | lzma_block_decoder(lzma_stream *strm, lzma_block *block) |
279 | 0 | { |
280 | 0 | lzma_next_strm_init(lzma_block_decoder_init, strm, block); |
281 | | |
282 | 0 | strm->internal->supported_actions[LZMA_RUN] = true; |
283 | 0 | strm->internal->supported_actions[LZMA_FINISH] = true; |
284 | |
|
285 | 0 | return LZMA_OK; |
286 | 0 | } |