Path: blob/master/Utilities/cmliblzma/liblzma/common/index_decoder.c
3153 views
// SPDX-License-Identifier: 0BSD12///////////////////////////////////////////////////////////////////////////////3//4/// \file index_decoder.c5/// \brief Decodes the Index field6//7// Author: Lasse Collin8//9///////////////////////////////////////////////////////////////////////////////1011#include "index_decoder.h"12#include "check.h"131415typedef struct {16enum {17SEQ_INDICATOR,18SEQ_COUNT,19SEQ_MEMUSAGE,20SEQ_UNPADDED,21SEQ_UNCOMPRESSED,22SEQ_PADDING_INIT,23SEQ_PADDING,24SEQ_CRC32,25} sequence;2627/// Memory usage limit28uint64_t memlimit;2930/// Target Index31lzma_index *index;3233/// Pointer give by the application, which is set after34/// successful decoding.35lzma_index **index_ptr;3637/// Number of Records left to decode.38lzma_vli count;3940/// The most recent Unpadded Size field41lzma_vli unpadded_size;4243/// The most recent Uncompressed Size field44lzma_vli uncompressed_size;4546/// Position in integers47size_t pos;4849/// CRC32 of the List of Records field50uint32_t crc32;51} lzma_index_coder;525354static lzma_ret55index_decode(void *coder_ptr, const lzma_allocator *allocator,56const uint8_t *restrict in, size_t *restrict in_pos,57size_t in_size,58uint8_t *restrict out lzma_attribute((__unused__)),59size_t *restrict out_pos lzma_attribute((__unused__)),60size_t out_size lzma_attribute((__unused__)),61lzma_action action lzma_attribute((__unused__)))62{63lzma_index_coder *coder = coder_ptr;6465// Similar optimization as in index_encoder.c66const size_t in_start = *in_pos;67lzma_ret ret = LZMA_OK;6869while (*in_pos < in_size)70switch (coder->sequence) {71case SEQ_INDICATOR:72// Return LZMA_DATA_ERROR instead of e.g. LZMA_PROG_ERROR or73// LZMA_FORMAT_ERROR, because a typical usage case for Index74// decoder is when parsing the Stream backwards. If seeking75// backward from the Stream Footer gives us something that76// doesn't begin with Index Indicator, the file is considered77// corrupt, not "programming error" or "unrecognized file78// format". One could argue that the application should79// verify the Index Indicator before trying to decode the80// Index, but well, I suppose it is simpler this way.81if (in[(*in_pos)++] != INDEX_INDICATOR)82return LZMA_DATA_ERROR;8384coder->sequence = SEQ_COUNT;85break;8687case SEQ_COUNT:88ret = lzma_vli_decode(&coder->count, &coder->pos,89in, in_pos, in_size);90if (ret != LZMA_STREAM_END)91goto out;9293coder->pos = 0;94coder->sequence = SEQ_MEMUSAGE;9596// Fall through9798case SEQ_MEMUSAGE:99if (lzma_index_memusage(1, coder->count) > coder->memlimit) {100ret = LZMA_MEMLIMIT_ERROR;101goto out;102}103104// Tell the Index handling code how many Records this105// Index has to allow it to allocate memory more efficiently.106lzma_index_prealloc(coder->index, coder->count);107108ret = LZMA_OK;109coder->sequence = coder->count == 0110? SEQ_PADDING_INIT : SEQ_UNPADDED;111break;112113case SEQ_UNPADDED:114case SEQ_UNCOMPRESSED: {115lzma_vli *size = coder->sequence == SEQ_UNPADDED116? &coder->unpadded_size117: &coder->uncompressed_size;118119ret = lzma_vli_decode(size, &coder->pos,120in, in_pos, in_size);121if (ret != LZMA_STREAM_END)122goto out;123124ret = LZMA_OK;125coder->pos = 0;126127if (coder->sequence == SEQ_UNPADDED) {128// Validate that encoded Unpadded Size isn't too small129// or too big.130if (coder->unpadded_size < UNPADDED_SIZE_MIN131|| coder->unpadded_size132> UNPADDED_SIZE_MAX)133return LZMA_DATA_ERROR;134135coder->sequence = SEQ_UNCOMPRESSED;136} else {137// Add the decoded Record to the Index.138return_if_error(lzma_index_append(139coder->index, allocator,140coder->unpadded_size,141coder->uncompressed_size));142143// Check if this was the last Record.144coder->sequence = --coder->count == 0145? SEQ_PADDING_INIT146: SEQ_UNPADDED;147}148149break;150}151152case SEQ_PADDING_INIT:153coder->pos = lzma_index_padding_size(coder->index);154coder->sequence = SEQ_PADDING;155156// Fall through157158case SEQ_PADDING:159if (coder->pos > 0) {160--coder->pos;161if (in[(*in_pos)++] != 0x00)162return LZMA_DATA_ERROR;163164break;165}166167// Finish the CRC32 calculation.168coder->crc32 = lzma_crc32(in + in_start,169*in_pos - in_start, coder->crc32);170171coder->sequence = SEQ_CRC32;172173// Fall through174175case SEQ_CRC32:176do {177if (*in_pos == in_size)178return LZMA_OK;179180if (((coder->crc32 >> (coder->pos * 8)) & 0xFF)181!= in[(*in_pos)++]) {182#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION183return LZMA_DATA_ERROR;184#endif185}186187} while (++coder->pos < 4);188189// Decoding was successful, now we can let the application190// see the decoded Index.191*coder->index_ptr = coder->index;192193// Make index NULL so we don't free it unintentionally.194coder->index = NULL;195196return LZMA_STREAM_END;197198default:199assert(0);200return LZMA_PROG_ERROR;201}202203out:204// Update the CRC32.205//206// Avoid null pointer + 0 (undefined behavior) in "in + in_start".207// In such a case we had no input and thus in_used == 0.208{209const size_t in_used = *in_pos - in_start;210if (in_used > 0)211coder->crc32 = lzma_crc32(in + in_start,212in_used, coder->crc32);213}214215return ret;216}217218219static void220index_decoder_end(void *coder_ptr, const lzma_allocator *allocator)221{222lzma_index_coder *coder = coder_ptr;223lzma_index_end(coder->index, allocator);224lzma_free(coder, allocator);225return;226}227228229static lzma_ret230index_decoder_memconfig(void *coder_ptr, uint64_t *memusage,231uint64_t *old_memlimit, uint64_t new_memlimit)232{233lzma_index_coder *coder = coder_ptr;234235*memusage = lzma_index_memusage(1, coder->count);236*old_memlimit = coder->memlimit;237238if (new_memlimit != 0) {239if (new_memlimit < *memusage)240return LZMA_MEMLIMIT_ERROR;241242coder->memlimit = new_memlimit;243}244245return LZMA_OK;246}247248249static lzma_ret250index_decoder_reset(lzma_index_coder *coder, const lzma_allocator *allocator,251lzma_index **i, uint64_t memlimit)252{253// Remember the pointer given by the application. We will set it254// to point to the decoded Index only if decoding is successful.255// Before that, keep it NULL so that applications can always safely256// pass it to lzma_index_end() no matter did decoding succeed or not.257coder->index_ptr = i;258*i = NULL;259260// We always allocate a new lzma_index.261coder->index = lzma_index_init(allocator);262if (coder->index == NULL)263return LZMA_MEM_ERROR;264265// Initialize the rest.266coder->sequence = SEQ_INDICATOR;267coder->memlimit = my_max(1, memlimit);268coder->count = 0; // Needs to be initialized due to _memconfig().269coder->pos = 0;270coder->crc32 = 0;271272return LZMA_OK;273}274275276extern lzma_ret277lzma_index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,278lzma_index **i, uint64_t memlimit)279{280lzma_next_coder_init(&lzma_index_decoder_init, next, allocator);281282if (i == NULL)283return LZMA_PROG_ERROR;284285lzma_index_coder *coder = next->coder;286if (coder == NULL) {287coder = lzma_alloc(sizeof(lzma_index_coder), allocator);288if (coder == NULL)289return LZMA_MEM_ERROR;290291next->coder = coder;292next->code = &index_decode;293next->end = &index_decoder_end;294next->memconfig = &index_decoder_memconfig;295coder->index = NULL;296} else {297lzma_index_end(coder->index, allocator);298}299300return index_decoder_reset(coder, allocator, i, memlimit);301}302303304extern LZMA_API(lzma_ret)305lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)306{307// If i isn't NULL, *i must always be initialized due to308// the wording in the API docs. This way it is initialized309// if we return LZMA_PROG_ERROR due to strm == NULL.310if (i != NULL)311*i = NULL;312313lzma_next_strm_init(lzma_index_decoder_init, strm, i, memlimit);314315strm->internal->supported_actions[LZMA_RUN] = true;316strm->internal->supported_actions[LZMA_FINISH] = true;317318return LZMA_OK;319}320321322extern LZMA_API(lzma_ret)323lzma_index_buffer_decode(lzma_index **i, uint64_t *memlimit,324const lzma_allocator *allocator,325const uint8_t *in, size_t *in_pos, size_t in_size)326{327// If i isn't NULL, *i must always be initialized due to328// the wording in the API docs.329if (i != NULL)330*i = NULL;331332// Sanity checks333if (i == NULL || memlimit == NULL334|| in == NULL || in_pos == NULL || *in_pos > in_size)335return LZMA_PROG_ERROR;336337// Initialize the decoder.338lzma_index_coder coder;339return_if_error(index_decoder_reset(&coder, allocator, i, *memlimit));340341// Store the input start position so that we can restore it in case342// of an error.343const size_t in_start = *in_pos;344345// Do the actual decoding.346lzma_ret ret = index_decode(&coder, allocator, in, in_pos, in_size,347NULL, NULL, 0, LZMA_RUN);348349if (ret == LZMA_STREAM_END) {350ret = LZMA_OK;351} else {352// Something went wrong, free the Index structure and restore353// the input position.354lzma_index_end(coder.index, allocator);355*in_pos = in_start;356357if (ret == LZMA_OK) {358// The input is truncated or otherwise corrupt.359// Use LZMA_DATA_ERROR instead of LZMA_BUF_ERROR360// like lzma_vli_decode() does in single-call mode.361ret = LZMA_DATA_ERROR;362363} else if (ret == LZMA_MEMLIMIT_ERROR) {364// Tell the caller how much memory would have365// been needed.366*memlimit = lzma_index_memusage(1, coder.count);367}368}369370return ret;371}372373374