/src/xz/src/liblzma/common/alone_decoder.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: 0BSD |
2 | | |
3 | | /////////////////////////////////////////////////////////////////////////////// |
4 | | // |
5 | | /// \file alone_decoder.c |
6 | | /// \brief Decoder for LZMA_Alone files |
7 | | // |
8 | | // Author: Lasse Collin |
9 | | // |
10 | | /////////////////////////////////////////////////////////////////////////////// |
11 | | |
12 | | #include "alone_decoder.h" |
13 | | #include "lzma_decoder.h" |
14 | | #include "lz_decoder.h" |
15 | | |
16 | | |
17 | | typedef struct { |
18 | | lzma_next_coder next; |
19 | | |
20 | | enum { |
21 | | SEQ_PROPERTIES, |
22 | | SEQ_DICTIONARY_SIZE, |
23 | | SEQ_UNCOMPRESSED_SIZE, |
24 | | SEQ_CODER_INIT, |
25 | | SEQ_CODE, |
26 | | } sequence; |
27 | | |
28 | | /// If true, reject files that are unlikely to be .lzma files. |
29 | | /// If false, more non-.lzma files get accepted and will give |
30 | | /// LZMA_DATA_ERROR either immediately or after a few output bytes. |
31 | | bool picky; |
32 | | |
33 | | /// Position in the header fields |
34 | | size_t pos; |
35 | | |
36 | | /// Uncompressed size decoded from the header |
37 | | lzma_vli uncompressed_size; |
38 | | |
39 | | /// Memory usage limit |
40 | | uint64_t memlimit; |
41 | | |
42 | | /// Amount of memory actually needed (only an estimate) |
43 | | uint64_t memusage; |
44 | | |
45 | | /// Options decoded from the header needed to initialize |
46 | | /// the LZMA decoder |
47 | | lzma_options_lzma options; |
48 | | } lzma_alone_coder; |
49 | | |
50 | | |
51 | | static lzma_ret |
52 | | alone_decode(void *coder_ptr, const lzma_allocator *allocator, |
53 | | const uint8_t *restrict in, size_t *restrict in_pos, |
54 | | size_t in_size, uint8_t *restrict out, |
55 | | size_t *restrict out_pos, size_t out_size, |
56 | | lzma_action action) |
57 | 66.6k | { |
58 | 66.6k | lzma_alone_coder *coder = coder_ptr; |
59 | | |
60 | 98.5k | while (*out_pos < out_size |
61 | 98.5k | && (coder->sequence == SEQ_CODE || *in_pos < in_size)) |
62 | 98.0k | switch (coder->sequence) { |
63 | 2.52k | case SEQ_PROPERTIES: |
64 | 2.52k | if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos])) |
65 | 6 | return LZMA_FORMAT_ERROR; |
66 | | |
67 | 2.51k | coder->sequence = SEQ_DICTIONARY_SIZE; |
68 | 2.51k | ++*in_pos; |
69 | 2.51k | break; |
70 | | |
71 | 10.0k | case SEQ_DICTIONARY_SIZE: |
72 | 10.0k | coder->options.dict_size |
73 | 10.0k | |= (size_t)(in[*in_pos]) << (coder->pos * 8); |
74 | | |
75 | 10.0k | if (++coder->pos == 4) { |
76 | 2.49k | if (coder->picky && coder->options.dict_size |
77 | 2.49k | != UINT32_MAX) { |
78 | | // A hack to ditch tons of false positives: |
79 | | // We allow only dictionary sizes that are |
80 | | // 2^n or 2^n + 2^(n-1). LZMA_Alone created |
81 | | // only files with 2^n, but accepts any |
82 | | // dictionary size. |
83 | 2.48k | uint32_t d = coder->options.dict_size - 1; |
84 | 2.48k | d |= d >> 2; |
85 | 2.48k | d |= d >> 3; |
86 | 2.48k | d |= d >> 4; |
87 | 2.48k | d |= d >> 8; |
88 | 2.48k | d |= d >> 16; |
89 | 2.48k | ++d; |
90 | | |
91 | 2.48k | if (d != coder->options.dict_size) |
92 | 52 | return LZMA_FORMAT_ERROR; |
93 | 2.48k | } |
94 | | |
95 | 2.44k | coder->pos = 0; |
96 | 2.44k | coder->sequence = SEQ_UNCOMPRESSED_SIZE; |
97 | 2.44k | } |
98 | | |
99 | 9.95k | ++*in_pos; |
100 | 9.95k | break; |
101 | | |
102 | 19.4k | case SEQ_UNCOMPRESSED_SIZE: |
103 | 19.4k | coder->uncompressed_size |
104 | 19.4k | |= (lzma_vli)(in[*in_pos]) << (coder->pos * 8); |
105 | 19.4k | ++*in_pos; |
106 | 19.4k | if (++coder->pos < 8) |
107 | 17.0k | break; |
108 | | |
109 | | // Another hack to ditch false positives: Assume that |
110 | | // if the uncompressed size is known, it must be less |
111 | | // than 256 GiB. |
112 | | // |
113 | | // FIXME? Without picky we allow > LZMA_VLI_MAX which doesn't |
114 | | // really matter in this specific situation (> LZMA_VLI_MAX is |
115 | | // safe in the LZMA decoder) but it's somewhat weird still. |
116 | 2.43k | if (coder->picky |
117 | 2.43k | && coder->uncompressed_size != LZMA_VLI_UNKNOWN |
118 | 2.43k | && coder->uncompressed_size |
119 | 2.33k | >= (LZMA_VLI_C(1) << 38)) |
120 | 107 | return LZMA_FORMAT_ERROR; |
121 | | |
122 | | // Use LZMA_FILTER_LZMA1EXT features to specify the |
123 | | // uncompressed size and that the end marker is allowed |
124 | | // even when the uncompressed size is known. Both .lzma |
125 | | // header and LZMA1EXT use UINT64_MAX indicate that size |
126 | | // is unknown. |
127 | 2.32k | coder->options.ext_flags = LZMA_LZMA1EXT_ALLOW_EOPM; |
128 | 2.32k | lzma_set_ext_size(coder->options, coder->uncompressed_size); |
129 | | |
130 | | // Calculate the memory usage so that it is ready |
131 | | // for SEQ_CODER_INIT. |
132 | 2.32k | coder->memusage = lzma_lzma_decoder_memusage(&coder->options) |
133 | 2.32k | + LZMA_MEMUSAGE_BASE; |
134 | | |
135 | 2.32k | coder->pos = 0; |
136 | 2.32k | coder->sequence = SEQ_CODER_INIT; |
137 | 2.32k | FALLTHROUGH; |
138 | | |
139 | 2.32k | case SEQ_CODER_INIT: { |
140 | 2.32k | if (coder->memusage > coder->memlimit) |
141 | 0 | return LZMA_MEMLIMIT_ERROR; |
142 | | |
143 | 2.32k | lzma_filter_info filters[2] = { |
144 | 2.32k | { |
145 | 2.32k | .id = LZMA_FILTER_LZMA1EXT, |
146 | 2.32k | .init = &lzma_lzma_decoder_init, |
147 | 2.32k | .options = &coder->options, |
148 | 2.32k | }, { |
149 | 2.32k | .init = NULL, |
150 | 2.32k | } |
151 | 2.32k | }; |
152 | | |
153 | 2.32k | return_if_error(lzma_next_filter_init(&coder->next, |
154 | 2.32k | allocator, filters)); |
155 | | |
156 | 2.31k | coder->sequence = SEQ_CODE; |
157 | 2.31k | break; |
158 | 2.32k | } |
159 | | |
160 | 65.9k | case SEQ_CODE: { |
161 | 65.9k | return coder->next.code(coder->next.coder, |
162 | 65.9k | allocator, in, in_pos, in_size, |
163 | 65.9k | out, out_pos, out_size, action); |
164 | 2.32k | } |
165 | | |
166 | 0 | default: |
167 | 0 | return LZMA_PROG_ERROR; |
168 | 98.0k | } |
169 | | |
170 | 498 | return LZMA_OK; |
171 | 66.6k | } |
172 | | |
173 | | |
174 | | static void |
175 | | alone_decoder_end(void *coder_ptr, const lzma_allocator *allocator) |
176 | 2.52k | { |
177 | 2.52k | lzma_alone_coder *coder = coder_ptr; |
178 | 2.52k | lzma_next_end(&coder->next, allocator); |
179 | 2.52k | lzma_free(coder, allocator); |
180 | 2.52k | return; |
181 | 2.52k | } |
182 | | |
183 | | |
184 | | static lzma_ret |
185 | | alone_decoder_memconfig(void *coder_ptr, uint64_t *memusage, |
186 | | uint64_t *old_memlimit, uint64_t new_memlimit) |
187 | 0 | { |
188 | 0 | lzma_alone_coder *coder = coder_ptr; |
189 | |
|
190 | 0 | *memusage = coder->memusage; |
191 | 0 | *old_memlimit = coder->memlimit; |
192 | |
|
193 | 0 | if (new_memlimit != 0) { |
194 | 0 | if (new_memlimit < coder->memusage) |
195 | 0 | return LZMA_MEMLIMIT_ERROR; |
196 | | |
197 | 0 | coder->memlimit = new_memlimit; |
198 | 0 | } |
199 | | |
200 | 0 | return LZMA_OK; |
201 | 0 | } |
202 | | |
203 | | |
204 | | extern lzma_ret |
205 | | lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator, |
206 | | uint64_t memlimit, bool picky) |
207 | 2.52k | { |
208 | 2.52k | lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator); |
209 | | |
210 | 2.52k | lzma_alone_coder *coder = next->coder; |
211 | | |
212 | 2.52k | if (coder == NULL) { |
213 | 2.52k | coder = lzma_alloc(sizeof(lzma_alone_coder), allocator); |
214 | 2.52k | if (coder == NULL) |
215 | 0 | return LZMA_MEM_ERROR; |
216 | | |
217 | 2.52k | next->coder = coder; |
218 | 2.52k | next->code = &alone_decode; |
219 | 2.52k | next->end = &alone_decoder_end; |
220 | 2.52k | next->memconfig = &alone_decoder_memconfig; |
221 | 2.52k | coder->next = LZMA_NEXT_CODER_INIT; |
222 | 2.52k | } |
223 | | |
224 | 2.52k | coder->sequence = SEQ_PROPERTIES; |
225 | 2.52k | coder->picky = picky; |
226 | 2.52k | coder->pos = 0; |
227 | 2.52k | coder->options.dict_size = 0; |
228 | 2.52k | coder->options.preset_dict = NULL; |
229 | 2.52k | coder->options.preset_dict_size = 0; |
230 | 2.52k | coder->uncompressed_size = 0; |
231 | 2.52k | coder->memlimit = my_max(1, memlimit); |
232 | 2.52k | coder->memusage = LZMA_MEMUSAGE_BASE; |
233 | | |
234 | 2.52k | return LZMA_OK; |
235 | 2.52k | } |
236 | | |
237 | | |
238 | | extern LZMA_API(lzma_ret) |
239 | | lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit) |
240 | 0 | { |
241 | 0 | lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit, false); |
242 | | |
243 | 0 | strm->internal->supported_actions[LZMA_RUN] = true; |
244 | 0 | strm->internal->supported_actions[LZMA_FINISH] = true; |
245 | |
|
246 | 0 | return LZMA_OK; |
247 | 0 | } |