diff options
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.patch | 381 |
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 + + |