Combine lzma_options_block validation needed by both Block
encoder and decoder, and put the shared things to block_private.h. Improved the checks a little so that they may detect too big Compressed Size at initialization time if lzma_options_block.total_size or .total_limit is known. Allow encoding and decoding Blocks with combinations of fields that are not allowed by the file format specification. Doing this requires that the application passes such a combination in lzma_options_lzma; liblzma doesn't do that, but it's not impossible that someone could find them useful in some custom file format.
This commit is contained in:
parent
bf4200c818
commit
4441e00418
|
@ -296,8 +296,8 @@ block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern lzma_ret
|
static lzma_ret
|
||||||
lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
||||||
lzma_options_block *options)
|
lzma_options_block *options)
|
||||||
{
|
{
|
||||||
// This is pretty similar to lzma_block_encoder_init().
|
// This is pretty similar to lzma_block_encoder_init().
|
||||||
|
@ -313,27 +313,12 @@ lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
||||||
next->coder->next = LZMA_NEXT_CODER_INIT;
|
next->coder->next = LZMA_NEXT_CODER_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lzma_vli_is_valid(options->total_size)
|
if (validate_options_1(options))
|
||||||
|| !lzma_vli_is_valid(options->compressed_size)
|
|
||||||
|| !lzma_vli_is_valid(options->uncompressed_size)
|
|
||||||
|| !lzma_vli_is_valid(options->total_size)
|
|
||||||
|| !lzma_vli_is_valid(options->total_limit)
|
|
||||||
|| !lzma_vli_is_valid(options->uncompressed_limit)
|
|
||||||
|| (options->uncompressed_size
|
|
||||||
!= LZMA_VLI_VALUE_UNKNOWN
|
|
||||||
&& options->uncompressed_size
|
|
||||||
> options->uncompressed_limit)
|
|
||||||
|| (options->total_size != LZMA_VLI_VALUE_UNKNOWN
|
|
||||||
&& options->total_size
|
|
||||||
> options->total_limit)
|
|
||||||
|| (!options->has_eopm && options->uncompressed_size
|
|
||||||
== LZMA_VLI_VALUE_UNKNOWN)
|
|
||||||
|| options->header_size > options->total_size
|
|
||||||
|| (options->handle_padding
|
|
||||||
&& (options->has_uncompressed_size_in_footer
|
|
||||||
|| options->has_backward_size)))
|
|
||||||
return LZMA_PROG_ERROR;
|
return LZMA_PROG_ERROR;
|
||||||
|
|
||||||
|
if (validate_options_2(options))
|
||||||
|
return LZMA_DATA_ERROR;
|
||||||
|
|
||||||
return_if_error(lzma_check_init(&next->coder->check, options->check));
|
return_if_error(lzma_check_init(&next->coder->check, options->check));
|
||||||
|
|
||||||
next->coder->sequence = SEQ_CODE;
|
next->coder->sequence = SEQ_CODE;
|
||||||
|
@ -365,10 +350,18 @@ lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern lzma_ret
|
||||||
|
lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
||||||
|
lzma_options_block *options)
|
||||||
|
{
|
||||||
|
lzma_next_coder_init(block_decoder_init, next, allocator, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern LZMA_API lzma_ret
|
extern LZMA_API lzma_ret
|
||||||
lzma_block_decoder(lzma_stream *strm, lzma_options_block *options)
|
lzma_block_decoder(lzma_stream *strm, lzma_options_block *options)
|
||||||
{
|
{
|
||||||
lzma_next_strm_init(strm, lzma_block_decoder_init, options);
|
lzma_next_strm_init(strm, block_decoder_init, options);
|
||||||
|
|
||||||
strm->internal->supported_actions[LZMA_RUN] = true;
|
strm->internal->supported_actions[LZMA_RUN] = true;
|
||||||
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
|
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
|
||||||
|
|
|
@ -232,10 +232,8 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator,
|
||||||
|
|
||||||
case SEQ_PADDING:
|
case SEQ_PADDING:
|
||||||
if (coder->options->handle_padding) {
|
if (coder->options->handle_padding) {
|
||||||
assert(!coder->options
|
assert(coder->options->total_size
|
||||||
->has_uncompressed_size_in_footer);
|
!= LZMA_VLI_VALUE_UNKNOWN);
|
||||||
assert(!coder->options->has_backward_size);
|
|
||||||
assert(coder->options->total_size != LZMA_VLI_VALUE_UNKNOWN);
|
|
||||||
|
|
||||||
if (coder->total_size < coder->options->total_size) {
|
if (coder->total_size < coder->options->total_size) {
|
||||||
out[*out_pos] = 0x00;
|
out[*out_pos] = 0x00;
|
||||||
|
@ -284,27 +282,9 @@ block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
||||||
lzma_options_block *options)
|
lzma_options_block *options)
|
||||||
{
|
{
|
||||||
// Validate some options.
|
// Validate some options.
|
||||||
if (options == NULL
|
if (validate_options_1(options) || validate_options_2(options)
|
||||||
|| !lzma_vli_is_valid(options->total_size)
|
|| (options->handle_padding && options->total_size
|
||||||
|| !lzma_vli_is_valid(options->compressed_size)
|
== LZMA_VLI_VALUE_UNKNOWN))
|
||||||
|| !lzma_vli_is_valid(options->uncompressed_size)
|
|
||||||
|| !lzma_vli_is_valid(options->total_size)
|
|
||||||
|| !lzma_vli_is_valid(options->total_limit)
|
|
||||||
|| !lzma_vli_is_valid(options->uncompressed_limit)
|
|
||||||
|| (options->uncompressed_size
|
|
||||||
!= LZMA_VLI_VALUE_UNKNOWN
|
|
||||||
&& options->uncompressed_size
|
|
||||||
> options->uncompressed_limit)
|
|
||||||
|| (options->total_size != LZMA_VLI_VALUE_UNKNOWN
|
|
||||||
&& options->total_size
|
|
||||||
> options->total_limit)
|
|
||||||
|| (!options->has_eopm && options->uncompressed_size
|
|
||||||
== LZMA_VLI_VALUE_UNKNOWN)
|
|
||||||
|| (options->handle_padding && (options->total_size
|
|
||||||
== LZMA_VLI_VALUE_UNKNOWN
|
|
||||||
|| options->has_uncompressed_size_in_footer
|
|
||||||
|| options->has_backward_size))
|
|
||||||
|| options->header_size > options->total_size)
|
|
||||||
return LZMA_PROG_ERROR;
|
return LZMA_PROG_ERROR;
|
||||||
|
|
||||||
// Allocate and initialize *next->coder if needed.
|
// Allocate and initialize *next->coder if needed.
|
||||||
|
@ -325,7 +305,7 @@ block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|
||||||
// Compressed Data is empty. That is, we don't call the encoder at all.
|
// Compressed Data is empty. That is, we don't call the encoder at all.
|
||||||
// We initialize it though; it allows detecting invalid options.
|
// We initialize it though; it allows detecting invalid options.
|
||||||
if (!options->has_eopm && options->uncompressed_size == 0) {
|
if (!options->has_eopm && options->uncompressed_size == 0) {
|
||||||
// Also Compressed Size must also be zero if it has been
|
// Also Compressed Size must be zero if it has been
|
||||||
// given to us.
|
// given to us.
|
||||||
if (!is_size_valid(0, options->compressed_size))
|
if (!is_size_valid(0, options->compressed_size))
|
||||||
return LZMA_PROG_ERROR;
|
return LZMA_PROG_ERROR;
|
||||||
|
|
|
@ -43,4 +43,54 @@ is_size_valid(lzma_vli size, lzma_vli reference)
|
||||||
return reference == LZMA_VLI_VALUE_UNKNOWN || reference == size;
|
return reference == LZMA_VLI_VALUE_UNKNOWN || reference == size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// If any of these tests fail, the caller has to return LZMA_PROG_ERROR.
|
||||||
|
static inline bool
|
||||||
|
validate_options_1(const lzma_options_block *options)
|
||||||
|
{
|
||||||
|
return options == NULL
|
||||||
|
|| !lzma_vli_is_valid(options->compressed_size)
|
||||||
|
|| !lzma_vli_is_valid(options->uncompressed_size)
|
||||||
|
|| !lzma_vli_is_valid(options->total_size)
|
||||||
|
|| !lzma_vli_is_valid(options->total_limit)
|
||||||
|
|| !lzma_vli_is_valid(options->uncompressed_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// If any of these tests fail, the encoder has to return LZMA_PROG_ERROR
|
||||||
|
/// because something is going horribly wrong if such values get passed
|
||||||
|
/// to the encoder. In contrast, the decoder has to return LZMA_DATA_ERROR,
|
||||||
|
/// since these tests failing indicate that something is wrong in the Stream.
|
||||||
|
static inline bool
|
||||||
|
validate_options_2(const lzma_options_block *options)
|
||||||
|
{
|
||||||
|
if ((options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
|
||||||
|
&& options->uncompressed_size
|
||||||
|
> options->uncompressed_limit)
|
||||||
|
|| (options->total_size != LZMA_VLI_VALUE_UNKNOWN
|
||||||
|
&& options->total_size
|
||||||
|
> options->total_limit)
|
||||||
|
|| (!options->has_eopm && options->uncompressed_size
|
||||||
|
== LZMA_VLI_VALUE_UNKNOWN)
|
||||||
|
|| options->header_size > options->total_size)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
|
||||||
|
// Calculate a rough minimum possible valid Total Size of
|
||||||
|
// this Block, and check that total_size and total_limit
|
||||||
|
// are big enough. Note that the real minimum size can be
|
||||||
|
// bigger due to the Check, Uncompressed Size, Backwards
|
||||||
|
// Size, pr Padding being present. A rough check here is
|
||||||
|
// enough for us to catch the most obvious errors as early
|
||||||
|
// as possible.
|
||||||
|
const lzma_vli total_min = options->compressed_size
|
||||||
|
+ (lzma_vli)(options->header_size);
|
||||||
|
if (total_min > options->total_size
|
||||||
|
|| total_min > options->total_limit)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue