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