(root)/
xz-5.4.5/
src/
liblzma/
common/
block_header_decoder.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       block_header_decoder.c
       4  /// \brief      Decodes Block Header from .xz files
       5  //
       6  //  Author:     Lasse Collin
       7  //
       8  //  This file has been put into the public domain.
       9  //  You can do whatever you want with this file.
      10  //
      11  ///////////////////////////////////////////////////////////////////////////////
      12  
      13  #include "common.h"
      14  #include "check.h"
      15  
      16  
      17  extern LZMA_API(lzma_ret)
      18  lzma_block_header_decode(lzma_block *block,
      19  		const lzma_allocator *allocator, const uint8_t *in)
      20  {
      21  	// NOTE: We consider the header to be corrupt not only when the
      22  	// CRC32 doesn't match, but also when variable-length integers
      23  	// are invalid or over 63 bits, or if the header is too small
      24  	// to contain the claimed information.
      25  
      26  	// Catch unexpected NULL pointers.
      27  	if (block == NULL || block->filters == NULL || in == NULL)
      28  		return LZMA_PROG_ERROR;
      29  
      30  	// Initialize the filter options array. This way the caller can
      31  	// safely free() the options even if an error occurs in this function.
      32  	for (size_t i = 0; i <= LZMA_FILTERS_MAX; ++i) {
      33  		block->filters[i].id = LZMA_VLI_UNKNOWN;
      34  		block->filters[i].options = NULL;
      35  	}
      36  
      37  	// Versions 0 and 1 are supported. If a newer version was specified,
      38  	// we need to downgrade it.
      39  	if (block->version > 1)
      40  		block->version = 1;
      41  
      42  	// This isn't a Block Header option, but since the decompressor will
      43  	// read it if version >= 1, it's better to initialize it here than
      44  	// to expect the caller to do it since in almost all cases this
      45  	// should be false.
      46  	block->ignore_check = false;
      47  
      48  	// Validate Block Header Size and Check type. The caller must have
      49  	// already set these, so it is a programming error if this test fails.
      50  	if (lzma_block_header_size_decode(in[0]) != block->header_size
      51  			|| (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
      52  		return LZMA_PROG_ERROR;
      53  
      54  	// Exclude the CRC32 field.
      55  	const size_t in_size = block->header_size - 4;
      56  
      57  	// Verify CRC32
      58  	if (lzma_crc32(in, in_size, 0) != read32le(in + in_size)) {
      59  #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
      60  		return LZMA_DATA_ERROR;
      61  #endif
      62  	}
      63  
      64  	// Check for unsupported flags.
      65  	if (in[1] & 0x3C)
      66  		return LZMA_OPTIONS_ERROR;
      67  
      68  	// Start after the Block Header Size and Block Flags fields.
      69  	size_t in_pos = 2;
      70  
      71  	// Compressed Size
      72  	if (in[1] & 0x40) {
      73  		return_if_error(lzma_vli_decode(&block->compressed_size,
      74  				NULL, in, &in_pos, in_size));
      75  
      76  		// Validate Compressed Size. This checks that it isn't zero
      77  		// and that the total size of the Block is a valid VLI.
      78  		if (lzma_block_unpadded_size(block) == 0)
      79  			return LZMA_DATA_ERROR;
      80  	} else {
      81  		block->compressed_size = LZMA_VLI_UNKNOWN;
      82  	}
      83  
      84  	// Uncompressed Size
      85  	if (in[1] & 0x80)
      86  		return_if_error(lzma_vli_decode(&block->uncompressed_size,
      87  				NULL, in, &in_pos, in_size));
      88  	else
      89  		block->uncompressed_size = LZMA_VLI_UNKNOWN;
      90  
      91  	// Filter Flags
      92  	const size_t filter_count = (in[1] & 3U) + 1;
      93  	for (size_t i = 0; i < filter_count; ++i) {
      94  		const lzma_ret ret = lzma_filter_flags_decode(
      95  				&block->filters[i], allocator,
      96  				in, &in_pos, in_size);
      97  		if (ret != LZMA_OK) {
      98  			lzma_filters_free(block->filters, allocator);
      99  			return ret;
     100  		}
     101  	}
     102  
     103  	// Padding
     104  	while (in_pos < in_size) {
     105  		if (in[in_pos++] != 0x00) {
     106  			lzma_filters_free(block->filters, allocator);
     107  
     108  			// Possibly some new field present so use
     109  			// LZMA_OPTIONS_ERROR instead of LZMA_DATA_ERROR.
     110  			return LZMA_OPTIONS_ERROR;
     111  		}
     112  	}
     113  
     114  	return LZMA_OK;
     115  }