|
|
1c5bb4e |
From a2986a7959919bc748784bb75970bfbd42697d3b Mon Sep 17 00:00:00 2001
|
|
|
1c5bb4e |
From: Ian Jackson <ian.jackson@eu.citrix.com>
|
|
|
1c5bb4e |
Date: Fri, 14 Jun 2013 16:45:41 +0100
|
|
|
1c5bb4e |
Subject: [PATCH 19/21] libxc: check return values from malloc
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
A sufficiently malformed input to libxc (such as a malformed input ELF
|
|
|
1c5bb4e |
or other guest-controlled data) might cause one of libxc's malloc() to
|
|
|
1c5bb4e |
fail. In this case we need to make sure we don't dereference or do
|
|
|
1c5bb4e |
pointer arithmetic on the result.
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
Search for all occurrences of \b(m|c|re)alloc in libxc, and all
|
|
|
1c5bb4e |
functions which call them, and add appropriate error checking where
|
|
|
1c5bb4e |
missing.
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
This includes the functions xc_dom_malloc*, which now print a message
|
|
|
1c5bb4e |
when they fail so that callers don't have to do so.
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
The function xc_cpuid_to_str wasn't provided with a sane return value
|
|
|
1c5bb4e |
and has a pretty strange API, which now becomes a little stranger.
|
|
|
1c5bb4e |
There are no in-tree callers.
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
Changes in the Xen 4.2 version of this series:
|
|
|
1c5bb4e |
* No need to fix code relating to ARM.
|
|
|
1c5bb4e |
* No need to fix code relating to superpage support.
|
|
|
1c5bb4e |
* Additionally fix `dom->p2m_host = xc_dom_malloc...' in xc_dom_ia64.c.
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
Changes in the Xen 4.1 version of this series:
|
|
|
1c5bb4e |
* An additional check is needed in xc_flask.c:xc_flask_access.
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
This is part of the fix to a security issue, XSA-55.
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
|
|
|
1c5bb4e |
---
|
|
|
1c5bb4e |
tools/libxc/xc_cpuid_x86.c | 20 ++++++++++++++++++--
|
|
|
1c5bb4e |
tools/libxc/xc_dom_core.c | 13 +++++++++++++
|
|
|
1c5bb4e |
tools/libxc/xc_dom_elfloader.c | 2 ++
|
|
|
1c5bb4e |
tools/libxc/xc_dom_ia64.c | 6 ++++++
|
|
|
1c5bb4e |
tools/libxc/xc_dom_x86.c | 3 +++
|
|
|
1c5bb4e |
tools/libxc/xc_domain_restore.c | 5 +++++
|
|
|
1c5bb4e |
tools/libxc/xc_flask.c | 2 ++
|
|
|
1c5bb4e |
tools/libxc/xc_linux_osdep.c | 4 ++++
|
|
|
1c5bb4e |
tools/libxc/xc_private.c | 2 ++
|
|
|
1c5bb4e |
tools/libxc/xenctrl.h | 2 +-
|
|
|
1c5bb4e |
10 files changed, 56 insertions(+), 3 deletions(-)
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
|
|
|
1c5bb4e |
index f61308a..5adf2d9 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_cpuid_x86.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_cpuid_x86.c
|
|
|
1c5bb4e |
@@ -515,6 +515,8 @@ static int xc_cpuid_do_domctl(
|
|
|
1c5bb4e |
static char *alloc_str(void)
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
char *s = malloc(33);
|
|
|
1c5bb4e |
+ if ( s == NULL )
|
|
|
1c5bb4e |
+ return s;
|
|
|
1c5bb4e |
memset(s, 0, 33);
|
|
|
1c5bb4e |
return s;
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
@@ -526,6 +528,8 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs)
|
|
|
1c5bb4e |
for ( i = 0; i < 4; i++ )
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
strs[i] = alloc_str();
|
|
|
1c5bb4e |
+ if ( strs[i] == NULL )
|
|
|
1c5bb4e |
+ continue;
|
|
|
1c5bb4e |
for ( j = 0; j < 32; j++ )
|
|
|
1c5bb4e |
strs[i][j] = !!((regs[i] & (1U << (31 - j)))) ? '1' : '0';
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
@@ -599,7 +603,7 @@ int xc_cpuid_check(
|
|
|
1c5bb4e |
const char **config,
|
|
|
1c5bb4e |
char **config_transformed)
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
- int i, j;
|
|
|
1c5bb4e |
+ int i, j, rc;
|
|
|
1c5bb4e |
unsigned int regs[4];
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
memset(config_transformed, 0, 4 * sizeof(*config_transformed));
|
|
|
1c5bb4e |
@@ -611,6 +615,11 @@ int xc_cpuid_check(
|
|
|
1c5bb4e |
if ( config[i] == NULL )
|
|
|
1c5bb4e |
continue;
|
|
|
1c5bb4e |
config_transformed[i] = alloc_str();
|
|
|
1c5bb4e |
+ if ( config_transformed[i] == NULL )
|
|
|
1c5bb4e |
+ {
|
|
|
1c5bb4e |
+ rc = -ENOMEM;
|
|
|
1c5bb4e |
+ goto fail_rc;
|
|
|
1c5bb4e |
+ }
|
|
|
1c5bb4e |
for ( j = 0; j < 32; j++ )
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
unsigned char val = !!((regs[i] & (1U << (31 - j))));
|
|
|
1c5bb4e |
@@ -627,12 +636,14 @@ int xc_cpuid_check(
|
|
|
1c5bb4e |
return 0;
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
fail:
|
|
|
1c5bb4e |
+ rc = -EPERM;
|
|
|
1c5bb4e |
+ fail_rc:
|
|
|
1c5bb4e |
for ( i = 0; i < 4; i++ )
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
free(config_transformed[i]);
|
|
|
1c5bb4e |
config_transformed[i] = NULL;
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
- return -EPERM;
|
|
|
1c5bb4e |
+ return rc;
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
/*
|
|
|
1c5bb4e |
@@ -677,6 +688,11 @@ int xc_cpuid_set(
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
config_transformed[i] = alloc_str();
|
|
|
1c5bb4e |
+ if ( config_transformed[i] == NULL )
|
|
|
1c5bb4e |
+ {
|
|
|
1c5bb4e |
+ rc = -ENOMEM;
|
|
|
1c5bb4e |
+ goto fail;
|
|
|
1c5bb4e |
+ }
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
for ( j = 0; j < 32; j++ )
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
|
|
|
1c5bb4e |
index a54ddae..3cbf9f7 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_dom_core.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_dom_core.c
|
|
|
1c5bb4e |
@@ -120,9 +120,17 @@ void *xc_dom_malloc(struct xc_dom_image *dom, size_t size)
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
struct xc_dom_mem *block;
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
+ if ( size > SIZE_MAX - sizeof(*block) )
|
|
|
1c5bb4e |
+ {
|
|
|
1c5bb4e |
+ DOMPRINTF("%s: unreasonable allocation size", __FUNCTION__);
|
|
|
1c5bb4e |
+ return NULL;
|
|
|
1c5bb4e |
+ }
|
|
|
1c5bb4e |
block = malloc(sizeof(*block) + size);
|
|
|
1c5bb4e |
if ( block == NULL )
|
|
|
1c5bb4e |
+ {
|
|
|
1c5bb4e |
+ DOMPRINTF("%s: allocation failed", __FUNCTION__);
|
|
|
1c5bb4e |
return NULL;
|
|
|
1c5bb4e |
+ }
|
|
|
1c5bb4e |
memset(block, 0, sizeof(*block) + size);
|
|
|
1c5bb4e |
block->next = dom->memblocks;
|
|
|
1c5bb4e |
dom->memblocks = block;
|
|
|
1c5bb4e |
@@ -138,7 +146,10 @@ void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size)
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
block = malloc(sizeof(*block));
|
|
|
1c5bb4e |
if ( block == NULL )
|
|
|
1c5bb4e |
+ {
|
|
|
1c5bb4e |
+ DOMPRINTF("%s: allocation failed", __FUNCTION__);
|
|
|
1c5bb4e |
return NULL;
|
|
|
1c5bb4e |
+ }
|
|
|
1c5bb4e |
memset(block, 0, sizeof(*block));
|
|
|
1c5bb4e |
block->mmap_len = size;
|
|
|
1c5bb4e |
block->mmap_ptr = mmap(NULL, block->mmap_len,
|
|
|
1c5bb4e |
@@ -146,6 +157,7 @@ void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size)
|
|
|
1c5bb4e |
-1, 0);
|
|
|
1c5bb4e |
if ( block->mmap_ptr == MAP_FAILED )
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
+ DOMPRINTF("%s: mmap failed", __FUNCTION__);
|
|
|
1c5bb4e |
free(block);
|
|
|
1c5bb4e |
return NULL;
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
@@ -202,6 +214,7 @@ void *xc_dom_malloc_filemap(struct xc_dom_image *dom,
|
|
|
1c5bb4e |
close(fd);
|
|
|
1c5bb4e |
if ( block != NULL )
|
|
|
1c5bb4e |
free(block);
|
|
|
1c5bb4e |
+ DOMPRINTF("%s: failed (on file `%s')", __FUNCTION__, filename);
|
|
|
1c5bb4e |
return NULL;
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_dom_elfloader.c b/tools/libxc/xc_dom_elfloader.c
|
|
|
1c5bb4e |
index aa6b5f0..0fb3629 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_dom_elfloader.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_dom_elfloader.c
|
|
|
1c5bb4e |
@@ -329,6 +329,8 @@ static elf_errorstatus xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
|
|
|
1c5bb4e |
return rc;
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
elf = xc_dom_malloc(dom, sizeof(*elf));
|
|
|
1c5bb4e |
+ if ( elf == NULL )
|
|
|
1c5bb4e |
+ return -1;
|
|
|
1c5bb4e |
dom->private_loader = elf;
|
|
|
1c5bb4e |
rc = elf_init(elf, dom->kernel_blob, dom->kernel_size);
|
|
|
1c5bb4e |
xc_elf_set_logfile(dom->xch, elf, 1);
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_dom_ia64.c b/tools/libxc/xc_dom_ia64.c
|
|
|
1c5bb4e |
index 7c0eff1..076821c 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_dom_ia64.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_dom_ia64.c
|
|
|
1c5bb4e |
@@ -188,6 +188,12 @@ int arch_setup_meminit(struct xc_dom_image *dom)
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
/* setup initial p2m */
|
|
|
1c5bb4e |
dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * nbr);
|
|
|
1c5bb4e |
+ if ( dom->p2m_host == NULL )
|
|
|
1c5bb4e |
+ {
|
|
|
1c5bb4e |
+ DOMPRINTF("%s: xc_dom_malloc failed for p2m_host",
|
|
|
1c5bb4e |
+ __FUNCTION__);
|
|
|
1c5bb4e |
+ return -1;
|
|
|
1c5bb4e |
+ }
|
|
|
1c5bb4e |
for ( pfn = 0; pfn < nbr; pfn++ )
|
|
|
1c5bb4e |
dom->p2m_host[pfn] = start + pfn;
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c
|
|
|
1c5bb4e |
index 75d6b83..448d9a1 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_dom_x86.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_dom_x86.c
|
|
|
1c5bb4e |
@@ -780,6 +780,9 @@ int arch_setup_meminit(struct xc_dom_image *dom)
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * dom->total_pages);
|
|
|
1c5bb4e |
+ if ( dom->p2m_host == NULL )
|
|
|
1c5bb4e |
+ return -EINVAL;
|
|
|
1c5bb4e |
+
|
|
|
1c5bb4e |
if ( dom->superpages )
|
|
|
1c5bb4e |
{
|
|
|
1c5bb4e |
int count = dom->total_pages >> SUPERPAGE_PFN_SHIFT;
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c
|
|
|
1c5bb4e |
index 29af52b..0f1e2d1 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_domain_restore.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_domain_restore.c
|
|
|
1c5bb4e |
@@ -967,6 +967,11 @@ static int apply_batch(xc_interface *xch, uint32_t dom, struct restore_ctx *ctx,
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
/* Map relevant mfns */
|
|
|
1c5bb4e |
pfn_err = calloc(j, sizeof(*pfn_err));
|
|
|
1c5bb4e |
+ if ( pfn_err == NULL )
|
|
|
1c5bb4e |
+ {
|
|
|
1c5bb4e |
+ PERROR("allocation for pfn_err failed");
|
|
|
1c5bb4e |
+ return -1;
|
|
|
1c5bb4e |
+ }
|
|
|
1c5bb4e |
region_base = xc_map_foreign_bulk(
|
|
|
1c5bb4e |
xch, dom, PROT_WRITE, region_mfn, pfn_err, j);
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_flask.c b/tools/libxc/xc_flask.c
|
|
|
1c5bb4e |
index 27794a8..78c243c 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_flask.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_flask.c
|
|
|
1c5bb4e |
@@ -284,6 +284,8 @@ int xc_flask_access(xc_interface *xc_handle, const char *scon, const char *tcon,
|
|
|
1c5bb4e |
MAX_SHORT_DEC_LEN + 1 +
|
|
|
1c5bb4e |
sizeof(req)*2 + 1;
|
|
|
1c5bb4e |
buf = malloc(bufLen);
|
|
|
1c5bb4e |
+ if ( buf == NULL )
|
|
|
1c5bb4e |
+ return -ENOMEM;
|
|
|
1c5bb4e |
snprintf(buf, bufLen, "%s %s %hu %x", scon, tcon, tclass, req);
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
op.cmd = FLASK_ACCESS;
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
|
|
|
1c5bb4e |
index 6477ad8..fa7bb7c 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_linux_osdep.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_linux_osdep.c
|
|
|
1c5bb4e |
@@ -294,6 +294,8 @@ static void *linux_privcmd_map_foreign_range(xc_interface *xch, xc_osdep_handle
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT;
|
|
|
1c5bb4e |
arr = calloc(num, sizeof(xen_pfn_t));
|
|
|
1c5bb4e |
+ if ( arr == NULL )
|
|
|
1c5bb4e |
+ return NULL;
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
for ( i = 0; i < num; i++ )
|
|
|
1c5bb4e |
arr[i] = mfn + i;
|
|
|
1c5bb4e |
@@ -318,6 +320,8 @@ static void *linux_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handle
|
|
|
1c5bb4e |
num_per_entry = chunksize >> XC_PAGE_SHIFT;
|
|
|
1c5bb4e |
num = num_per_entry * nentries;
|
|
|
1c5bb4e |
arr = calloc(num, sizeof(xen_pfn_t));
|
|
|
1c5bb4e |
+ if ( arr == NULL )
|
|
|
1c5bb4e |
+ return NULL;
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
for ( i = 0; i < nentries; i++ )
|
|
|
1c5bb4e |
for ( j = 0; j < num_per_entry; j++ )
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
|
|
|
1c5bb4e |
index 09c8f23..1bf25d2 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xc_private.c
|
|
|
1c5bb4e |
+++ b/tools/libxc/xc_private.c
|
|
|
1c5bb4e |
@@ -742,6 +742,8 @@ const char *xc_strerror(xc_interface *xch, int errcode)
|
|
|
1c5bb4e |
errbuf = pthread_getspecific(errbuf_pkey);
|
|
|
1c5bb4e |
if (errbuf == NULL) {
|
|
|
1c5bb4e |
errbuf = malloc(XS_BUFSIZE);
|
|
|
1c5bb4e |
+ if ( errbuf == NULL )
|
|
|
1c5bb4e |
+ return "(failed to allocate errbuf)";
|
|
|
1c5bb4e |
pthread_setspecific(errbuf_pkey, errbuf);
|
|
|
1c5bb4e |
}
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
|
|
|
1c5bb4e |
index 570c6d4..9bc9172 100644
|
|
|
1c5bb4e |
--- a/tools/libxc/xenctrl.h
|
|
|
1c5bb4e |
+++ b/tools/libxc/xenctrl.h
|
|
|
1c5bb4e |
@@ -1608,7 +1608,7 @@ int xc_cpuid_set(xc_interface *xch,
|
|
|
1c5bb4e |
int xc_cpuid_apply_policy(xc_interface *xch,
|
|
|
1c5bb4e |
domid_t domid);
|
|
|
1c5bb4e |
void xc_cpuid_to_str(const unsigned int *regs,
|
|
|
1c5bb4e |
- char **strs);
|
|
|
1c5bb4e |
+ char **strs); /* some strs[] may be NULL if ENOMEM */
|
|
|
1c5bb4e |
int xc_mca_op(xc_interface *xch, struct xen_mc *mc);
|
|
|
1c5bb4e |
#endif
|
|
|
1c5bb4e |
|
|
|
1c5bb4e |
--
|
|
|
1c5bb4e |
1.7.2.5
|
|
|
1c5bb4e |
|