[Pkg-xen-devel] Bug#767295: [PATCH for-4.5 v2] libxc: don't leak buffer containing the uncompressed PV kernel
Gedalya
gedalya at gedalya.net
Fri Nov 21 03:19:16 UTC 2014
On 11/20/2014 10:13 PM, Gedalya wrote:
> On 11/20/2014 03:21 PM, Konrad Rzeszutek Wilk wrote:
>> On Thu, Nov 20, 2014 at 03:48:47PM +0000, Ian Campbell wrote:
>>> 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 at gedalya.net>
>> Gedelya,
>>
>> Could you also test this patch to make sure it does fix the
>> reported issue please?
>
> So here's what happens now.
> 1. Starts up tiny
> 2. reboot: leak
> 3. reboot: freed (process larger, but the delta is all/mostly shared
> pages)
> 4. reboot: leak
> 5. reboot: freed
> etc..
>
For the record, I applied it again the xen package currently in debian,
4.4.1-3, see attached patch.
The only problem was that tools/libxc/include/xc_dom.h is in
tools/libxc/xc_dom.h, otherwise it applied fine.
-------------- next part --------------
Index: xen-4.4.1/tools/libxc/xc_dom.h
===================================================================
--- xen-4.4.1.orig/tools/libxc/xc_dom.h
+++ xen-4.4.1/tools/libxc/xc_dom.h
@@ -33,8 +33,13 @@ struct xc_dom_seg {
struct xc_dom_mem {
struct xc_dom_mem *next;
- void *mmap_ptr;
- size_t mmap_len;
+ void *ptr;
+ enum {
+ XC_DOM_MEM_TYPE_MALLOC_INTERNAL,
+ XC_DOM_MEM_TYPE_MALLOC_EXTERNAL,
+ XC_DOM_MEM_TYPE_MMAP,
+ } type;
+ size_t len;
unsigned char memory[0];
};
@@ -290,6 +295,7 @@ void xc_dom_log_memory_footprint(struct
/* --- simple memory pool ------------------------------------------ */
void *xc_dom_malloc(struct xc_dom_image *dom, size_t size);
+int xc_dom_register_external(struct xc_dom_image *dom, void *ptr, size_t size);
void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size);
void *xc_dom_malloc_filemap(struct xc_dom_image *dom,
const char *filename, size_t * size,
Index: xen-4.4.1/tools/libxc/xc_dom_bzimageloader.c
===================================================================
--- xen-4.4.1.orig/tools/libxc/xc_dom_bzimageloader.c
+++ xen-4.4.1/tools/libxc/xc_dom_bzimageloader.c
@@ -161,6 +161,13 @@ static int xc_try_bzip2_decode(
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);
@@ -305,6 +312,13 @@ static int _xc_try_lzma_decode(
}
}
+ 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);
@@ -464,7 +478,13 @@ static int xc_try_lzo1x_decode(
dst_len = lzo_read_32(cur);
if ( !dst_len )
+ {
+ msg = "Error registering stream output";
+ if ( xc_dom_register_external(dom, out_buf, out_len) )
+ break;
+
return 0;
+ }
if ( dst_len > LZOP_MAX_BLOCK_SIZE )
{
Index: xen-4.4.1/tools/libxc/xc_dom_core.c
===================================================================
--- xen-4.4.1.orig/tools/libxc/xc_dom_core.c
+++ xen-4.4.1/tools/libxc/xc_dom_core.c
@@ -132,6 +132,7 @@ void *xc_dom_malloc(struct xc_dom_image
return NULL;
}
memset(block, 0, sizeof(*block) + size);
+ block->type = XC_DOM_MEM_TYPE_MALLOC_INTERNAL;
block->next = dom->memblocks;
dom->memblocks = block;
dom->alloc_malloc += sizeof(*block) + size;
@@ -151,23 +152,45 @@ void *xc_dom_malloc_page_aligned(struct
return NULL;
}
memset(block, 0, sizeof(*block));
- block->mmap_len = size;
- block->mmap_ptr = mmap(NULL, block->mmap_len,
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if ( block->mmap_ptr == MAP_FAILED )
+ block->len = size;
+ block->ptr = mmap(NULL, block->len,
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+ if ( block->ptr == MAP_FAILED )
{
DOMPRINTF("%s: mmap failed", __FUNCTION__);
free(block);
return NULL;
}
+ block->type = XC_DOM_MEM_TYPE_MMAP;
block->next = dom->memblocks;
dom->memblocks = block;
dom->alloc_malloc += sizeof(*block);
- dom->alloc_mem_map += block->mmap_len;
+ dom->alloc_mem_map += block->len;
if ( size > (100 * 1024) )
print_mem(dom, __FUNCTION__, size);
- return block->mmap_ptr;
+ return block->ptr;
+}
+
+int xc_dom_register_external(struct xc_dom_image *dom, void *ptr, size_t size)
+{
+ struct xc_dom_mem *block;
+
+ block = malloc(sizeof(*block));
+ if ( block == NULL )
+ {
+ DOMPRINTF("%s: allocation failed", __FUNCTION__);
+ return -1;
+ }
+ memset(block, 0, sizeof(*block));
+ block->ptr = ptr;
+ block->len = size;
+ block->type = XC_DOM_MEM_TYPE_MALLOC_EXTERNAL;
+ block->next = dom->memblocks;
+ dom->memblocks = block;
+ dom->alloc_malloc += sizeof(*block);
+ dom->alloc_mem_map += block->len;
+ return 0;
}
void *xc_dom_malloc_filemap(struct xc_dom_image *dom,
@@ -212,24 +235,25 @@ void *xc_dom_malloc_filemap(struct xc_do
}
memset(block, 0, sizeof(*block));
- block->mmap_len = *size;
- block->mmap_ptr = mmap(NULL, block->mmap_len, PROT_READ,
+ block->len = *size;
+ block->ptr = mmap(NULL, block->len, PROT_READ,
MAP_SHARED, fd, 0);
- if ( block->mmap_ptr == MAP_FAILED ) {
+ if ( block->ptr == MAP_FAILED ) {
xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
"failed to mmap file: %s",
strerror(errno));
goto err;
}
+ block->type = XC_DOM_MEM_TYPE_MMAP;
block->next = dom->memblocks;
dom->memblocks = block;
dom->alloc_malloc += sizeof(*block);
- dom->alloc_file_map += block->mmap_len;
+ dom->alloc_file_map += block->len;
close(fd);
if ( *size > (100 * 1024) )
print_mem(dom, __FUNCTION__, *size);
- return block->mmap_ptr;
+ return block->ptr;
err:
if ( fd != -1 )
@@ -246,8 +270,17 @@ static void xc_dom_free_all(struct xc_do
while ( (block = dom->memblocks) != NULL )
{
dom->memblocks = block->next;
- if ( block->mmap_ptr )
- munmap(block->mmap_ptr, block->mmap_len);
+ switch ( block->type )
+ {
+ case XC_DOM_MEM_TYPE_MALLOC_INTERNAL:
+ break;
+ case XC_DOM_MEM_TYPE_MALLOC_EXTERNAL:
+ free(block->ptr);
+ break;
+ case XC_DOM_MEM_TYPE_MMAP:
+ munmap(block->ptr, block->len);
+ break;
+ }
free(block);
}
}
Index: xen-4.4.1/tools/libxc/xc_dom_decompress_lz4.c
===================================================================
--- xen-4.4.1.orig/tools/libxc/xc_dom_decompress_lz4.c
+++ xen-4.4.1/tools/libxc/xc_dom_decompress_lz4.c
@@ -104,6 +104,11 @@ int xc_try_lz4_decode(
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;
More information about the Pkg-xen-devel
mailing list