Coverage Report

Created: 2023-09-25 06:56

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