diff options
author | Lasse Collin <lasse.collin@tukaani.org> | 2022-11-22 11:20:17 +0200 |
---|---|---|
committer | Lasse Collin <lasse.collin@tukaani.org> | 2022-11-22 11:23:23 +0200 |
commit | c392bf8ccba857baaf50399c4b460119befacd54 (patch) | |
tree | 555e18784810bc8a412a05ee74bbe37e3c427a91 | |
parent | liblzma: Fix two Doxygen commands in the API headers. (diff) | |
download | xz-c392bf8ccba857baaf50399c4b460119befacd54.tar.xz |
liblzma: Fix infinite loop in LZMA encoder init with dict_size >= 2 GiB.
The encoder doesn't support dictionary sizes larger than 1536 MiB.
This is validated, for example, when calculating the memory usage
via lzma_raw_encoder_memusage(). It is also enforced by the LZ
part of the encoder initialization. However, LZMA encoder with
LZMA_MODE_NORMAL did an unsafe calculation with dict_size before
such validation and that results in an infinite loop if dict_size
was 2 << 30 or greater.
-rw-r--r-- | src/liblzma/lzma/lzma_encoder.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/src/liblzma/lzma/lzma_encoder.c b/src/liblzma/lzma/lzma_encoder.c index 8b90c059..788bcd1f 100644 --- a/src/liblzma/lzma/lzma_encoder.c +++ b/src/liblzma/lzma/lzma_encoder.c @@ -611,10 +611,9 @@ lzma_lzma_encoder_create(void **coder_ptr, lzma_lzma1_encoder *coder = *coder_ptr; - // Set compression mode. We haven't validates the options yet, - // but it's OK here, since nothing bad happens with invalid - // options in the code below, and they will get rejected by - // lzma_lzma_encoder_reset() call at the end of this function. + // Set compression mode. Note that we haven't validated the options + // yet. Invalid options will get rejected by lzma_lzma_encoder_reset() + // call at the end of this function. switch (options->mode) { case LZMA_MODE_FAST: coder->fast_mode = true; @@ -625,6 +624,18 @@ lzma_lzma_encoder_create(void **coder_ptr, // Set dist_table_size. // Round the dictionary size up to next 2^n. + // + // Currently the maximum encoder dictionary size + // is 1.5 GiB due to lz_encoder.c and here we need + // to be below 2 GiB to make the rounded up value + // fit in an uint32_t and avoid an infite while-loop + // (and undefined behavior due to a too large shift). + // So do the same check as in LZ encoder, + // limiting to 1.5 GiB. + if (options->dict_size > (UINT32_C(1) << 30) + + (UINT32_C(1) << 29)) + return LZMA_OPTIONS_ERROR; + uint32_t log_size = 0; while ((UINT32_C(1) << log_size) < options->dict_size) ++log_size; |