summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app-emulation/xen-tools/files/xen-4.2-CVE-2013-20to23-XSA-55.patch')
-rw-r--r--app-emulation/xen-tools/files/xen-4.2-CVE-2013-20to23-XSA-55.patch381
1 files changed, 381 insertions, 0 deletions
diff --git a/app-emulation/xen-tools/files/xen-4.2-CVE-2013-20to23-XSA-55.patch b/app-emulation/xen-tools/files/xen-4.2-CVE-2013-20to23-XSA-55.patch
new file mode 100644
index 000000000000..b4c6dcad2961
--- /dev/null
+++ b/app-emulation/xen-tools/files/xen-4.2-CVE-2013-20to23-XSA-55.patch
@@ -0,0 +1,381 @@
+From 8dc90d163650ce8aa36ae0b46debab83cc61edb6 Mon Sep 17 00:00:00 2001
+From: Ian Jackson <ian.jackson@eu.citrix.com>
+Date: Fri, 14 Jun 2013 16:43:19 +0100
+Subject: [PATCH 20/23] libxc: check return values from malloc
+
+A sufficiently malformed input to libxc (such as a malformed input ELF
+or other guest-controlled data) might cause one of libxc's malloc() to
+fail. In this case we need to make sure we don't dereference or do
+pointer arithmetic on the result.
+
+Search for all occurrences of \b(m|c|re)alloc in libxc, and all
+functions which call them, and add appropriate error checking where
+missing.
+
+This includes the functions xc_dom_malloc*, which now print a message
+when they fail so that callers don't have to do so.
+
+The function xc_cpuid_to_str wasn't provided with a sane return value
+and has a pretty strange API, which now becomes a little stranger.
+There are no in-tree callers.
+
+Changes in the Xen 4.2 version of this series:
+* No need to fix code relating to ARM.
+* No need to fix code relating to superpage support.
+* Additionally fix `dom->p2m_host = xc_dom_malloc...' in xc_dom_ia64.c.
+
+This is part of the fix to a security issue, XSA-55.
+
+Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
+---
+ tools/libxc/xc_cpuid_x86.c | 20 ++++++++++++++++++--
+ tools/libxc/xc_dom_core.c | 13 +++++++++++++
+ tools/libxc/xc_dom_elfloader.c | 2 ++
+ tools/libxc/xc_dom_ia64.c | 6 ++++++
+ tools/libxc/xc_dom_x86.c | 3 +++
+ tools/libxc/xc_domain_restore.c | 5 +++++
+ tools/libxc/xc_linux_osdep.c | 4 ++++
+ tools/libxc/xc_private.c | 2 ++
+ tools/libxc/xenctrl.h | 2 +-
+ 9 files changed, 54 insertions(+), 3 deletions(-)
+
+diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
+index 0882ce6..da435ce 100644
+--- a/tools/libxc/xc_cpuid_x86.c
++++ b/tools/libxc/xc_cpuid_x86.c
+@@ -589,6 +589,8 @@ static int xc_cpuid_do_domctl(
+ static char *alloc_str(void)
+ {
+ char *s = malloc(33);
++ if ( s == NULL )
++ return s;
+ memset(s, 0, 33);
+ return s;
+ }
+@@ -600,6 +602,8 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs)
+ for ( i = 0; i < 4; i++ )
+ {
+ strs[i] = alloc_str();
++ if ( strs[i] == NULL )
++ continue;
+ for ( j = 0; j < 32; j++ )
+ strs[i][j] = !!((regs[i] & (1U << (31 - j)))) ? '1' : '0';
+ }
+@@ -680,7 +684,7 @@ int xc_cpuid_check(
+ const char **config,
+ char **config_transformed)
+ {
+- int i, j;
++ int i, j, rc;
+ unsigned int regs[4];
+
+ memset(config_transformed, 0, 4 * sizeof(*config_transformed));
+@@ -692,6 +696,11 @@ int xc_cpuid_check(
+ if ( config[i] == NULL )
+ continue;
+ config_transformed[i] = alloc_str();
++ if ( config_transformed[i] == NULL )
++ {
++ rc = -ENOMEM;
++ goto fail_rc;
++ }
+ for ( j = 0; j < 32; j++ )
+ {
+ unsigned char val = !!((regs[i] & (1U << (31 - j))));
+@@ -708,12 +717,14 @@ int xc_cpuid_check(
+ return 0;
+
+ fail:
++ rc = -EPERM;
++ fail_rc:
+ for ( i = 0; i < 4; i++ )
+ {
+ free(config_transformed[i]);
+ config_transformed[i] = NULL;
+ }
+- return -EPERM;
++ return rc;
+ }
+
+ /*
+@@ -758,6 +769,11 @@ int xc_cpuid_set(
+ }
+
+ config_transformed[i] = alloc_str();
++ if ( config_transformed[i] == NULL )
++ {
++ rc = -ENOMEM;
++ goto fail;
++ }
+
+ for ( j = 0; j < 32; j++ )
+ {
+diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
+index a54ddae..3cbf9f7 100644
+--- a/tools/libxc/xc_dom_core.c
++++ b/tools/libxc/xc_dom_core.c
+@@ -120,9 +120,17 @@ void *xc_dom_malloc(struct xc_dom_image *dom, size_t size)
+ {
+ struct xc_dom_mem *block;
+
++ if ( size > SIZE_MAX - sizeof(*block) )
++ {
++ DOMPRINTF("%s: unreasonable allocation size", __FUNCTION__);
++ return NULL;
++ }
+ block = malloc(sizeof(*block) + size);
+ if ( block == NULL )
++ {
++ DOMPRINTF("%s: allocation failed", __FUNCTION__);
+ return NULL;
++ }
+ memset(block, 0, sizeof(*block) + size);
+ block->next = dom->memblocks;
+ dom->memblocks = block;
+@@ -138,7 +146,10 @@ void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size)
+
+ block = malloc(sizeof(*block));
+ if ( block == NULL )
++ {
++ DOMPRINTF("%s: allocation failed", __FUNCTION__);
+ return NULL;
++ }
+ memset(block, 0, sizeof(*block));
+ block->mmap_len = size;
+ block->mmap_ptr = mmap(NULL, block->mmap_len,
+@@ -146,6 +157,7 @@ void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size)
+ -1, 0);
+ if ( block->mmap_ptr == MAP_FAILED )
+ {
++ DOMPRINTF("%s: mmap failed", __FUNCTION__);
+ free(block);
+ return NULL;
+ }
+@@ -202,6 +214,7 @@ void *xc_dom_malloc_filemap(struct xc_dom_image *dom,
+ close(fd);
+ if ( block != NULL )
+ free(block);
++ DOMPRINTF("%s: failed (on file `%s')", __FUNCTION__, filename);
+ return NULL;
+ }
+
+diff --git a/tools/libxc/xc_dom_elfloader.c b/tools/libxc/xc_dom_elfloader.c
+index 61b5798..be58276 100644
+--- a/tools/libxc/xc_dom_elfloader.c
++++ b/tools/libxc/xc_dom_elfloader.c
+@@ -329,6 +329,8 @@ static elf_errorstatus xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
+ return rc;
+
+ elf = xc_dom_malloc(dom, sizeof(*elf));
++ if ( elf == NULL )
++ return -1;
+ dom->private_loader = elf;
+ rc = elf_init(elf, dom->kernel_blob, dom->kernel_size);
+ xc_elf_set_logfile(dom->xch, elf, 1);
+diff --git a/tools/libxc/xc_dom_ia64.c b/tools/libxc/xc_dom_ia64.c
+index 7c0eff1..076821c 100644
+--- a/tools/libxc/xc_dom_ia64.c
++++ b/tools/libxc/xc_dom_ia64.c
+@@ -188,6 +188,12 @@ int arch_setup_meminit(struct xc_dom_image *dom)
+
+ /* setup initial p2m */
+ dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * nbr);
++ if ( dom->p2m_host == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_malloc failed for p2m_host",
++ __FUNCTION__);
++ return -1;
++ }
+ for ( pfn = 0; pfn < nbr; pfn++ )
+ dom->p2m_host[pfn] = start + pfn;
+
+diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c
+index 75d6b83..448d9a1 100644
+--- a/tools/libxc/xc_dom_x86.c
++++ b/tools/libxc/xc_dom_x86.c
+@@ -780,6 +780,9 @@ int arch_setup_meminit(struct xc_dom_image *dom)
+ }
+
+ dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * dom->total_pages);
++ if ( dom->p2m_host == NULL )
++ return -EINVAL;
++
+ if ( dom->superpages )
+ {
+ int count = dom->total_pages >> SUPERPAGE_PFN_SHIFT;
+diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c
+index 3994f8f..f9ed6b2 100644
+--- a/tools/libxc/xc_domain_restore.c
++++ b/tools/libxc/xc_domain_restore.c
+@@ -1180,6 +1180,11 @@ static int apply_batch(xc_interface *xch, uint32_t dom, struct restore_ctx *ctx,
+
+ /* Map relevant mfns */
+ pfn_err = calloc(j, sizeof(*pfn_err));
++ if ( pfn_err == NULL )
++ {
++ PERROR("allocation for pfn_err failed");
++ return -1;
++ }
+ region_base = xc_map_foreign_bulk(
+ xch, dom, PROT_WRITE, region_mfn, pfn_err, j);
+
+diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
+index 787e742..98e041c 100644
+--- a/tools/libxc/xc_linux_osdep.c
++++ b/tools/libxc/xc_linux_osdep.c
+@@ -378,6 +378,8 @@ static void *linux_privcmd_map_foreign_range(xc_interface *xch, xc_osdep_handle
+
+ num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT;
+ arr = calloc(num, sizeof(xen_pfn_t));
++ if ( arr == NULL )
++ return NULL;
+
+ for ( i = 0; i < num; i++ )
+ arr[i] = mfn + i;
+@@ -402,6 +404,8 @@ static void *linux_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handle
+ num_per_entry = chunksize >> XC_PAGE_SHIFT;
+ num = num_per_entry * nentries;
+ arr = calloc(num, sizeof(xen_pfn_t));
++ if ( arr == NULL )
++ return NULL;
+
+ for ( i = 0; i < nentries; i++ )
+ for ( j = 0; j < num_per_entry; j++ )
+diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
+index 3e03a91..848ceed 100644
+--- a/tools/libxc/xc_private.c
++++ b/tools/libxc/xc_private.c
+@@ -771,6 +771,8 @@ const char *xc_strerror(xc_interface *xch, int errcode)
+ errbuf = pthread_getspecific(errbuf_pkey);
+ if (errbuf == NULL) {
+ errbuf = malloc(XS_BUFSIZE);
++ if ( errbuf == NULL )
++ return "(failed to allocate errbuf)";
+ pthread_setspecific(errbuf_pkey, errbuf);
+ }
+
+diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
+index b7741ca..8952048 100644
+--- a/tools/libxc/xenctrl.h
++++ b/tools/libxc/xenctrl.h
+@@ -1778,7 +1778,7 @@ int xc_cpuid_set(xc_interface *xch,
+ int xc_cpuid_apply_policy(xc_interface *xch,
+ domid_t domid);
+ void xc_cpuid_to_str(const unsigned int *regs,
+- char **strs);
++ char **strs); /* some strs[] may be NULL if ENOMEM */
+ int xc_mca_op(xc_interface *xch, struct xen_mc *mc);
+ #endif
+
+--
+1.7.2.5
+#From 052a689aa526ca51fd70528d4b0f83dfb2de99c1 Mon Sep 17 00:00:00 2001
+#From: Ian Jackson <ian.jackson@eu.citrix.com>
+#Date: Fri, 14 Jun 2013 16:43:19 +0100
+#Subject: [PATCH 21/23] libxc: range checks in xc_dom_p2m_host and _guest
+#
+#These functions take guest pfns and look them up in the p2m. They did
+#no range checking.
+#
+#However, some callers, notably xc_dom_boot.c:setup_hypercall_page want
+#to pass untrusted guest-supplied value(s). It is most convenient to
+#detect this here and return INVALID_MFN.
+#
+#This is part of the fix to a security issue, XSA-55.
+#
+#Changes from Xen 4.2 version of this patch:
+#* 4.2 lacks dom->rambase_pfn, so don't add/subtract/check it.
+#
+#Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
+#---
+# tools/libxc/xc_dom.h | 4 ++++
+# 1 files changed, 4 insertions(+), 0 deletions(-)
+#
+diff --git a/tools/libxc/xc_dom.h b/tools/libxc/xc_dom.h
+index 0161459..d801f66 100644
+--- a/tools/libxc/xc_dom.h
++++ b/tools/libxc/xc_dom.h
+@@ -331,6 +331,8 @@ static inline xen_pfn_t xc_dom_p2m_host(struct xc_dom_image *dom, xen_pfn_t pfn)
+ {
+ if (dom->shadow_enabled)
+ return pfn;
++ if (pfn >= dom->total_pages)
++ return INVALID_MFN;
+ return dom->p2m_host[pfn];
+ }
+
+@@ -339,6 +341,8 @@ static inline xen_pfn_t xc_dom_p2m_guest(struct xc_dom_image *dom,
+ {
+ if (xc_dom_feature_translated(dom))
+ return pfn;
++ if (pfn >= dom->total_pages)
++ return INVALID_MFN;
+ return dom->p2m_host[pfn];
+ }
+
+--
+1.7.2.5
+#From 2a548e22915535ac13694eb38222903bca7245e3 Mon Sep 17 00:00:00 2001
+#From: Matthew Daley <mattjd@gmail.com>
+#Date: Fri, 14 Jun 2013 16:43:19 +0100
+#Subject: [PATCH 22/23] libxc: check blob size before proceeding in xc_dom_check_gzip
+#
+#This is part of the fix to a security issue, XSA-55.
+#
+#Signed-off-by: Matthew Daley <mattjd@gmail.com>
+#---
+# tools/libxc/xc_dom_core.c | 5 +++++
+# 1 files changed, 5 insertions(+), 0 deletions(-)
+#
+diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
+index 3cbf9f7..f8d1b08 100644
+--- a/tools/libxc/xc_dom_core.c
++++ b/tools/libxc/xc_dom_core.c
+@@ -284,6 +284,11 @@ size_t xc_dom_check_gzip(xc_interface *xch, void *blob, size_t ziplen)
+ unsigned char *gzlen;
+ size_t unziplen;
+
++ if ( ziplen < 6 )
++ /* Too small. We need (i.e. the subsequent code relies on)
++ * 2 bytes for the magic number plus 4 bytes length. */
++ return 0;
++
+ if ( strncmp(blob, "\037\213", 2) )
+ /* not gzipped */
+ return 0;
+--
+1.7.2.5
+#From d21d36e84354c04638b60a739a5f7c3d9f8adaf8 Mon Sep 17 00:00:00 2001
+#From: Ian Jackson <ian.jackson@eu.citrix.com>
+#Date: Fri, 14 Jun 2013 16:43:19 +0100
+#Subject: [PATCH 23/23] libxc: Better range check in xc_dom_alloc_segment
+#
+#If seg->pfn is too large, the arithmetic in the range check might
+#overflow, defeating the range check.
+#
+#This is part of the fix to a security issue, XSA-55.
+#
+#Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
+#Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
+#---
+# tools/libxc/xc_dom_core.c | 3 ++-
+# 1 files changed, 2 insertions(+), 1 deletions(-)
+#
+diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
+index f8d1b08..e79e38d 100644
+--- a/tools/libxc/xc_dom_core.c
++++ b/tools/libxc/xc_dom_core.c
+@@ -509,7 +509,8 @@ int xc_dom_alloc_segment(struct xc_dom_image *dom,
+ seg->vstart = start;
+ seg->pfn = (seg->vstart - dom->parms.virt_base) / page_size;
+
+- if ( pages > dom->total_pages || /* double test avoids overflow probs */
++ if ( pages > dom->total_pages || /* multiple test avoids overflow probs */
++ seg->pfn > dom->total_pages ||
+ pages > dom->total_pages - seg->pfn)
+ {
+ xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY,
+--
+1.7.2.5
+
+