[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC] libxc: Move compression support into own file
Move the existing decompression methods into its own file. Signed-off-by: Bastian Blank <waldi@xxxxxxxxxx> diff -r 66f563be41d9 tools/libxc/Makefile --- a/tools/libxc/Makefile Tue Feb 19 10:49:53 2013 +0100 +++ b/tools/libxc/Makefile Tue Feb 26 19:23:05 2013 +0100 @@ -58,6 +58,7 @@ GUEST_SRCS-y += xc_dom_core.c xc_dom_boot.c GUEST_SRCS-y += xc_dom_elfloader.c GUEST_SRCS-$(CONFIG_X86) += xc_dom_bzimageloader.c +GUEST_SRCS-$(CONFIG_X86) += xc_dom_decompress.c GUEST_SRCS-$(CONFIG_ARM) += xc_dom_armzimageloader.c GUEST_SRCS-y += xc_dom_binloader.c GUEST_SRCS-y += xc_dom_compat_linux.c @@ -182,8 +183,8 @@ zlib-options = $(ZLIB) endif -xc_dom_bzimageloader.o: CFLAGS += $(call zlib-options,D) -xc_dom_bzimageloader.opic: CFLAGS += $(call zlib-options,D) +xc_dom_decompress.o: CFLAGS += $(call zlib-options,D) +xc_dom_decompress.opic: CFLAGS += $(call zlib-options,D) libxenguest.so.$(MAJOR).$(MINOR): COMPRESSION_LIBS = $(call zlib-options,l) libxenguest.so.$(MAJOR).$(MINOR): $(GUEST_PIC_OBJS) libxenctrl.so diff -r 66f563be41d9 tools/libxc/xc_dom.h --- a/tools/libxc/xc_dom.h Tue Feb 19 10:49:53 2013 +0100 +++ b/tools/libxc/xc_dom.h Tue Feb 26 19:23:05 2013 +0100 @@ -293,6 +293,17 @@ void xc_dom_unmap_one(struct xc_dom_image *dom, xen_pfn_t pfn); void xc_dom_unmap_all(struct xc_dom_image *dom); +int xc_try_bzip2_decode(struct xc_dom_image *dom, void **blob, size_t *size) + __attribute__((visibility("hidden"))); +int xc_try_gzip_decode(struct xc_dom_image *dom, void **blob, size_t *size) + __attribute__((visibility("hidden"))); +int xc_try_lzma_decode(struct xc_dom_image *dom, void **blob, size_t *size) + __attribute__((visibility("hidden"))); +int xc_try_lzo1x_decode(struct xc_dom_image *dom, void **blob, size_t *size) + __attribute__((visibility("hidden"))); +int xc_try_xz_decode(struct xc_dom_image *dom, void **blob, size_t *size) + __attribute__((visibility("hidden"))); + static inline void *xc_dom_seg_to_ptr(struct xc_dom_image *dom, struct xc_dom_seg *seg) { diff -r 66f563be41d9 tools/libxc/xc_dom_bzimageloader.c --- a/tools/libxc/xc_dom_bzimageloader.c Tue Feb 19 10:49:53 2013 +0100 +++ b/tools/libxc/xc_dom_bzimageloader.c Tue Feb 26 19:23:05 2013 +0100 @@ -35,533 +35,6 @@ #include "xg_private.h" #include "xc_dom.h" -#if defined(HAVE_BZLIB) - -#include <bzlib.h> - -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; - - 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; -} - -#else /* !defined(HAVE_BZLIB) */ - -static int xc_try_bzip2_decode( - struct xc_dom_image *dom, void **blob, size_t *size) -{ - DOMPRINTF("%s: BZIP2 decompress support unavailable", - __FUNCTION__); - return -1; -} - -#endif - -#if defined(HAVE_LZMA) - -#include <lzma.h> - -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; - } - } - - 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; -} - -/* 128 Mb is the minimum size (half-way) documented to work for all inputs. */ -#define LZMA_BLOCK_SIZE (128*1024*1024) - -static int xc_try_xz_decode( - struct xc_dom_image *dom, void **blob, size_t *size) -{ - lzma_stream stream = LZMA_STREAM_INIT; - - if ( lzma_stream_decoder(&stream, LZMA_BLOCK_SIZE, 0) != LZMA_OK ) - { - DOMPRINTF("XZ: Failed to init decoder"); - return -1; - } - - return _xc_try_lzma_decode(dom, blob, size, &stream, "XZ"); -} - -static int xc_try_lzma_decode( - struct xc_dom_image *dom, void **blob, size_t *size) -{ - lzma_stream stream = LZMA_STREAM_INIT; - - if ( lzma_alone_decoder(&stream, LZMA_BLOCK_SIZE) != LZMA_OK ) - { - DOMPRINTF("LZMA: Failed to init decoder"); - return -1; - } - - return _xc_try_lzma_decode(dom, blob, size, &stream, "LZMA"); -} - -#else /* !defined(HAVE_LZMA) */ - -static int xc_try_xz_decode( - struct xc_dom_image *dom, void **blob, size_t *size) -{ - DOMPRINTF("%s: XZ decompress support unavailable", - __FUNCTION__); - return -1; -} - -static int xc_try_lzma_decode( - struct xc_dom_image *dom, void **blob, size_t *size) -{ - DOMPRINTF("%s: LZMA decompress support unavailable", - __FUNCTION__); - return -1; -} - -#endif - -#if defined(HAVE_LZO1X) - -#include <lzo/lzo1x.h> - -#define LZOP_HEADER_HAS_FILTER 0x00000800 -#define LZOP_MAX_BLOCK_SIZE (64*1024*1024) - -static inline uint_fast16_t lzo_read_16(const unsigned char *buf) -{ - return buf[1] | (buf[0] << 8); -} - -static inline uint_fast32_t lzo_read_32(const unsigned char *buf) -{ - return lzo_read_16(buf + 2) | ((uint32_t)lzo_read_16(buf) << 16); -} - -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. - */ - XC_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 ) - 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; -} - -#else /* !defined(HAVE_LZO1X) */ - -static int xc_try_lzo1x_decode( - struct xc_dom_image *dom, void **blob, size_t *size) -{ - DOMPRINTF("%s: LZO1x decompress support unavailable\n", - __FUNCTION__); - return -1; -} - -#endif - struct setup_header { uint8_t _pad0[0x1f1]; /* skip uninteresting stuff */ uint8_t setup_sects; diff -r 66f563be41d9 tools/libxc/xc_dom_decompress.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/xc_dom_decompress.c Tue Feb 26 19:23:05 2013 +0100 @@ -0,0 +1,567 @@ +/* + * Xen decompression wrapper + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * written 2006 by Gerd Hoffmann <kraxel@xxxxxxx>. + * written 2007 by Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx> + * written 2008 by Ian Campbell <ijc@xxxxxxxxxxxxxx> + * written 2009 by Chris Lalancette <clalance@xxxxxxxxxx> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> + +#include "xg_private.h" +#include "xc_dom.h" + +#if defined(HAVE_BZLIB) + +#include <bzlib.h> + +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; + + 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; +} + +#else /* !defined(HAVE_BZLIB) */ + +int xc_try_bzip2_decode( + struct xc_dom_image *dom, void **blob, size_t *size) +{ + DOMPRINTF("%s: BZIP2 decompress support unavailable", + __FUNCTION__); + return -1; +} + +#endif + +#if defined(HAVE_LZMA) + +#include <lzma.h> + +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; + } + } + + 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; +} + +/* 128 Mb is the minimum size (half-way) documented to work for all inputs. */ +#define LZMA_BLOCK_SIZE (128*1024*1024) + +int xc_try_xz_decode( + struct xc_dom_image *dom, void **blob, size_t *size) +{ + lzma_stream stream = LZMA_STREAM_INIT; + + if ( lzma_stream_decoder(&stream, LZMA_BLOCK_SIZE, 0) != LZMA_OK ) + { + DOMPRINTF("XZ: Failed to init decoder"); + return -1; + } + + return _xc_try_lzma_decode(dom, blob, size, &stream, "XZ"); +} + +int xc_try_lzma_decode( + struct xc_dom_image *dom, void **blob, size_t *size) +{ + lzma_stream stream = LZMA_STREAM_INIT; + + if ( lzma_alone_decoder(&stream, LZMA_BLOCK_SIZE) != LZMA_OK ) + { + DOMPRINTF("LZMA: Failed to init decoder"); + return -1; + } + + return _xc_try_lzma_decode(dom, blob, size, &stream, "LZMA"); +} + +#else /* !defined(HAVE_LZMA) */ + +int xc_try_xz_decode( + struct xc_dom_image *dom, void **blob, size_t *size) +{ + DOMPRINTF("%s: XZ decompress support unavailable", + __FUNCTION__); + return -1; +} + +int xc_try_lzma_decode( + struct xc_dom_image *dom, void **blob, size_t *size) +{ + DOMPRINTF("%s: LZMA decompress support unavailable", + __FUNCTION__); + return -1; +} + +#endif + +#if defined(HAVE_LZO1X) + +#include <lzo/lzo1x.h> + +#define LZOP_HEADER_HAS_FILTER 0x00000800 +#define LZOP_MAX_BLOCK_SIZE (64*1024*1024) + +static inline uint_fast16_t lzo_read_16(const unsigned char *buf) +{ + return buf[1] | (buf[0] << 8); +} + +static inline uint_fast32_t lzo_read_32(const unsigned char *buf) +{ + return lzo_read_16(buf + 2) | ((uint32_t)lzo_read_16(buf) << 16); +} + +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. + */ + XC_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 ) + 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; +} + +#else /* !defined(HAVE_LZO1X) */ + +int xc_try_lzo1x_decode( + struct xc_dom_image *dom, void **blob, size_t *size) +{ + DOMPRINTF("%s: LZO1x decompress support unavailable\n", + __FUNCTION__); + return -1; +} + +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |