|
[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 |