/* xz_dec_stream.c - .xz Stream decoder */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
*/
#include "xz_config.h"
#include "xz_private.h"
#include "xz_stream.h"
/* Hash used to validate the Index field */
struct xz_dec_hash {
#ifndef GRUB_EMBED_DECOMPRESSOR
#endif
};
/* Enough for up to 512 bits. */
struct xz_dec {
/* Position in dec_main() */
enum {
} sequence;
/* Position in variable-length integers and Check fields */
/* Variable-length integer decoded by dec_vli() */
/* Saved in_pos and out_pos */
/* CRC32 value in Block or Index */
#ifndef GRUB_EMBED_DECOMPRESSOR
#endif
int have_hash_value;
#ifndef GRUB_EMBED_DECOMPRESSOR
#endif
/* Hash function calculated from uncompressed data */
#ifndef GRUB_EMBED_DECOMPRESSOR
#endif
/* True if we are operating in single-call mode. */
bool single_call;
/*
* True if the next call to xz_dec_run() is allowed to return
* XZ_BUF_ERROR.
*/
bool allow_buf_error;
/* Information stored in Block Header */
struct {
/*
* Value stored in the Compressed Size field, or
* VLI_UNKNOWN if Compressed Size is not present.
*/
/*
* Value stored in the Uncompressed Size field, or
* VLI_UNKNOWN if Uncompressed Size is not present.
*/
/* Size of the Block Header field */
} block_header;
/* Information collected when decoding Blocks */
struct {
/* Observed compressed size of the current Block */
/* Observed uncompressed size of the current Block */
/* Number of Blocks decoded so far */
/*
* Hash calculated from the Block sizes. This is used to
* validate the Index field.
*/
} block;
/* Variables needed when verifying the Index field */
struct {
/* Position in dec_index() */
enum {
} sequence;
/* Size of the Index in bytes */
/* Number of Records (matches block.count in valid files) */
/*
* Hash calculated from the Records (matches block.hash in
* valid files).
*/
} index;
/*
* Temporary buffer needed to hold Stream Header, Block Header,
* and Stream Footer. The Block Header is the biggest (1 KiB)
* so we reserve space according to that. buf[] has to be aligned
* to a multiple of four bytes; the size_t variables before it
* should guarantee this.
*/
struct {
} temp;
#ifdef XZ_DEC_BCJ
bool bcj_active;
#endif
};
/*
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
* must have set s->temp.pos to indicate how much data we are supposed
* to copy into s->temp.buf. Return true once s->temp.pos has reached
* s->temp.size.
*/
{
return true;
}
return false;
}
/* Decode a variable-length integer (little-endian base-128 encoding) */
{
if (s->pos == 0)
s->vli = 0;
++*in_pos;
if ((byte & 0x80) == 0) {
/* Don't allow non-minimal encodings. */
return XZ_DATA_ERROR;
s->pos = 0;
return XZ_STREAM_END;
}
s->pos += 7;
return XZ_DATA_ERROR;
}
return XZ_OK;
}
/*
* Decode the Compressed Data field from a Block. Update and validate
* the observed compressed and uncompressed sizes of the Block so that
* they don't exceed the values possibly stored in the Block Header
* (validation assumes that no integer overflow occurs, since vli_type
* is normally uint64_t). Update the CRC32 if presence of the CRC32
* field was indicated in Stream Header.
*
* Once the decoding is finished, validate that the observed sizes match
* the sizes possibly stored in the Block Header. Update the hash and
* Block count, which are later used to validate the Index field.
*/
{
#ifdef XZ_DEC_BCJ
if (s->bcj_active)
else
#endif
/*
* There is no need to separately check for VLI_UNKNOWN, since
* the observed sizes are always smaller than VLI_UNKNOWN.
*/
|| s->block.uncompressed
> s->block_header.uncompressed)
return XZ_DATA_ERROR;
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
if (s->crc32)
#endif
if (ret == XZ_STREAM_END) {
&& s->block_header.compressed
!= s->block.compressed)
return XZ_DATA_ERROR;
&& s->block_header.uncompressed
!= s->block.uncompressed)
return XZ_DATA_ERROR;
+ s->block.compressed;
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
2 * sizeof(vli_type));
#endif
}
return ret;
}
/* Update the Index size and the CRC32 value. */
{
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
if (s->crc32)
#endif
}
/*
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
* fields from the Index field. That is, Index Padding and CRC32 are not
* decoded by this function.
*
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
*/
{
do {
if (ret != XZ_STREAM_END) {
index_update(s, b);
return ret;
}
case SEQ_INDEX_COUNT:
/*
* Validate that the Number of Records field
* indicates the same number of Records as
* there were Blocks in the Stream.
*/
return XZ_DATA_ERROR;
break;
case SEQ_INDEX_UNPADDED:
break;
case SEQ_INDEX_UNCOMPRESSED:
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
#endif
break;
}
return XZ_STREAM_END;
}
/*
* Validate that the next four input bytes match the value of s->crc32.
* s->pos must be zero when starting to validate the first byte.
*/
int crc32)
{
#ifndef GRUB_EMBED_DECOMPRESSOR
: s->hash_context;
if(!s->have_hash_value && hash
{
s->have_hash_value = 1;
{
grub_uint8_t t;
t = s->hash_value[0];
s->hash_value[3] = t;
t = s->hash_value[1];
s->hash_value[2] = t;
}
}
#endif
do {
return XZ_OK;
#ifndef GRUB_EMBED_DECOMPRESSOR
return XZ_DATA_ERROR;
#endif
s->pos += 8;
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
if (s->crc32)
#endif
s->have_hash_value = 0;
s->pos = 0;
return XZ_STREAM_END;
}
static const struct
{
const char *name;
} hashes[] = {
[0x01] = { "CRC32", 4},
[0x04] = { "CRC64", 8},
[0x0A] = { "SHA256", 32},
};
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
{
return XZ_FORMAT_ERROR;
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->crc32)
{
return XZ_DATA_ERROR;
}
#endif
#ifndef GRUB_EMBED_DECOMPRESSOR
/*
* Decode the Stream Flags field.
*/
return XZ_OPTIONS_ERROR;
if (s->crc32)
{
if (s->crc32_context == NULL)
return XZ_MEMLIMIT_ERROR;
}
#endif
{
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
{
return XZ_OPTIONS_ERROR;
if (s->hash_context == NULL)
{
kfree(s->crc32_context);
return XZ_MEMLIMIT_ERROR;
}
{
kfree(s->hash_context);
kfree(s->crc32_context);
return XZ_MEMLIMIT_ERROR;
}
{
kfree(s->hash_context);
kfree(s->crc32_context);
return XZ_MEMLIMIT_ERROR;
}
}
if (!s->hash)
return XZ_OPTIONS_ERROR;
#endif
}
else
{
#ifndef GRUB_EMBED_DECOMPRESSOR
s->hash = 0;
#endif
s->hash_size = 0;
}
s->have_hash_value = 0;
return XZ_OK;
}
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
{
return XZ_DATA_ERROR;
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->crc32)
{
return XZ_DATA_ERROR;
}
#endif
/*
* Validate Backward Size. Note that we never added the size of the
* instead of s->index.size / 4 - 1.
*/
return XZ_DATA_ERROR;
#ifndef GRUB_EMBED_DECOMPRESSOR
return XZ_DATA_ERROR;
#endif
/*
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
* for the caller.
*/
return XZ_STREAM_END;
}
/* Decode the Block Header and initialize the filter chain. */
{
/*
* Validate the CRC32. We know that the temp buffer is at least
* eight bytes so this is safe.
*/
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->crc32)
{
return XZ_DATA_ERROR;
}
#endif
/*
* Catch unsupported Block Flags. We support only one or two filters
* in the chain, so we catch that with the same test.
*/
#ifdef XZ_DEC_BCJ
#else
#endif
return XZ_OPTIONS_ERROR;
/* Compressed Size */
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
} else {
}
/* Uncompressed Size */
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
} else {
}
#ifdef XZ_DEC_BCJ
/* If there are two filters, the first one must be a BCJ filter. */
if (s->bcj_active) {
return XZ_OPTIONS_ERROR;
return ret;
/*
* We don't support custom start offset,
* so Size of Properties must be zero.
*/
return XZ_OPTIONS_ERROR;
}
#endif
/* Valid Filter Flags always take at least two bytes. */
return XZ_DATA_ERROR;
/* Filter ID = LZMA2 */
return XZ_OPTIONS_ERROR;
/* Size of Properties = 1-byte Filter Properties */
return XZ_OPTIONS_ERROR;
/* Filter Properties contains LZMA2 dictionary size. */
return XZ_DATA_ERROR;
return ret;
/* The rest must be Header Padding. */
return XZ_OPTIONS_ERROR;
s->block.compressed = 0;
s->block.uncompressed = 0;
return XZ_OK;
}
{
/*
* Store the start position for the case when we are in the middle
* of the Index field.
*/
while (true) {
switch (s->sequence) {
case SEQ_STREAM_HEADER:
/*
* Stream Header is copied to s->temp, and then
* decoded from there. This way if the caller
* gives us only little input at a time, we can
* still keep the Stream Header decoding code
* simple. Similar approach is used in many places
* in this file.
*/
if (!fill_temp(s, b))
return XZ_OK;
ret = dec_stream_header(s);
return ret;
s->sequence = SEQ_BLOCK_START;
case SEQ_BLOCK_START:
/* We need one byte of input to continue. */
return XZ_OK;
/* See if this is the beginning of the Index field. */
break;
}
/*
* Calculate the size of the Block Header and
* prepare to decode it.
*/
s->block_header.size
s->sequence = SEQ_BLOCK_HEADER;
case SEQ_BLOCK_HEADER:
if (!fill_temp(s, b))
return XZ_OK;
ret = dec_block_header(s);
return ret;
s->sequence = SEQ_BLOCK_UNCOMPRESS;
case SEQ_BLOCK_UNCOMPRESS:
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_BLOCK_PADDING;
case SEQ_BLOCK_PADDING:
/*
* Size of Compressed Data + Block Padding
* must be a multiple of four. We don't need
* s->block.compressed for anything else
* anymore, so we use it here to test the size
* of the Block Padding field.
*/
return XZ_OK;
return XZ_DATA_ERROR;
++s->block.compressed;
}
s->sequence = SEQ_BLOCK_CHECK;
case SEQ_BLOCK_CHECK:
ret = hash_validate(s, b, 0);
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_BLOCK_START;
break;
case SEQ_INDEX:
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_INDEX_PADDING;
case SEQ_INDEX_PADDING:
& 3) {
index_update(s, b);
return XZ_OK;
}
return XZ_DATA_ERROR;
}
/* Finish the CRC32 value and Index size. */
index_update(s, b);
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
{
/* Compare the hashes to validate the Index field. */
return XZ_DATA_ERROR;
}
#endif
s->sequence = SEQ_INDEX_CRC32;
case SEQ_INDEX_CRC32:
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_STREAM_FOOTER;
case SEQ_STREAM_FOOTER:
if (!fill_temp(s, b))
return XZ_OK;
return dec_stream_footer(s);
}
}
/* Never reached */
}
/*
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
* multi-call and single-call decoding.
*
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
* are not going to make any progress anymore. This is to prevent the caller
* from calling us infinitely when the input file is truncated or otherwise
* corrupt. Since zlib-style API allows that the caller fills the input buffer
* only when the decoder doesn't produce any new output, we have to be careful
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
* after the second consecutive call to xz_dec_run() that makes no progress.
*
* In single-call mode, if we couldn't decode everything and no error
* occurred, either the input is truncated or the output buffer is too small.
* Since we know that the last input byte never produces any output, we know
* that if all the input was consumed and decoding wasn't finished, the file
* must be corrupt. Otherwise the output buffer has to be too small or the
* file is corrupt in a way that decoding it produces too big output.
*
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
* their original values. This is because with some filter chains there won't
* be any valid uncompressed data in the output buffer unless the decoding
* actually succeeds (that's the price to pay of using the output buffer as
* the workspace).
*/
{
if (s->single_call)
xz_dec_reset(s);
if (s->single_call) {
if (ret != XZ_STREAM_END) {
}
if (s->allow_buf_error)
ret = XZ_BUF_ERROR;
s->allow_buf_error = true;
} else {
s->allow_buf_error = false;
}
return ret;
}
#ifdef GRUB_EMBED_DECOMPRESSOR
#endif
{
struct xz_dec *s;
#ifdef GRUB_EMBED_DECOMPRESSOR
s = &decoder;
#else
s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s == NULL)
return NULL;
#endif
memset (s, 0, sizeof (*s));
s->single_call = dict_max == 0;
#ifdef XZ_DEC_BCJ
goto error_bcj;
#endif
goto error_lzma2;
xz_dec_reset(s);
return s;
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
#endif
#ifndef GRUB_EMBED_DECOMPRESSOR
kfree(s);
#endif
return NULL;
}
{
s->sequence = SEQ_STREAM_HEADER;
s->allow_buf_error = false;
s->pos = 0;
{
#ifndef GRUB_EMBED_DECOMPRESSOR
uint64_t *t;
#endif
#ifndef GRUB_EMBED_DECOMPRESSOR
#endif
#ifndef GRUB_EMBED_DECOMPRESSOR
#endif
}
#ifndef GRUB_EMBED_DECOMPRESSOR
if (s->hash)
{
}
#endif
s->have_hash_value = 0;
}
{
if (s != NULL) {
xz_dec_lzma2_end(s->lzma2);
#ifndef GRUB_EMBED_DECOMPRESSOR
kfree(s->hash_context);
kfree(s->crc32_context);
#endif
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
#endif
#ifndef GRUB_EMBED_DECOMPRESSOR
kfree(s);
#endif
}
}