mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
The libxc xc_dom_* infrastructure uses a very simple malloc memory pool which is freed by xc_dom_release. However the various xc_try_*_decode routines (other than the gzip one) just use plain malloc/realloc and therefore the buffer ends up leaked. The memory pool currently supports mmap'd buffers as well as a directly allocated buffers, however the try decode routines make use of realloc and do not fit well into this model. Introduce a concept of an external memory block to the memory pool and provide an interface to register such memory. The mmap_ptr and mmap_len fields of the memblock tracking struct lose their mmap_ prefix since they are now also used for external memory blocks. We are only seeing this now because the gzip decoder doesn't leak and it's only relatively recently that kernels in the wild have switched to better compression. This is https://bugs.debian.org/767295 Reported by: Gedalya <gedalya@gedalya.net> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Reviewed-by: Wei Liu <wei.liu2@citrix.com>
142 lines
2.6 KiB
C
142 lines
2.6 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <inttypes.h>
|
|
#include <stdint.h>
|
|
|
|
#include "xg_private.h"
|
|
#include "xc_dom_decompress.h"
|
|
|
|
#define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
|
|
|
typedef uint8_t u8;
|
|
typedef uint16_t u16;
|
|
typedef uint32_t u32;
|
|
typedef uint64_t u64;
|
|
|
|
#define likely(a) a
|
|
#define unlikely(a) a
|
|
|
|
static inline uint_fast16_t le16_to_cpup(const unsigned char *buf)
|
|
{
|
|
return buf[0] | (buf[1] << 8);
|
|
}
|
|
|
|
static inline uint_fast32_t le32_to_cpup(const unsigned char *buf)
|
|
{
|
|
return le16_to_cpup(buf) | ((uint32_t)le16_to_cpup(buf + 2) << 16);
|
|
}
|
|
|
|
#include "../../xen/include/xen/lz4.h"
|
|
#include "../../xen/common/decompress.h"
|
|
|
|
#ifndef __MINIOS__
|
|
|
|
#include "../../xen/common/lz4/decompress.c"
|
|
|
|
#define ARCHIVE_MAGICNUMBER 0x184C2102
|
|
|
|
int xc_try_lz4_decode(
|
|
struct xc_dom_image *dom, void **blob, size_t *psize)
|
|
{
|
|
int ret = -1;
|
|
unsigned char *inp = *blob, *output, *outp;
|
|
ssize_t size = *psize - 4;
|
|
size_t out_len, dest_len, chunksize;
|
|
const char *msg;
|
|
|
|
if (size < 4) {
|
|
msg = "input too small";
|
|
goto exit_0;
|
|
}
|
|
|
|
out_len = get_unaligned_le32(inp + size);
|
|
if (xc_dom_kernel_check_size(dom, out_len)) {
|
|
msg = "Decompressed image too large";
|
|
goto exit_0;
|
|
}
|
|
|
|
output = malloc(out_len);
|
|
if (!output) {
|
|
msg = "Could not allocate output buffer";
|
|
goto exit_0;
|
|
}
|
|
outp = output;
|
|
|
|
chunksize = get_unaligned_le32(inp);
|
|
if (chunksize == ARCHIVE_MAGICNUMBER) {
|
|
inp += 4;
|
|
size -= 4;
|
|
} else {
|
|
msg = "invalid header";
|
|
goto exit_2;
|
|
}
|
|
|
|
for (;;) {
|
|
if (size < 4) {
|
|
msg = "missing data";
|
|
goto exit_2;
|
|
}
|
|
chunksize = get_unaligned_le32(inp);
|
|
if (chunksize == ARCHIVE_MAGICNUMBER) {
|
|
inp += 4;
|
|
size -= 4;
|
|
continue;
|
|
}
|
|
inp += 4;
|
|
size -= 4;
|
|
if (chunksize > size) {
|
|
msg = "insufficient input data";
|
|
goto exit_2;
|
|
}
|
|
|
|
dest_len = out_len - (outp - output);
|
|
ret = lz4_decompress_unknownoutputsize(inp, chunksize, outp,
|
|
&dest_len);
|
|
if (ret < 0) {
|
|
msg = "decoding failed";
|
|
goto exit_2;
|
|
}
|
|
|
|
ret = -1;
|
|
outp += dest_len;
|
|
size -= chunksize;
|
|
|
|
if (size == 0)
|
|
{
|
|
if ( xc_dom_register_external(dom, output, out_len) )
|
|
{
|
|
msg = "Error registering stream output";
|
|
goto exit_2;
|
|
}
|
|
*blob = output;
|
|
*psize = out_len;
|
|
return 0;
|
|
}
|
|
|
|
if (size < 0) {
|
|
msg = "data corrupted";
|
|
goto exit_2;
|
|
}
|
|
|
|
inp += chunksize;
|
|
}
|
|
|
|
exit_2:
|
|
free(output);
|
|
exit_0:
|
|
DOMPRINTF("LZ4 decompression error: %s\n", msg);
|
|
return ret;
|
|
}
|
|
|
|
#else /* __MINIOS__ */
|
|
|
|
#include "../../xen/common/unlz4.c"
|
|
|
|
int xc_try_lz4_decode(
|
|
struct xc_dom_image *dom, void **blob, size_t *size)
|
|
{
|
|
return xc_dom_decompress_unsafe(unlz4, dom, blob, size);
|
|
}
|
|
|
|
#endif
|