int xc_dom_try_gunzip(struct xc_dom_image *dom, void **blob, size_t * size) { void *unzip; size_t unziplen; unziplen = xc_dom_check_gzip(dom->xch, *blob, *size); if ( unziplen == 0 ) return 0; if ( xc_dom_kernel_check_size(dom, unziplen) ) return 0; unzip = xc_dom_malloc(dom, unziplen); if ( unzip == NULL ) return -1; if ( xc_dom_do_gunzip(dom->xch, *blob, *size, unzip, unziplen) == -1 ) return -1; *blob = unzip; *size = unziplen; return 0; }
static int xc_try_lzo1x_decode( struct xc_dom_image *dom, void **blob, size_t *size) { int ret; const unsigned char *cur = dom->kernel_blob; unsigned char *out_buf = NULL; size_t left = dom->kernel_size; const char *msg; unsigned version; static const unsigned char magic[] = { 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a }; /* * lzo_uint should match size_t. Check that this is the case to be * sure we won't overflow various lzo_uint fields. */ BUILD_BUG_ON(sizeof(lzo_uint) != sizeof(size_t)); ret = lzo_init(); if ( ret != LZO_E_OK ) { DOMPRINTF("LZO1x: Failed to init library (%d)\n", ret); return -1; } if ( left < 16 || memcmp(cur, magic, 9) ) { DOMPRINTF("LZO1x: Unrecognized magic\n"); return -1; } /* get version (2bytes), skip library version (2), * 'need to be extracted' version (2) and method (1) */ version = lzo_read_16(cur + 9); cur += 16; left -= 16; if ( version >= 0x0940 ) { /* skip level */ ++cur; if ( left ) --left; } if ( left >= 4 && (lzo_read_32(cur) & LZOP_HEADER_HAS_FILTER) ) ret = 8; /* flags + filter info */ else ret = 4; /* flags */ /* skip mode and mtime_low */ ret += 8; if ( version >= 0x0940 ) ret += 4; /* skip mtime_high */ /* don't care about the file name, and skip checksum */ if ( left > ret ) ret += 1 + cur[ret] + 4; if ( left < ret ) { DOMPRINTF("LZO1x: Incomplete header\n"); return -1; } cur += ret; left -= ret; for ( *size = 0; ; ) { lzo_uint src_len, dst_len, out_len; unsigned char *tmp_buf; msg = "Short input"; if ( left < 4 ) break; dst_len = lzo_read_32(cur); if ( !dst_len ) { msg = "Error registering stream output"; if ( xc_dom_register_external(dom, out_buf, *size) ) break; return 0; } if ( dst_len > LZOP_MAX_BLOCK_SIZE ) { msg = "Block size too large"; break; } if ( left < 12 ) break; src_len = lzo_read_32(cur + 4); cur += 12; /* also skip block checksum info */ left -= 12; msg = "Bad source length"; if ( src_len <= 0 || src_len > dst_len || src_len > left ) break; msg = "Output buffer overflow"; if ( *size > SIZE_MAX - dst_len ) break; msg = "Decompressed image too large"; if ( xc_dom_kernel_check_size(dom, *size + dst_len) ) break; msg = "Failed to (re)alloc memory"; tmp_buf = realloc(out_buf, *size + dst_len); if ( tmp_buf == NULL ) break; out_buf = tmp_buf; out_len = dst_len; ret = lzo1x_decompress_safe(cur, src_len, out_buf + *size, &out_len, NULL); switch ( ret ) { case LZO_E_OK: msg = "Input underrun"; if ( out_len != dst_len ) break; *blob = out_buf; *size += out_len; cur += src_len; left -= src_len; continue; case LZO_E_INPUT_NOT_CONSUMED: msg = "Unconsumed input"; break; case LZO_E_OUTPUT_OVERRUN: msg = "Output overrun"; break; case LZO_E_INPUT_OVERRUN: msg = "Input overrun"; break; case LZO_E_LOOKBEHIND_OVERRUN: msg = "Look-behind overrun"; break; case LZO_E_EOF_NOT_FOUND: msg = "No EOF marker"; break; case LZO_E_ERROR: msg = "General error"; break; default: msg = "Internal program error (bug)"; break; } break; } free(out_buf); DOMPRINTF("LZO1x decompression error: %s\n", msg); return -1; }
static int xc_try_bzip2_decode( struct xc_dom_image *dom, void **blob, size_t *size) { bz_stream stream; int ret; char *out_buf; char *tmp_buf; int retval = -1; unsigned int outsize; uint64_t total; stream.bzalloc = NULL; stream.bzfree = NULL; stream.opaque = NULL; if ( dom->kernel_size == 0) { DOMPRINTF("BZIP2: Input is 0 size"); return -1; } ret = BZ2_bzDecompressInit(&stream, 0, 0); if ( ret != BZ_OK ) { DOMPRINTF("BZIP2: Error initting stream"); return -1; } /* sigh. We don't know up-front how much memory we are going to need * for the output buffer. Allocate the output buffer to be equal * the input buffer to start, and we'll realloc as needed. */ outsize = dom->kernel_size; /* * stream.avail_in and outsize are unsigned int, while kernel_size * is a size_t. Check we aren't overflowing. */ if ( outsize != dom->kernel_size ) { DOMPRINTF("BZIP2: Input too large"); goto bzip2_cleanup; } out_buf = malloc(outsize); if ( out_buf == NULL ) { DOMPRINTF("BZIP2: Failed to alloc memory"); goto bzip2_cleanup; } stream.next_in = dom->kernel_blob; stream.avail_in = dom->kernel_size; stream.next_out = out_buf; stream.avail_out = dom->kernel_size; for ( ; ; ) { ret = BZ2_bzDecompress(&stream); if ( ret == BZ_STREAM_END ) { DOMPRINTF("BZIP2: Saw data stream end"); retval = 0; break; } if ( ret != BZ_OK ) { DOMPRINTF("BZIP2: error %d", ret); free(out_buf); goto bzip2_cleanup; } if ( stream.avail_out == 0 ) { /* Protect against output buffer overflow */ if ( outsize > UINT_MAX / 2 ) { DOMPRINTF("BZIP2: output buffer overflow"); free(out_buf); goto bzip2_cleanup; } if ( xc_dom_kernel_check_size(dom, outsize * 2) ) { DOMPRINTF("BZIP2: output too large"); free(out_buf); goto bzip2_cleanup; } tmp_buf = realloc(out_buf, outsize * 2); if ( tmp_buf == NULL ) { DOMPRINTF("BZIP2: Failed to realloc memory"); free(out_buf); goto bzip2_cleanup; } out_buf = tmp_buf; stream.next_out = out_buf + outsize; stream.avail_out = (outsize * 2) - outsize; outsize *= 2; } else if ( stream.avail_in == 0 ) { /* * If there is output buffer available then this indicates * that BZ2_bzDecompress would like more input data to be * provided. However our complete input buffer is in * memory and provided upfront so if avail_in is zero this * actually indicates a truncated input. */ DOMPRINTF("BZIP2: not enough input"); free(out_buf); goto bzip2_cleanup; } } total = (((uint64_t)stream.total_out_hi32) << 32) | stream.total_out_lo32; if ( xc_dom_register_external(dom, out_buf, total) ) { DOMPRINTF("BZIP2: Error registering stream output"); free(out_buf); goto bzip2_cleanup; } DOMPRINTF("%s: BZIP2 decompress OK, 0x%zx -> 0x%lx", __FUNCTION__, *size, (long unsigned int) total); *blob = out_buf; *size = total; bzip2_cleanup: BZ2_bzDecompressEnd(&stream); return retval; }
static int _xc_try_lzma_decode( struct xc_dom_image *dom, void **blob, size_t *size, lzma_stream *stream, const char *what) { lzma_ret ret; lzma_action action = LZMA_RUN; unsigned char *out_buf; unsigned char *tmp_buf; int retval = -1; size_t outsize; const char *msg; if ( dom->kernel_size == 0) { DOMPRINTF("%s: Input is 0 size", what); return -1; } /* sigh. We don't know up-front how much memory we are going to need * for the output buffer. Allocate the output buffer to be equal * the input buffer to start, and we'll realloc as needed. */ outsize = dom->kernel_size; out_buf = malloc(outsize); if ( out_buf == NULL ) { DOMPRINTF("%s: Failed to alloc memory", what); goto lzma_cleanup; } stream->next_in = dom->kernel_blob; stream->avail_in = dom->kernel_size; stream->next_out = out_buf; stream->avail_out = dom->kernel_size; for ( ; ; ) { ret = lzma_code(stream, action); if ( ret == LZMA_STREAM_END ) { DOMPRINTF("%s: Saw data stream end", what); retval = 0; break; } if ( ret != LZMA_OK ) { switch ( ret ) { case LZMA_MEM_ERROR: msg = strerror(ENOMEM); break; case LZMA_MEMLIMIT_ERROR: msg = "Memory usage limit reached"; break; case LZMA_FORMAT_ERROR: msg = "File format not recognized"; break; case LZMA_OPTIONS_ERROR: // FIXME: Better message? msg = "Unsupported compression options"; break; case LZMA_DATA_ERROR: msg = "File is corrupt"; break; case LZMA_BUF_ERROR: msg = "Unexpected end of input"; break; default: msg = "Internal program error (bug)"; break; } DOMPRINTF("%s: %s decompression error: %s", __FUNCTION__, what, msg); free(out_buf); goto lzma_cleanup; } if ( stream->avail_out == 0 ) { /* Protect against output buffer overflow */ if ( outsize > SIZE_MAX / 2 ) { DOMPRINTF("%s: output buffer overflow", what); free(out_buf); goto lzma_cleanup; } if ( xc_dom_kernel_check_size(dom, outsize * 2) ) { DOMPRINTF("%s: output too large", what); free(out_buf); goto lzma_cleanup; } tmp_buf = realloc(out_buf, outsize * 2); if ( tmp_buf == NULL ) { DOMPRINTF("%s: Failed to realloc memory", what); free(out_buf); goto lzma_cleanup; } out_buf = tmp_buf; stream->next_out = out_buf + outsize; stream->avail_out = (outsize * 2) - outsize; outsize *= 2; } } if ( xc_dom_register_external(dom, out_buf, stream->total_out) ) { DOMPRINTF("%s: Error registering stream output", what); free(out_buf); goto lzma_cleanup; } DOMPRINTF("%s: %s decompress OK, 0x%zx -> 0x%zx", __FUNCTION__, what, *size, (size_t)stream->total_out); *blob = out_buf; *size = stream->total_out; lzma_cleanup: lzma_end(stream); return retval; }