xref: /freebsd/contrib/xz/src/liblzma/common/block_header_decoder.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
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 }
116