/src/barebox/lib/decompress_unxz.c
Line | Count | Source |
1 | | /* |
2 | | * Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd |
3 | | * |
4 | | * Author: Lasse Collin <lasse.collin@tukaani.org> |
5 | | * |
6 | | * This file has been put into the public domain. |
7 | | * You can do whatever you want with this file. |
8 | | */ |
9 | | |
10 | | /* |
11 | | * Important notes about in-place decompression |
12 | | * |
13 | | * At least on x86, the kernel is decompressed in place: the compressed data |
14 | | * is placed to the end of the output buffer, and the decompressor overwrites |
15 | | * most of the compressed data. There must be enough safety margin to |
16 | | * guarantee that the write position is always behind the read position. |
17 | | * |
18 | | * The safety margin for XZ with LZMA2 or BCJ+LZMA2 is calculated below. |
19 | | * Note that the margin with XZ is bigger than with Deflate (gzip)! |
20 | | * |
21 | | * The worst case for in-place decompression is that the beginning of |
22 | | * the file is compressed extremely well, and the rest of the file is |
23 | | * uncompressible. Thus, we must look for worst-case expansion when the |
24 | | * compressor is encoding uncompressible data. |
25 | | * |
26 | | * The structure of the .xz file in case of a compresed kernel is as follows. |
27 | | * Sizes (as bytes) of the fields are in parenthesis. |
28 | | * |
29 | | * Stream Header (12) |
30 | | * Block Header: |
31 | | * Block Header (8-12) |
32 | | * Compressed Data (N) |
33 | | * Block Padding (0-3) |
34 | | * CRC32 (4) |
35 | | * Index (8-20) |
36 | | * Stream Footer (12) |
37 | | * |
38 | | * Normally there is exactly one Block, but let's assume that there are |
39 | | * 2-4 Blocks just in case. Because Stream Header and also Block Header |
40 | | * of the first Block don't make the decompressor produce any uncompressed |
41 | | * data, we can ignore them from our calculations. Block Headers of possible |
42 | | * additional Blocks have to be taken into account still. With these |
43 | | * assumptions, it is safe to assume that the total header overhead is |
44 | | * less than 128 bytes. |
45 | | * |
46 | | * Compressed Data contains LZMA2 or BCJ+LZMA2 encoded data. Since BCJ |
47 | | * doesn't change the size of the data, it is enough to calculate the |
48 | | * safety margin for LZMA2. |
49 | | * |
50 | | * LZMA2 stores the data in chunks. Each chunk has a header whose size is |
51 | | * a maximum of 6 bytes, but to get round 2^n numbers, let's assume that |
52 | | * the maximum chunk header size is 8 bytes. After the chunk header, there |
53 | | * may be up to 64 KiB of actual payload in the chunk. Often the payload is |
54 | | * quite a bit smaller though; to be safe, let's assume that an average |
55 | | * chunk has only 32 KiB of payload. |
56 | | * |
57 | | * The maximum uncompressed size of the payload is 2 MiB. The minimum |
58 | | * uncompressed size of the payload is in practice never less than the |
59 | | * payload size itself. The LZMA2 format would allow uncompressed size |
60 | | * to be less than the payload size, but no sane compressor creates such |
61 | | * files. LZMA2 supports storing uncompressible data in uncompressed form, |
62 | | * so there's never a need to create payloads whose uncompressed size is |
63 | | * smaller than the compressed size. |
64 | | * |
65 | | * The assumption, that the uncompressed size of the payload is never |
66 | | * smaller than the payload itself, is valid only when talking about |
67 | | * the payload as a whole. It is possible that the payload has parts where |
68 | | * the decompressor consumes more input than it produces output. Calculating |
69 | | * the worst case for this would be tricky. Instead of trying to do that, |
70 | | * let's simply make sure that the decompressor never overwrites any bytes |
71 | | * of the payload which it is currently reading. |
72 | | * |
73 | | * Now we have enough information to calculate the safety margin. We need |
74 | | * - 128 bytes for the .xz file format headers; |
75 | | * - 8 bytes per every 32 KiB of uncompressed size (one LZMA2 chunk header |
76 | | * per chunk, each chunk having average payload size of 32 KiB); and |
77 | | * - 64 KiB (biggest possible LZMA2 chunk payload size) to make sure that |
78 | | * the decompressor never overwrites anything from the LZMA2 chunk |
79 | | * payload it is currently reading. |
80 | | * |
81 | | * We get the following formula: |
82 | | * |
83 | | * safety_margin = 128 + uncompressed_size * 8 / 32768 + 65536 |
84 | | * = 128 + (uncompressed_size >> 12) + 65536 |
85 | | * |
86 | | * For comparison, according to arch/x86/boot/compressed/misc.c, the |
87 | | * equivalent formula for Deflate is this: |
88 | | * |
89 | | * safety_margin = 18 + (uncompressed_size >> 12) + 32768 |
90 | | * |
91 | | * Thus, when updating Deflate-only in-place kernel decompressor to |
92 | | * support XZ, the fixed overhead has to be increased from 18+32768 bytes |
93 | | * to 128+65536 bytes. |
94 | | */ |
95 | | |
96 | | /* |
97 | | * STATIC is defined to "static" if we are being built for kernel |
98 | | * decompression (pre-boot code). <linux/decompress/mm.h> will define |
99 | | * STATIC to empty if it wasn't already defined. Since we will need to |
100 | | * know later if we are being used for kernel decompression, we define |
101 | | * XZ_PREBOOT here. |
102 | | */ |
103 | | #ifdef STATIC |
104 | | # define XZ_PREBOOT |
105 | | #endif |
106 | | #ifdef __KERNEL__ |
107 | | # include <linux/decompress/mm.h> |
108 | | #endif |
109 | | #define XZ_EXTERN STATIC |
110 | | |
111 | | #ifndef XZ_PREBOOT |
112 | 2.09k | #define FREE free |
113 | 2.09k | #define MALLOC malloc |
114 | | # include <malloc.h> |
115 | | # include <linux/xz.h> |
116 | | #else |
117 | | /* |
118 | | * Use the internal CRC32 code instead of kernel's CRC32 module, which |
119 | | * is not available in early phase of booting. |
120 | | */ |
121 | | #define XZ_INTERNAL_CRC32 1 |
122 | | |
123 | | /* |
124 | | * For boot time use, we enable only the BCJ filter of the current |
125 | | * architecture or none if no BCJ filter is available for the architecture. |
126 | | */ |
127 | | #ifdef CONFIG_X86 |
128 | | # define XZ_DEC_X86 |
129 | | #endif |
130 | | #ifdef CONFIG_PPC |
131 | | # define XZ_DEC_POWERPC |
132 | | #endif |
133 | | #ifdef CONFIG_ARM |
134 | | # ifdef CONFIG_ARM64 |
135 | | # define XZ_DEC_ARM64 |
136 | | # elif defined CONFIG_THUMB2_BAREBOX |
137 | | # define XZ_DEC_ARMTHUMB |
138 | | # else |
139 | | # define XZ_DEC_ARM |
140 | | # endif |
141 | | #endif |
142 | | #ifdef CONFIG_IA64 |
143 | | # define XZ_DEC_IA64 |
144 | | #endif |
145 | | #ifdef CONFIG_SPARC |
146 | | # define XZ_DEC_SPARC |
147 | | #endif |
148 | | |
149 | | /* |
150 | | * This will get the basic headers so that memeq() and others |
151 | | * can be defined. |
152 | | */ |
153 | | #include "xz/xz_private.h" |
154 | | |
155 | | /* |
156 | | * Replace the normal allocation functions with the versions from |
157 | | * <linux/decompress/mm.h>. vfree() needs to support vfree(NULL) |
158 | | * when XZ_DYNALLOC is used, but the pre-boot free() doesn't support it. |
159 | | * Workaround it here because the other decompressors don't need it. |
160 | | */ |
161 | | #undef kmalloc |
162 | | #undef kfree |
163 | | #undef vmalloc |
164 | | #undef vfree |
165 | | #define kmalloc(size, flags) malloc(size) |
166 | | #define kfree(ptr) free(ptr) |
167 | | #define vmalloc(size) malloc(size) |
168 | | #define vfree(ptr) do { if (ptr != NULL) free(ptr); } while (0) |
169 | | |
170 | | /* |
171 | | * FIXME: Not all basic memory functions are provided in architecture-specific |
172 | | * files (yet). We define our own versions here for now, but this should be |
173 | | * only a temporary solution. |
174 | | * |
175 | | * memeq and memzero are not used much and any remotely sane implementation |
176 | | * is fast enough. memcpy/memmove speed matters in multi-call mode, but |
177 | | * the kernel image is decompressed in single-call mode, in which only |
178 | | * memcpy speed can matter and only if there is a lot of uncompressible data |
179 | | * (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the |
180 | | * functions below should just be kept small; it's probably not worth |
181 | | * optimizing for speed. |
182 | | */ |
183 | | |
184 | | #ifndef memeq |
185 | | static bool memeq(const void *a, const void *b, size_t size) |
186 | | { |
187 | | const uint8_t *x = a; |
188 | | const uint8_t *y = b; |
189 | | size_t i; |
190 | | |
191 | | for (i = 0; i < size; ++i) |
192 | | if (x[i] != y[i]) |
193 | | return false; |
194 | | |
195 | | return true; |
196 | | } |
197 | | #endif |
198 | | |
199 | | #ifndef memzero |
200 | | static void memzero(void *buf, size_t size) |
201 | | { |
202 | | uint8_t *b = buf; |
203 | | uint8_t *e = b + size; |
204 | | |
205 | | while (b != e) |
206 | | *b++ = '\0'; |
207 | | } |
208 | | #endif |
209 | | |
210 | | /* |
211 | | * Since we need memmove anyway, would use it as memcpy too. |
212 | | * Commented out for now to avoid breaking things. |
213 | | */ |
214 | | /* |
215 | | #ifndef memcpy |
216 | | # define memcpy memmove |
217 | | #endif |
218 | | */ |
219 | | |
220 | | #include "xz/xz_crc32.c" |
221 | | #include "xz/xz_dec_stream.c" |
222 | | #include "xz/xz_dec_lzma2.c" |
223 | | #include "xz/xz_dec_bcj.c" |
224 | | |
225 | | #endif /* XZ_PREBOOT */ |
226 | | |
227 | | /* Size of the input and output buffers in multi-call mode */ |
228 | 4.18k | #define XZ_IOBUF_SIZE 4096 |
229 | | |
230 | | /* |
231 | | * This function implements the API defined in <linux/decompress/generic.h>. |
232 | | * |
233 | | * This wrapper will automatically choose single-call or multi-call mode |
234 | | * of the native XZ decoder API. The single-call mode can be used only when |
235 | | * both input and output buffers are available as a single chunk, i.e. when |
236 | | * fill() and flush() won't be used. |
237 | | */ |
238 | | STATIC int decompress_unxz(unsigned char *in, long in_size, |
239 | | long (*fill)(void *dest, unsigned long size), |
240 | | long (*flush)(void *src, unsigned long size), |
241 | | unsigned char *out, long *in_used, |
242 | | void (*error)(char *x)) |
243 | 2.09k | { |
244 | 2.09k | struct xz_buf b; |
245 | 2.09k | struct xz_dec *s; |
246 | 2.09k | enum xz_ret ret; |
247 | 2.09k | bool must_free_in = false; |
248 | | |
249 | 2.09k | #if XZ_INTERNAL_CRC32 |
250 | 2.09k | xz_crc32_init(); |
251 | 2.09k | #endif |
252 | | |
253 | 2.09k | if (in_used != NULL) |
254 | 0 | *in_used = 0; |
255 | | |
256 | 2.09k | if (fill == NULL && flush == NULL) |
257 | 0 | s = xz_dec_init(XZ_SINGLE, 0); |
258 | 2.09k | else |
259 | 2.09k | s = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1); |
260 | | |
261 | 2.09k | if (s == NULL) |
262 | 0 | goto error_alloc_state; |
263 | | |
264 | 2.09k | if (flush == NULL) { |
265 | 0 | b.out = out; |
266 | 0 | b.out_size = (size_t)-1; |
267 | 2.09k | } else { |
268 | 2.09k | b.out_size = XZ_IOBUF_SIZE; |
269 | 2.09k | b.out = MALLOC(XZ_IOBUF_SIZE); |
270 | 2.09k | if (b.out == NULL) |
271 | 0 | goto error_alloc_out; |
272 | 2.09k | } |
273 | | |
274 | 2.09k | if (in == NULL) { |
275 | 0 | must_free_in = true; |
276 | 0 | in = MALLOC(XZ_IOBUF_SIZE); |
277 | 0 | if (in == NULL) |
278 | 0 | goto error_alloc_in; |
279 | 0 | } |
280 | | |
281 | 2.09k | b.in = in; |
282 | 2.09k | b.in_pos = 0; |
283 | 2.09k | b.in_size = in_size; |
284 | 2.09k | b.out_pos = 0; |
285 | | |
286 | 2.09k | if (fill == NULL && flush == NULL) { |
287 | 0 | ret = xz_dec_run(s, &b); |
288 | 2.09k | } else { |
289 | 20.6k | do { |
290 | 20.6k | if (b.in_pos == b.in_size && fill != NULL) { |
291 | 0 | if (in_used != NULL) |
292 | 0 | *in_used += b.in_pos; |
293 | |
|
294 | 0 | b.in_pos = 0; |
295 | |
|
296 | 0 | in_size = fill(in, XZ_IOBUF_SIZE); |
297 | 0 | if (in_size < 0) { |
298 | | /* |
299 | | * This isn't an optimal error code |
300 | | * but it probably isn't worth making |
301 | | * a new one either. |
302 | | */ |
303 | 0 | ret = XZ_BUF_ERROR; |
304 | 0 | break; |
305 | 0 | } |
306 | | |
307 | 0 | b.in_size = in_size; |
308 | 0 | } |
309 | | |
310 | 20.6k | ret = xz_dec_run(s, &b); |
311 | | |
312 | 20.6k | if (flush != NULL && (b.out_pos == b.out_size |
313 | 18.0k | || (ret != XZ_OK && b.out_pos > 0))) { |
314 | | /* |
315 | | * Setting ret here may hide an error |
316 | | * returned by xz_dec_run(), but probably |
317 | | * it's not too bad. |
318 | | */ |
319 | 18.0k | if (flush(b.out, b.out_pos) != (long)b.out_pos) |
320 | 0 | ret = XZ_BUF_ERROR; |
321 | | |
322 | 18.0k | b.out_pos = 0; |
323 | 18.0k | } |
324 | 20.6k | } while (ret == XZ_OK); |
325 | | |
326 | 2.09k | if (must_free_in) |
327 | 0 | FREE(in); |
328 | | |
329 | 2.09k | if (flush != NULL) |
330 | 2.09k | FREE(b.out); |
331 | 2.09k | } |
332 | | |
333 | 2.09k | if (in_used != NULL) |
334 | 0 | *in_used += b.in_pos; |
335 | | |
336 | 2.09k | xz_dec_end(s); |
337 | | |
338 | 2.09k | switch (ret) { |
339 | 0 | case XZ_STREAM_END: |
340 | 0 | return 0; |
341 | | |
342 | 1 | case XZ_MEM_ERROR: |
343 | | /* This can occur only in multi-call mode. */ |
344 | 1 | error("XZ decompressor ran out of memory"); |
345 | 1 | break; |
346 | | |
347 | 0 | case XZ_FORMAT_ERROR: |
348 | 0 | error("Input is not in the XZ format (wrong magic bytes)"); |
349 | 0 | break; |
350 | | |
351 | 45 | case XZ_OPTIONS_ERROR: |
352 | 45 | error("Input was encoded with settings that are not " |
353 | 45 | "supported by this XZ decoder"); |
354 | 45 | break; |
355 | | |
356 | 1.29k | case XZ_DATA_ERROR: |
357 | 2.04k | case XZ_BUF_ERROR: |
358 | 2.04k | error("XZ-compressed data is corrupt"); |
359 | 2.04k | break; |
360 | | |
361 | 0 | default: |
362 | 0 | error("Bug in the XZ decompressor"); |
363 | 0 | break; |
364 | 2.09k | } |
365 | | |
366 | 2.09k | return -1; |
367 | | |
368 | 0 | error_alloc_in: |
369 | 0 | if (flush != NULL) |
370 | 0 | FREE(b.out); |
371 | |
|
372 | 0 | error_alloc_out: |
373 | 0 | xz_dec_end(s); |
374 | |
|
375 | 0 | error_alloc_state: |
376 | 0 | error("XZ decompressor ran out of memory"); |
377 | 0 | return -1; |
378 | 0 | } |
379 | | |
380 | | /* |
381 | | * This macro is used by architecture-specific files to decompress |
382 | | * the kernel image. |
383 | | */ |
384 | | #define decompress decompress_unxz |