Coverage Report

Created: 2025-06-16 07:00

/src/xz/src/liblzma/common/block_decoder.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: 0BSD
2
3
///////////////////////////////////////////////////////////////////////////////
4
//
5
/// \file       block_decoder.c
6
/// \brief      Decodes .xz Blocks
7
//
8
//  Author:     Lasse Collin
9
//
10
///////////////////////////////////////////////////////////////////////////////
11
12
#include "block_decoder.h"
13
#include "filter_decoder.h"
14
#include "check.h"
15
16
17
typedef struct {
18
  enum {
19
    SEQ_CODE,
20
    SEQ_PADDING,
21
    SEQ_CHECK,
22
  } sequence;
23
24
  /// The filters in the chain; initialized with lzma_raw_decoder_init().
25
  lzma_next_coder next;
26
27
  /// Decoding options; we also write Compressed Size and Uncompressed
28
  /// Size back to this structure when the decoding has been finished.
29
  lzma_block *block;
30
31
  /// Compressed Size calculated while decoding
32
  lzma_vli compressed_size;
33
34
  /// Uncompressed Size calculated while decoding
35
  lzma_vli uncompressed_size;
36
37
  /// Maximum allowed Compressed Size; this takes into account the
38
  /// size of the Block Header and Check fields when Compressed Size
39
  /// is unknown.
40
  lzma_vli compressed_limit;
41
42
  /// Maximum allowed Uncompressed Size.
43
  lzma_vli uncompressed_limit;
44
45
  /// Position when reading the Check field
46
  size_t check_pos;
47
48
  /// Check of the uncompressed data
49
  lzma_check_state check;
50
51
  /// True if the integrity check won't be calculated and verified.
52
  bool ignore_check;
53
} lzma_block_coder;
54
55
56
static inline bool
57
is_size_valid(lzma_vli size, lzma_vli reference)
58
8.56k
{
59
8.56k
  return reference == LZMA_VLI_UNKNOWN || reference == size;
60
8.56k
}
61
62
63
static lzma_ret
64
block_decode(void *coder_ptr, const lzma_allocator *allocator,
65
    const uint8_t *restrict in, size_t *restrict in_pos,
66
    size_t in_size, uint8_t *restrict out,
67
    size_t *restrict out_pos, size_t out_size, lzma_action action)
