Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/xz: Add MicroLZMA decoder

MicroLZMA is a yet another header format variant where the first
byte of a raw LZMA stream (without the end of stream marker) has
been replaced with a bitwise-negation of the lc/lp/pb properties
byte. MicroLZMA was created to be used in EROFS but can be used
by other things too where wasting minimal amount of space for
headers is important.

This is implemented using most of the LZMA2 code as is so the
amount of new code is small. The API has a few extra features
compared to the XZ decoder. On the other hand, the API lacks
XZ_BUF_ERROR support which is important to take into account
when using this API.

MicroLZMA doesn't support BCJ filters. In theory they could be
added later as there are many unused/reserved values for the
first byte of the compressed stream but in practice it is
somewhat unlikely to happen due to a few implementation reasons.

Link: https://lore.kernel.org/r/20211010213145.17462-5-xiang@kernel.org
Signed-off-by: Lasse Collin <lasse.collin@tukaani.org>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>

authored by

Lasse Collin and committed by
Gao Xiang
aaa2975f a98a2540

+284 -3
+106
include/linux/xz.h
··· 234 234 XZ_EXTERN void xz_dec_end(struct xz_dec *s); 235 235 236 236 /* 237 + * Decompressor for MicroLZMA, an LZMA variant with a very minimal header. 238 + * See xz_dec_microlzma_alloc() below for details. 239 + * 240 + * These functions aren't used or available in preboot code and thus aren't 241 + * marked with XZ_EXTERN. This avoids warnings about static functions that 242 + * are never defined. 243 + */ 244 + /** 245 + * struct xz_dec_microlzma - Opaque type to hold the MicroLZMA decoder state 246 + */ 247 + struct xz_dec_microlzma; 248 + 249 + /** 250 + * xz_dec_microlzma_alloc() - Allocate memory for the MicroLZMA decoder 251 + * @mode XZ_SINGLE or XZ_PREALLOC 252 + * @dict_size LZMA dictionary size. This must be at least 4 KiB and 253 + * at most 3 GiB. 254 + * 255 + * In contrast to xz_dec_init(), this function only allocates the memory 256 + * and remembers the dictionary size. xz_dec_microlzma_reset() must be used 257 + * before calling xz_dec_microlzma_run(). 258 + * 259 + * The amount of allocated memory is a little less than 30 KiB with XZ_SINGLE. 260 + * With XZ_PREALLOC also a dictionary buffer of dict_size bytes is allocated. 261 + * 262 + * On success, xz_dec_microlzma_alloc() returns a pointer to 263 + * struct xz_dec_microlzma. If memory allocation fails or 264 + * dict_size is invalid, NULL is returned. 265 + * 266 + * The compressed format supported by this decoder is a raw LZMA stream 267 + * whose first byte (always 0x00) has been replaced with bitwise-negation 268 + * of the LZMA properties (lc/lp/pb) byte. For example, if lc/lp/pb is 269 + * 3/0/2, the first byte is 0xA2. This way the first byte can never be 0x00. 270 + * Just like with LZMA2, lc + lp <= 4 must be true. The LZMA end-of-stream 271 + * marker must not be used. The unused values are reserved for future use. 272 + * This MicroLZMA header format was created for use in EROFS but may be used 273 + * by others too. 274 + */ 275 + extern struct xz_dec_microlzma *xz_dec_microlzma_alloc(enum xz_mode mode, 276 + uint32_t dict_size); 277 + 278 + /** 279 + * xz_dec_microlzma_reset() - Reset the MicroLZMA decoder state 280 + * @s Decoder state allocated using xz_dec_microlzma_alloc() 281 + * @comp_size Compressed size of the input stream 282 + * @uncomp_size Uncompressed size of the input stream. A value smaller 283 + * than the real uncompressed size of the input stream can 284 + * be specified if uncomp_size_is_exact is set to false. 285 + * uncomp_size can never be set to a value larger than the 286 + * expected real uncompressed size because it would eventually 287 + * result in XZ_DATA_ERROR. 288 + * @uncomp_size_is_exact This is an int instead of bool to avoid 289 + * requiring stdbool.h. This should normally be set to true. 290 + * When this is set to false, error detection is weaker. 291 + */ 292 + extern void xz_dec_microlzma_reset(struct xz_dec_microlzma *s, 293 + uint32_t comp_size, uint32_t uncomp_size, 294 + int uncomp_size_is_exact); 295 + 296 + /** 297 + * xz_dec_microlzma_run() - Run the MicroLZMA decoder 298 + * @s Decoder state initialized using xz_dec_microlzma_reset() 299 + * @b: Input and output buffers 300 + * 301 + * This works similarly to xz_dec_run() with a few important differences. 302 + * Only the differences are documented here. 303 + * 304 + * The only possible return values are XZ_OK, XZ_STREAM_END, and 305 + * XZ_DATA_ERROR. This function cannot return XZ_BUF_ERROR: if no progress 306 + * is possible due to lack of input data or output space, this function will 307 + * keep returning XZ_OK. Thus, the calling code must be written so that it 308 + * will eventually provide input and output space matching (or exceeding) 309 + * comp_size and uncomp_size arguments given to xz_dec_microlzma_reset(). 310 + * If the caller cannot do this (for example, if the input file is truncated 311 + * or otherwise corrupt), the caller must detect this error by itself to 312 + * avoid an infinite loop. 313 + * 314 + * If the compressed data seems to be corrupt, XZ_DATA_ERROR is returned. 315 + * This can happen also when incorrect dictionary, uncompressed, or 316 + * compressed sizes have been specified. 317 + * 318 + * With XZ_PREALLOC only: As an extra feature, b->out may be NULL to skip over 319 + * uncompressed data. This way the caller doesn't need to provide a temporary 320 + * output buffer for the bytes that will be ignored. 321 + * 322 + * With XZ_SINGLE only: In contrast to xz_dec_run(), the return value XZ_OK 323 + * is also possible and thus XZ_SINGLE is actually a limited multi-call mode. 324 + * After XZ_OK the bytes decoded so far may be read from the output buffer. 325 + * It is possible to continue decoding but the variables b->out and b->out_pos 326 + * MUST NOT be changed by the caller. Increasing the value of b->out_size is 327 + * allowed to make more output space available; one doesn't need to provide 328 + * space for the whole uncompressed data on the first call. The input buffer 329 + * may be changed normally like with XZ_PREALLOC. This way input data can be 330 + * provided from non-contiguous memory. 331 + */ 332 + extern enum xz_ret xz_dec_microlzma_run(struct xz_dec_microlzma *s, 333 + struct xz_buf *b); 334 + 335 + /** 336 + * xz_dec_microlzma_end() - Free the memory allocated for the decoder state 337 + * @s: Decoder state allocated using xz_dec_microlzma_alloc(). 338 + * If s is NULL, this function does nothing. 339 + */ 340 + extern void xz_dec_microlzma_end(struct xz_dec_microlzma *s); 341 + 342 + /* 237 343 * Standalone build (userspace build or in-kernel build for boot time use) 238 344 * needs a CRC32 implementation. For normal in-kernel use, kernel's own 239 345 * CRC32 module is used instead, and users of this module don't need to
+13
lib/xz/Kconfig
··· 39 39 default y 40 40 select XZ_DEC_BCJ 41 41 42 + config XZ_DEC_MICROLZMA 43 + bool "MicroLZMA decoder" 44 + default n 45 + help 46 + MicroLZMA is a header format variant where the first byte 47 + of a raw LZMA stream (without the end of stream marker) has 48 + been replaced with a bitwise-negation of the lc/lp/pb 49 + properties byte. MicroLZMA was created to be used in EROFS 50 + but can be used by other things too where wasting minimal 51 + amount of space for headers is important. 52 + 53 + Unless you know that you need this, say N. 54 + 42 55 endif 43 56 44 57 config XZ_DEC_BCJ
+154 -2
lib/xz/xz_dec_lzma2.c
··· 248 248 * before the first LZMA chunk. 249 249 */ 250 250 bool need_props; 251 + 252 + #ifdef XZ_DEC_MICROLZMA 253 + bool pedantic_microlzma; 254 + #endif 251 255 }; 252 256 253 257 struct xz_dec_lzma2 { ··· 423 419 } 424 420 } 425 421 422 + #ifdef XZ_DEC_MICROLZMA 423 + # define DICT_FLUSH_SUPPORTS_SKIPPING true 424 + #else 425 + # define DICT_FLUSH_SUPPORTS_SKIPPING false 426 + #endif 427 + 426 428 /* 427 429 * Flush pending data from dictionary to b->out. It is assumed that there is 428 430 * enough space in b->out. This is guaranteed because caller uses dict_limit() ··· 447 437 * decompression because in multi-call mode dict->buf 448 438 * has been allocated by us in this file; it's not 449 439 * provided by the caller like in single-call mode. 440 + * 441 + * With MicroLZMA, b->out can be NULL to skip bytes that 442 + * the caller doesn't need. This cannot be done with XZ 443 + * because it would break BCJ filters. 450 444 */ 451 - memcpy(b->out + b->out_pos, dict->buf + dict->start, 452 - copy_size); 445 + if (!DICT_FLUSH_SUPPORTS_SKIPPING || b->out != NULL) 446 + memcpy(b->out + b->out_pos, dict->buf + dict->start, 447 + copy_size); 453 448 } 454 449 455 450 dict->start = dict->pos; ··· 1205 1190 1206 1191 kfree(s); 1207 1192 } 1193 + 1194 + #ifdef XZ_DEC_MICROLZMA 1195 + /* This is a wrapper struct to have a nice struct name in the public API. */ 1196 + struct xz_dec_microlzma { 1197 + struct xz_dec_lzma2 s; 1198 + }; 1199 + 1200 + enum xz_ret xz_dec_microlzma_run(struct xz_dec_microlzma *s_ptr, 1201 + struct xz_buf *b) 1202 + { 1203 + struct xz_dec_lzma2 *s = &s_ptr->s; 1204 + 1205 + /* 1206 + * sequence is SEQ_PROPERTIES before the first input byte, 1207 + * SEQ_LZMA_PREPARE until a total of five bytes have been read, 1208 + * and SEQ_LZMA_RUN for the rest of the input stream. 1209 + */ 1210 + if (s->lzma2.sequence != SEQ_LZMA_RUN) { 1211 + if (s->lzma2.sequence == SEQ_PROPERTIES) { 1212 + /* One byte is needed for the props. */ 1213 + if (b->in_pos >= b->in_size) 1214 + return XZ_OK; 1215 + 1216 + /* 1217 + * Don't increment b->in_pos here. The same byte is 1218 + * also passed to rc_read_init() which will ignore it. 1219 + */ 1220 + if (!lzma_props(s, ~b->in[b->in_pos])) 1221 + return XZ_DATA_ERROR; 1222 + 1223 + s->lzma2.sequence = SEQ_LZMA_PREPARE; 1224 + } 1225 + 1226 + /* 1227 + * xz_dec_microlzma_reset() doesn't validate the compressed 1228 + * size so we do it here. We have to limit the maximum size 1229 + * to avoid integer overflows in lzma2_lzma(). 3 GiB is a nice 1230 + * round number and much more than users of this code should 1231 + * ever need. 1232 + */ 1233 + if (s->lzma2.compressed < RC_INIT_BYTES 1234 + || s->lzma2.compressed > (3U << 30)) 1235 + return XZ_DATA_ERROR; 1236 + 1237 + if (!rc_read_init(&s->rc, b)) 1238 + return XZ_OK; 1239 + 1240 + s->lzma2.compressed -= RC_INIT_BYTES; 1241 + s->lzma2.sequence = SEQ_LZMA_RUN; 1242 + 1243 + dict_reset(&s->dict, b); 1244 + } 1245 + 1246 + /* This is to allow increasing b->out_size between calls. */ 1247 + if (DEC_IS_SINGLE(s->dict.mode)) 1248 + s->dict.end = b->out_size - b->out_pos; 1249 + 1250 + while (true) { 1251 + dict_limit(&s->dict, min_t(size_t, b->out_size - b->out_pos, 1252 + s->lzma2.uncompressed)); 1253 + 1254 + if (!lzma2_lzma(s, b)) 1255 + return XZ_DATA_ERROR; 1256 + 1257 + s->lzma2.uncompressed -= dict_flush(&s->dict, b); 1258 + 1259 + if (s->lzma2.uncompressed == 0) { 1260 + if (s->lzma2.pedantic_microlzma) { 1261 + if (s->lzma2.compressed > 0 || s->lzma.len > 0 1262 + || !rc_is_finished(&s->rc)) 1263 + return XZ_DATA_ERROR; 1264 + } 1265 + 1266 + return XZ_STREAM_END; 1267 + } 1268 + 1269 + if (b->out_pos == b->out_size) 1270 + return XZ_OK; 1271 + 1272 + if (b->in_pos == b->in_size 1273 + && s->temp.size < s->lzma2.compressed) 1274 + return XZ_OK; 1275 + } 1276 + } 1277 + 1278 + struct xz_dec_microlzma *xz_dec_microlzma_alloc(enum xz_mode mode, 1279 + uint32_t dict_size) 1280 + { 1281 + struct xz_dec_microlzma *s; 1282 + 1283 + /* Restrict dict_size to the same range as in the LZMA2 code. */ 1284 + if (dict_size < 4096 || dict_size > (3U << 30)) 1285 + return NULL; 1286 + 1287 + s = kmalloc(sizeof(*s), GFP_KERNEL); 1288 + if (s == NULL) 1289 + return NULL; 1290 + 1291 + s->s.dict.mode = mode; 1292 + s->s.dict.size = dict_size; 1293 + 1294 + if (DEC_IS_MULTI(mode)) { 1295 + s->s.dict.end = dict_size; 1296 + 1297 + s->s.dict.buf = vmalloc(dict_size); 1298 + if (s->s.dict.buf == NULL) { 1299 + kfree(s); 1300 + return NULL; 1301 + } 1302 + } 1303 + 1304 + return s; 1305 + } 1306 + 1307 + void xz_dec_microlzma_reset(struct xz_dec_microlzma *s, uint32_t comp_size, 1308 + uint32_t uncomp_size, int uncomp_size_is_exact) 1309 + { 1310 + /* 1311 + * comp_size is validated in xz_dec_microlzma_run(). 1312 + * uncomp_size can safely be anything. 1313 + */ 1314 + s->s.lzma2.compressed = comp_size; 1315 + s->s.lzma2.uncompressed = uncomp_size; 1316 + s->s.lzma2.pedantic_microlzma = uncomp_size_is_exact; 1317 + 1318 + s->s.lzma2.sequence = SEQ_PROPERTIES; 1319 + s->s.temp.size = 0; 1320 + } 1321 + 1322 + void xz_dec_microlzma_end(struct xz_dec_microlzma *s) 1323 + { 1324 + if (DEC_IS_MULTI(s->s.dict.mode)) 1325 + vfree(s->s.dict.buf); 1326 + 1327 + kfree(s); 1328 + } 1329 + #endif
+8 -1
lib/xz/xz_dec_syms.c
··· 15 15 EXPORT_SYMBOL(xz_dec_run); 16 16 EXPORT_SYMBOL(xz_dec_end); 17 17 18 + #ifdef CONFIG_XZ_DEC_MICROLZMA 19 + EXPORT_SYMBOL(xz_dec_microlzma_alloc); 20 + EXPORT_SYMBOL(xz_dec_microlzma_reset); 21 + EXPORT_SYMBOL(xz_dec_microlzma_run); 22 + EXPORT_SYMBOL(xz_dec_microlzma_end); 23 + #endif 24 + 18 25 MODULE_DESCRIPTION("XZ decompressor"); 19 - MODULE_VERSION("1.0"); 26 + MODULE_VERSION("1.1"); 20 27 MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org> and Igor Pavlov"); 21 28 22 29 /*
+3
lib/xz/xz_private.h
··· 37 37 # ifdef CONFIG_XZ_DEC_SPARC 38 38 # define XZ_DEC_SPARC 39 39 # endif 40 + # ifdef CONFIG_XZ_DEC_MICROLZMA 41 + # define XZ_DEC_MICROLZMA 42 + # endif 40 43 # define memeq(a, b, size) (memcmp(a, b, size) == 0) 41 44 # define memzero(buf, size) memset(buf, 0, size) 42 45 # endif