Coverage Report

Created: 2025-11-14 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xz/src/liblzma/common/block_decoder.c
Line
Count
Source
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
9.51k
{
59
9.51k
  return reference == LZMA_VLI_UNKNOWN || reference == size;
60
9.51k
}
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
304k
{
69
304k
  lzma_block_coder *coder = coder_ptr;
70
71
304k
  switch (coder->sequence) {
72
304k
  case SEQ_CODE: {
73
304k
    const size_t in_start = *in_pos;
74
304k
    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
304k
    const size_t in_stop = *in_pos + (size_t)my_min(
80
304k
      in_size - *in_pos,
81
304k
      coder->compressed_limit - coder->compressed_size);
82
304k
    const size_t out_stop = *out_pos + (size_t)my_min(
83
304k
      out_size - *out_pos,
84
304k
      coder->uncompressed_limit - coder->uncompressed_size);
85
86
304k
    const lzma_ret ret = coder->next.code(coder->next.coder,
87
304k
        allocator, in, in_pos, in_stop,
88
304k
        out, out_pos, out_stop, action);
89
90
304k
    const size_t in_used = *in_pos - in_start;
91
304k
    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
304k
    coder->compressed_size += in_used;
96
304k
    coder->uncompressed_size += out_used;
97
98
304k
    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
32
        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
174
        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
290k
      if (uncomp_done && *in_pos < in_size)
122
81
        return LZMA_DATA_ERROR;
123
290k
    }
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
304k
    if (!coder->ignore_check && out_used > 0)
129
288k
      lzma_check_update(&coder->check, coder->block->check,
130
288k
          out + out_start, out_used);
131
132
304k
    if (ret != LZMA_STREAM_END)
133
299k
      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.97k
    if (!is_size_valid(coder->compressed_size,
138
4.97k
          coder->block->compressed_size)
139
4.53k
        || !is_size_valid(coder->uncompressed_size,
140
4.53k
          coder->block->uncompressed_size))
141
846
      return LZMA_DATA_ERROR;
142
143
    // Copy the values into coder->block. The caller
144
    // may use this information to construct Index.
145
4.13k
    coder->block->compressed_size = coder->compressed_size;
146
4.13k
    coder->block->uncompressed_size = coder->uncompressed_size;
147
148
4.13k
    coder->sequence = SEQ_PADDING;
149
4.13k
    FALLTHROUGH;
150
4.13k
  }
151
152
4.31k
  case SEQ_PADDING:
153
    // Compressed Data is padded to a multiple of four bytes.
154
10.6k
    while (coder->compressed_size & 3) {
155
6.75k
      if (*in_pos >= in_size)
156
276
        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.47k
      ++coder->compressed_size;
163
164
6.47k
      if (in[(*in_pos)++] != 0x00)
165
178
        return LZMA_DATA_ERROR;
166
6.47k
    }
167
168
3.86k
    if (coder->block->check == LZMA_CHECK_NONE)
169
1.11k
      return LZMA_STREAM_END;
170
171
2.74k
    if (!coder->ignore_check)
172
2.74k
      lzma_check_finish(&coder->check, coder->block->check);
173
174
2.74k
    coder->sequence = SEQ_CHECK;
175
2.74k
    FALLTHROUGH;
176
177
3.00k
  case SEQ_CHECK: {
178
3.00k
    const size_t check_size = lzma_check_size(coder->block->check);
179
3.00k
    lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
180
3.00k
        &coder->check_pos, check_size);
181
3.00k
    if (coder->check_pos < check_size)
182
439
      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.56k
    if (!coder->ignore_check
188
2.56k
        && lzma_check_is_supported(coder->block->check)
189
401
        && memcmp(coder->block->raw_check,
190
401
          coder->check.buffer.u8,
191
401
          check_size) != 0)
192
228
      return LZMA_DATA_ERROR;
193
194
2.33k
    return LZMA_STREAM_END;
195
2.56k
  }
196
304k
  }
197
198
0
  return LZMA_PROG_ERROR;
199
304k
}
200
201
202
static void
203
block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
204
10.7k
{
205
10.7k
  lzma_block_coder *coder = coder_ptr;
206
10.7k
  lzma_next_end(&coder->next, allocator);
207
10.7k
  lzma_free(coder, allocator);
208
10.7k
  return;
209
10.7k
}
210
211
212
extern lzma_ret
213
lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
214
    lzma_block *block)
215
32.9k
{
216
32.9k
  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
32.9k
  if (lzma_block_unpadded_size(block) == 0
222
32.9k
      || !lzma_vli_is_valid(block->uncompressed_size))
223
0
    return LZMA_PROG_ERROR;
224
225
  // Allocate *next->coder if needed.
226
32.9k
  lzma_block_coder *coder = next->coder;
227
32.9k
  if (coder == NULL) {
228
10.7k
    coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
229
10.7k
    if (coder == NULL)
230
0
      return LZMA_MEM_ERROR;
231
232
10.7k
    next->coder = coder;
233
10.7k
    next->code = &block_decode;
234
10.7k
    next->end = &block_decoder_end;
235
10.7k
    coder->next = LZMA_NEXT_CODER_INIT;
236
10.7k
  }
237
238
  // Basic initializations
239
32.9k
  coder->sequence = SEQ_CODE;
240
32.9k
  coder->block = block;
241
32.9k
  coder->compressed_size = 0;
242
32.9k
  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
32.9k
  coder->compressed_limit
248
32.9k
      = block->compressed_size == LZMA_VLI_UNKNOWN
249
32.9k
        ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
250
26.1k
          - block->header_size
251
26.1k
          - lzma_check_size(block->check)
252
32.9k
        : 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
32.9k
  coder->uncompressed_limit
258
32.9k
      = block->uncompressed_size == LZMA_VLI_UNKNOWN
259
32.9k
        ? LZMA_VLI_MAX
260
32.9k
        : 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
32.9k
  coder->check_pos = 0;
266
32.9k
  lzma_check_init(&coder->check, block->check);
267
268
32.9k
  coder->ignore_check = block->version >= 1
269
32.9k
      ? block->ignore_check : false;
270
271
  // Initialize the filter chain.
272
32.9k
  return lzma_raw_decoder_init(&coder->next, allocator,
273
32.9k
      block->filters);
274
32.9k
}
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
}