68
302k
{
69
302k
  lzma_block_coder *coder = coder_ptr;
70
71
302k
  switch (coder->sequence) {
72
301k
  case SEQ_CODE: {
73
301k
    const size_t in_start = *in_pos;
74
301k
    const size_t out_start = *out_pos;
75
76
    // Limit the amount of input and output space that we give
77
    // to the raw decoder based on the information we have
78
    // (or don't have) from Block Header.
79
301k
    const size_t in_stop = *in_pos + (size_t)my_min(
80
301k
      in_size - *in_pos,
81
301k
      coder->compressed_limit - coder->compressed_size);
82
301k
    const size_t out_stop = *out_pos + (size_t)my_min(
83
301k
      out_size - *out_pos,
84
301k
      coder->uncompressed_limit - coder->uncompressed_size);
85
86
301k
    const lzma_ret ret = coder->next.code(coder->next.coder,
87
301k
        allocator, in, in_pos, in_stop,
88
301k
        out, out_pos, out_stop, action);
89
90
301k
    const size_t in_used = *in_pos - in_start;
91
301k
    const size_t out_used = *out_pos - out_start;
92
93
    // Because we have limited the input and output sizes,
94
    // we know that these cannot grow too big or overflow.
95
301k
    coder->compressed_size += in_used;
96
301k
    coder->uncompressed_size += out_used;
97
98
301k
    if (ret == LZMA_OK) {
99
291k
      const bool comp_done = coder->compressed_size
100
291k
          == coder->block->compressed_size;
101
291k
      const bool uncomp_done = coder->uncompressed_size
102
291k
          == coder->block->uncompressed_size;
103
104
      // If both input and output amounts match the sizes
105
      // in Block Header but we still got LZMA_OK instead
106
      // of LZMA_STREAM_END, the file is broken.
107
291k
      if (comp_done && uncomp_done)
108
23
        return LZMA_DATA_ERROR;
109
110
      // If the decoder has consumed all the input that it
111
      // needs but it still couldn't fill the output buffer
112
      // or return LZMA_STREAM_END, the file is broken.
113
291k
      if (comp_done && *out_pos < out_size)
114
164
        return LZMA_DATA_ERROR;
115
116
      // If the decoder has produced all the output but
117
      // it still didn't return LZMA_STREAM_END or consume
118
      // more input (for example, detecting an end of
119
      // payload marker may need more input but produce
120
      // no output) the file is broken.
121
291k
      if (uncomp_done && *in_pos < in_size)
122
66
        return LZMA_DATA_ERROR;
123
291k
    }
124
125
    // Don't waste time updating the integrity check if it will be
126
    // ignored. Also skip it if no new output was produced. This
127
    // avoids null pointer + 0 (undefined behavior) when out == 0.
128
301k
    if (!coder->ignore_check && out_used > 0)
129
285k
      lzma_check_update(&coder->check, coder->block->check,
130
285k
          out + out_start, out_used);
131
132
301k
    if (ret != LZMA_STREAM_END)
133
297k
      return ret;
134
135
    // Compressed and Uncompressed Sizes are now at their final
136
    // values. Verify that they match the values given to us.
137
4.45k
    if (!is_size_valid(coder->compressed_size,
138
4.45k
          coder->block->compressed_size)
139
4.45k
        || !is_size_valid(coder->uncompressed_size,
140
4.11k
          coder->block->uncompressed_size))
141
573
      return LZMA_DATA_ERROR;
142
143
    // Copy the values into coder->block. The caller
144
    // may use this information to construct Index.
145
3.87k
    coder->block->compressed_size = coder->compressed_size;
146
3.87k
    coder->block->uncompressed_size = coder->uncompressed_size;
147
148
3.87k
    coder->sequence = SEQ_PADDING;
149
3.87k
    FALLTHROUGH;
150
3.87k
  }
151
152
4.07k
  case SEQ_PADDING:
153
    // Compressed Data is padded to a multiple of four bytes.
154
10.1k
    while (coder->compressed_size & 3) {
155
6.57k
      if (*in_pos >= in_size)
156
290
        return LZMA_OK;
157
158
      // We use compressed_size here just get the Padding
159
      // right. The actual Compressed Size was stored to
160
      // coder->block already, and won't be modified by
161
      // us anymore.
162
6.28k
      ++coder->compressed_size;
163
164
6.28k
      if (in[(*in_pos)++] != 0x00)
165
175
        return LZMA_DATA_ERROR;
166
6.28k
    }
167
168
3.60k
    if (coder->block->check == LZMA_CHECK_NONE)
169
1.23k
      return LZMA_STREAM_END;
170
171
2.37k
    if (!coder->ignore_check)
172
2.37k
      lzma_check_finish(&coder->check, coder->block->check);
173
174
2.37k
    coder->sequence = SEQ_CHECK;
175
2.37k
    FALLTHROUGH;
176
177
2.63k
  case SEQ_CHECK: {
178
2.63k
    const size_t check_size = lzma_check_size(coder->block->check);
179
2.63k
    lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
180
2.63k
        &coder->check_pos, check_size);
181
2.63k
    if (coder->check_pos < check_size)
182
386
      return LZMA_OK;
183
184
    // Validate the Check only if we support it.
185
    // coder->check.buffer may be uninitialized
186
    // when the Check ID is not supported.
187
2.24k
    if (!coder->ignore_check
188
2.24k
        && lzma_check_is_supported(coder->block->check)
189
2.24k
        && memcmp(coder->block->raw_check,
190
498
          coder->check.buffer.u8,
191
498
          check_size) != 0)
192
306
      return LZMA_DATA_ERROR;
193
194
1.93k
    return LZMA_STREAM_END;
195
2.24k
  }
196
302k
  }
