block_header_decoder.c 3.4 KB

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