197
198
0
  return LZMA_PROG_ERROR;
199
302k
}
200
201
202
static void
203
block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
204
11.2k
{
205
11.2k
  lzma_block_coder *coder = coder_ptr;
206
11.2k
  lzma_next_end(&coder->next, allocator);
207
11.2k
  lzma_free(coder, allocator);
208
11.2k
  return;
209
11.2k
}
210
211
212
extern lzma_ret
213
lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
214
    lzma_block *block)
215
25.1k
{
216
25.1k
  lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
217
218
  // Validate the options. lzma_block_unpadded_size() does that for us
219
  // except for Uncompressed Size and filters. Filters are validated
220
  // by the raw decoder.
221
25.1k
  if (lzma_block_unpadded_size(block) == 0
222
25.1k
      || !lzma_vli_is_valid(block->uncompressed_size))
223
0
    return LZMA_PROG_ERROR;
224
225
  // Allocate *next->coder if needed.
226
25.1k
  lzma_block_coder *coder = next->coder;
227
25.1k
  if (coder == NULL) {
228
11.2k
    coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
229
11.2k
    if (coder == NULL)
230
0
      return LZMA_MEM_ERROR;
231
232
11.2k
    next->coder = coder;
233
11.2k
    next->code = &block_decode;
234
11.2k
    next->end = &block_decoder_end;
235
11.2k
    coder->next = LZMA_NEXT_CODER_INIT;
236
11.2k
  }
237
238
  // Basic initializations
239
25.1k
  coder->sequence = SEQ_CODE;
240
25.1k
  coder->block = block;
241
25.1k
  coder->compressed_size = 0;
242
25.1k
  coder->uncompressed_size = 0;
243
244
  // If Compressed Size is not known, we calculate the maximum allowed
245
  // value so that encoded size of the Block (including Block Padding)
246
  // is still a valid VLI and a multiple of four.
247
25.1k
  coder->compressed_limit
248
25.1k
      = block->compressed_size == LZMA_VLI_UNKNOWN
249
25.1k
        ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
250
20.6k
          - block->header_size
251
20.6k
          - lzma_check_size(block->check)
252
25.1k
        : block->compressed_size;
253
254
  // With Uncompressed Size this is simpler. If Block Header lacks
255
  // the size info, then LZMA_VLI_MAX is the maximum possible
256
  // Uncompressed Size.
257
25.1k
  coder->uncompressed_limit
258
25.1k
      = block->uncompressed_size == LZMA_VLI_UNKNOWN
259
25.1k
        ? LZMA_VLI_MAX
260
25.1k
        : block->uncompressed_size;
261
262
  // Initialize the check. It's caller's problem if the Check ID is not
263
  // supported, and the Block decoder cannot verify the Check field.
264
  // Caller can test lzma_check_is_supported(block->check).
265
25.1k
  coder->check_pos = 0;
266
25.1k
  lzma_check_init(&coder->check, block->check);
267
268
25.1k
  coder->ignore_check = block->version >= 1
269
25.1k
      ? block->ignore_check : false;
270
271
  // Initialize the filter chain.
272
25.1k
  return lzma_raw_decoder_init(&coder->next, allocator,
273
25.1k
      block->filters);
274
25.1k
}
275
276
277
extern LZMA_API(lzma_ret)
278
lzma_block_decoder(lzma_stream *strm, lzma_block *block)
279
0
{
280
0
  lzma_next_strm_init(lzma_block_decoder_init, strm, block);
281
282
0
  strm->internal->supported_actions[LZMA_RUN] = true;
283
0
  strm->internal->supported_actions[LZMA_FINISH] = true;
284
285
0
  return LZMA_OK;
286
0
}