aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2013-06-26 12:08:38 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2013-06-26 12:10:30 +0000
commitdac4485dfa4d8ae59e99caf4b911c196dc2b717f (patch)
tree96960ffa03d10d31b732058ddb1456cc5e6d419b /main
parent74c598f705ba7b8f403190104ac83504617ca35d (diff)
downloadaports-dac4485dfa4d8ae59e99caf4b911c196dc2b717f.tar.bz2
aports-dac4485dfa4d8ae59e99caf4b911c196dc2b717f.tar.xz
main/xen: fix xsa55 and xsa57 (CVE-2013-2194,CVE-2013-2195,CVE-2013-2196,CV
E-2013-2211) ref #2108 ref #2117 fixes #2112 fixes #2121
Diffstat (limited to 'main')
-rw-r--r--main/xen/APKBUILD6
-rw-r--r--main/xen/xsa55-4.1.patch3330
-rw-r--r--main/xen/xsa57-4.1.patch363
3 files changed, 3698 insertions, 1 deletions
diff --git a/main/xen/APKBUILD b/main/xen/APKBUILD
index c3fd941717..4f44f4d0a6 100644
--- a/main/xen/APKBUILD
+++ b/main/xen/APKBUILD
@@ -2,7 +2,7 @@
# Maintainer: William Pitcock <nenolod@dereferenced.org>
pkgname=xen
pkgver=4.1.4
-pkgrel=4
+pkgrel=5
pkgdesc="Xen hypervisor"
url="http://www.xen.org/"
arch="x86 x86_64"
@@ -26,7 +26,9 @@ source="http://bits.xensource.com/oss-xen/release/$pkgver/$pkgname-$pkgver.tar.g
xsa52-4.1.patch
xsa53-4.1.patch
xsa54.patch
+ xsa55-4.1.patch
xsa56.patch
+ xsa57-4.1.patch
xencommons.initd
xend.initd
@@ -107,7 +109,9 @@ ce56f00762139cd611dfc3332b7571cf xsa41.patch
db1e5a92547c8c8ed2e1872efed99ab0 xsa52-4.1.patch
e11ae888997d11fcb91b431ebf609d4e xsa53-4.1.patch
a8393d1ec6b886ea72ffe624a04ee10a xsa54.patch
+391d90e3851df0b42b2971e8b860e19a xsa55-4.1.patch
e70b9128ffc2175cea314a533a7d8457 xsa56.patch
+a065178b8f5ed028b97fa51db97e41e2 xsa57-4.1.patch
0b62c1fbe2699a32e745724fd301db5b xencommons.initd
5ee6a16ec70dfbcd4944ded71b393fa2 xend.initd
a2b5234483f1b5892d22e9315d9c307f xendomains.initd"
diff --git a/main/xen/xsa55-4.1.patch b/main/xen/xsa55-4.1.patch
new file mode 100644
index 0000000000..831cfd9b68
--- /dev/null
+++ b/main/xen/xsa55-4.1.patch
@@ -0,0 +1,3330 @@
+diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
+index d2acb7d..e0e6076 100644
+--- a/tools/libxc/Makefile
++++ b/tools/libxc/Makefile
+@@ -49,8 +49,13 @@ GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c
+ vpath %.c ../../xen/common/libelf
+ CFLAGS += -I../../xen/common/libelf
+
+-GUEST_SRCS-y += libelf-tools.c libelf-loader.c
+-GUEST_SRCS-y += libelf-dominfo.c libelf-relocate.c
++ELF_SRCS-y += libelf-tools.c libelf-loader.c
++ELF_SRCS-y += libelf-dominfo.c
++
++GUEST_SRCS-y += $(ELF_SRCS-y)
++
++$(patsubst %.c,%.o,$(ELF_SRCS-y)): CFLAGS += -Wno-pointer-sign
++$(patsubst %.c,%.opic,$(ELF_SRCS-y)): CFLAGS += -Wno-pointer-sign
+
+ # new domain builder
+ GUEST_SRCS-y += xc_dom_core.c xc_dom_boot.c
+diff --git a/tools/libxc/ia64/xc_ia64_dom_fwloader.c b/tools/libxc/ia64/xc_ia64_dom_fwloader.c
+index cdf3333..dbd3349 100644
+--- a/tools/libxc/ia64/xc_ia64_dom_fwloader.c
++++ b/tools/libxc/ia64/xc_ia64_dom_fwloader.c
+@@ -60,6 +60,8 @@ static int xc_dom_load_fw_kernel(struct xc_dom_image *dom)
+ unsigned long i;
+
+ dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart);
++ if ( dest == NULL )
++ return -1;
+ memcpy(dest, dom->kernel_blob, FW_SIZE);
+
+ /* Synchronize cache. */
+diff --git a/tools/libxc/xc_bitops.h b/tools/libxc/xc_bitops.h
+new file mode 100644
+index 0000000..d8e0c16
+--- /dev/null
++++ b/tools/libxc/xc_bitops.h
+@@ -0,0 +1,63 @@
++#ifndef XC_BITOPS_H
++#define XC_BITOPS_H 1
++
++/* bitmap operations for single threaded access */
++
++#include <stdlib.h>
++#include <string.h>
++
++#define BITS_PER_LONG (sizeof(unsigned long) * 8)
++#define ORDER_LONG (sizeof(unsigned long) == 4 ? 5 : 6)
++
++#define BITMAP_ENTRY(_nr,_bmap) ((_bmap))[(_nr)/BITS_PER_LONG]
++#define BITMAP_SHIFT(_nr) ((_nr) % BITS_PER_LONG)
++
++/* calculate required space for number of longs needed to hold nr_bits */
++static inline int bitmap_size(int nr_bits)
++{
++ int nr_long, nr_bytes;
++ nr_long = (nr_bits + BITS_PER_LONG - 1) >> ORDER_LONG;
++ nr_bytes = nr_long * sizeof(unsigned long);
++ return nr_bytes;
++}
++
++static inline unsigned long *bitmap_alloc(int nr_bits)
++{
++ return calloc(1, bitmap_size(nr_bits));
++}
++
++static inline void bitmap_clear(unsigned long *addr, int nr_bits)
++{
++ memset(addr, 0, bitmap_size(nr_bits));
++}
++
++static inline int test_bit(int nr, unsigned long *addr)
++{
++ return (BITMAP_ENTRY(nr, addr) >> BITMAP_SHIFT(nr)) & 1;
++}
++
++static inline void clear_bit(int nr, unsigned long *addr)
++{
++ BITMAP_ENTRY(nr, addr) &= ~(1UL << BITMAP_SHIFT(nr));
++}
++
++static inline void set_bit(int nr, unsigned long *addr)
++{
++ BITMAP_ENTRY(nr, addr) |= (1UL << BITMAP_SHIFT(nr));
++}
++
++static inline int test_and_clear_bit(int nr, unsigned long *addr)
++{
++ int oldbit = test_bit(nr, addr);
++ clear_bit(nr, addr);
++ return oldbit;
++}
++
++static inline int test_and_set_bit(int nr, unsigned long *addr)
++{
++ int oldbit = test_bit(nr, addr);
++ set_bit(nr, addr);
++ return oldbit;
++}
++
++#endif /* XC_BITOPS_H */
+diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
+index f61308a..5adf2d9 100644
+--- a/tools/libxc/xc_cpuid_x86.c
++++ b/tools/libxc/xc_cpuid_x86.c
+@@ -515,6 +515,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;
+ }
+@@ -526,6 +528,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';
+ }
+@@ -599,7 +603,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));
+@@ -611,6 +615,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))));
+@@ -627,12 +636,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;
+ }
+
+ /*
+@@ -677,6 +688,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.h b/tools/libxc/xc_dom.h
+index 7043f96..316e2ae 100644
+--- a/tools/libxc/xc_dom.h
++++ b/tools/libxc/xc_dom.h
+@@ -135,9 +135,10 @@ struct xc_dom_image {
+
+ struct xc_dom_loader {
+ char *name;
+- int (*probe) (struct xc_dom_image * dom);
+- int (*parser) (struct xc_dom_image * dom);
+- int (*loader) (struct xc_dom_image * dom);
++ /* Sadly the error returns from these functions are not consistent: */
++ elf_negerrnoval (*probe) (struct xc_dom_image * dom);
++ elf_negerrnoval (*parser) (struct xc_dom_image * dom);
++ elf_errorstatus (*loader) (struct xc_dom_image * dom);
+
+ struct xc_dom_loader *next;
+ };
+@@ -259,27 +260,50 @@ int xc_dom_alloc_segment(struct xc_dom_image *dom,
+
+ void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t first,
+ xen_pfn_t count);
++void *xc_dom_pfn_to_ptr_retcount(struct xc_dom_image *dom, xen_pfn_t first,
++ xen_pfn_t count, xen_pfn_t *count_out);
+ void xc_dom_unmap_one(struct xc_dom_image *dom, xen_pfn_t pfn);
+ void xc_dom_unmap_all(struct xc_dom_image *dom);
+
+-static inline void *xc_dom_seg_to_ptr(struct xc_dom_image *dom,
+- struct xc_dom_seg *seg)
++static inline void *xc_dom_seg_to_ptr_pages(struct xc_dom_image *dom,
++ struct xc_dom_seg *seg,
++ xen_pfn_t *pages_out)
+ {
+ xen_vaddr_t segsize = seg->vend - seg->vstart;
+ unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
+ xen_pfn_t pages = (segsize + page_size - 1) / page_size;
++ void *retval;
++
++ retval = xc_dom_pfn_to_ptr(dom, seg->pfn, pages);
+
+- return xc_dom_pfn_to_ptr(dom, seg->pfn, pages);
++ *pages_out = retval ? pages : 0;
++ return retval;
++}
++
++static inline void *xc_dom_seg_to_ptr(struct xc_dom_image *dom,
++ struct xc_dom_seg *seg)
++{
++ xen_pfn_t dummy;
++
++ return xc_dom_seg_to_ptr_pages(dom, seg, &dummy);
+ }
+
+ static inline void *xc_dom_vaddr_to_ptr(struct xc_dom_image *dom,
+- xen_vaddr_t vaddr)
++ xen_vaddr_t vaddr,
++ size_t *safe_region_out)
+ {
+ unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
+ xen_pfn_t page = (vaddr - dom->parms.virt_base) / page_size;
+ unsigned int offset = (vaddr - dom->parms.virt_base) % page_size;
+- void *ptr = xc_dom_pfn_to_ptr(dom, page, 0);
+- return (ptr ? (ptr + offset) : NULL);
++ xen_pfn_t safe_region_count;
++ void *ptr;
++
++ *safe_region_out = 0;
++ ptr = xc_dom_pfn_to_ptr_retcount(dom, page, 0, &safe_region_count);
++ if ( ptr == NULL )
++ return ptr;
++ *safe_region_out = (safe_region_count << XC_DOM_PAGE_SHIFT(dom)) - offset;
++ return ptr;
+ }
+
+ static inline int xc_dom_feature_translated(struct xc_dom_image *dom)
+@@ -291,6 +315,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];
+ }
+
+@@ -299,6 +325,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];
+ }
+
+diff --git a/tools/libxc/xc_dom_binloader.c b/tools/libxc/xc_dom_binloader.c
+index 769e97d..553b366 100644
+--- a/tools/libxc/xc_dom_binloader.c
++++ b/tools/libxc/xc_dom_binloader.c
+@@ -123,10 +123,13 @@ static struct xen_bin_image_table *find_table(struct xc_dom_image *dom)
+ uint32_t *probe_ptr;
+ uint32_t *probe_end;
+
++ if ( dom->kernel_size < sizeof(*table) )
++ return NULL;
+ probe_ptr = dom->kernel_blob;
+- probe_end = dom->kernel_blob + dom->kernel_size - sizeof(*table);
+- if ( (void*)probe_end > (dom->kernel_blob + 8192) )
++ if ( dom->kernel_size > (8192 + sizeof(*table)) )
+ probe_end = dom->kernel_blob + 8192;
++ else
++ probe_end = dom->kernel_blob + dom->kernel_size - sizeof(*table);
+
+ for ( table = NULL; probe_ptr < probe_end; probe_ptr++ )
+ {
+@@ -249,6 +252,7 @@ static int xc_dom_load_bin_kernel(struct xc_dom_image *dom)
+ char *image = dom->kernel_blob;
+ char *dest;
+ size_t image_size = dom->kernel_size;
++ size_t dest_size;
+ uint32_t start_addr;
+ uint32_t load_end_addr;
+ uint32_t bss_end_addr;
+@@ -272,7 +276,29 @@ static int xc_dom_load_bin_kernel(struct xc_dom_image *dom)
+ DOMPRINTF(" text_size: 0x%" PRIx32 "", text_size);
+ DOMPRINTF(" bss_size: 0x%" PRIx32 "", bss_size);
+
+- dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart);
++ dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart, &dest_size);
++ if ( dest == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart)"
++ " => NULL", __FUNCTION__);
++ return -EINVAL;
++ }
++
++ if ( dest_size < text_size ||
++ dest_size - text_size < bss_size )
++ {
++ DOMPRINTF("%s: mapped region is too small for image", __FUNCTION__);
++ return -EINVAL;
++ }
++
++ if ( image_size < skip ||
++ image_size - skip < text_size )
++ {
++ DOMPRINTF("%s: image is too small for declared text size",
++ __FUNCTION__);
++ return -EINVAL;
++ }
++
+ memcpy(dest, image + skip, text_size);
+ memset(dest + text_size, 0, bss_size);
+
+diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
+index 2a01d7c..f8d1b08 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;
+ }
+
+@@ -271,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;
+@@ -351,10 +369,19 @@ int xc_dom_try_gunzip(struct xc_dom_image *dom, void **blob, size_t * size)
+ void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t pfn,
+ xen_pfn_t count)
+ {
++ xen_pfn_t count_out_dummy;
++ return xc_dom_pfn_to_ptr_retcount(dom, pfn, count, &count_out_dummy);
++}
++
++void *xc_dom_pfn_to_ptr_retcount(struct xc_dom_image *dom, xen_pfn_t pfn,
++ xen_pfn_t count, xen_pfn_t *count_out)
++{
+ struct xc_dom_phys *phys;
+ unsigned int page_shift = XC_DOM_PAGE_SHIFT(dom);
+ char *mode = "unset";
+
++ *count_out = 0;
++
+ if ( pfn > dom->total_pages || /* multiple checks to avoid overflows */
+ count > dom->total_pages ||
+ pfn > dom->total_pages - count )
+@@ -384,6 +411,7 @@ void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t pfn,
+ phys->count);
+ return NULL;
+ }
++ *count_out = count;
+ }
+ else
+ {
+@@ -391,6 +419,9 @@ void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t pfn,
+ just hand out a pointer to it */
+ if ( pfn < phys->first )
+ continue;
++ if ( pfn >= phys->first + phys->count )
++ continue;
++ *count_out = phys->count - (pfn - phys->first);
+ }
+ return phys->ptr + ((pfn - phys->first) << page_shift);
+ }
+@@ -855,6 +886,12 @@ int xc_dom_build_image(struct xc_dom_image *dom)
+ ramdisklen) != 0 )
+ goto err;
+ ramdiskmap = xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg);
++ if ( ramdiskmap == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg) => NULL",
++ __FUNCTION__);
++ goto err;
++ }
+ if ( unziplen )
+ {
+ if ( xc_dom_do_gunzip(dom->xch,
+diff --git a/tools/libxc/xc_dom_elfloader.c b/tools/libxc/xc_dom_elfloader.c
+index 9114bfb..0fb3629 100644
+--- a/tools/libxc/xc_dom_elfloader.c
++++ b/tools/libxc/xc_dom_elfloader.c
+@@ -28,13 +28,14 @@
+
+ #include "xg_private.h"
+ #include "xc_dom.h"
++#include "xc_bitops.h"
+
+ #define XEN_VER "xen-3.0"
+
+ /* ------------------------------------------------------------------------ */
+
+ static void log_callback(struct elf_binary *elf, void *caller_data,
+- int iserr, const char *fmt, va_list al) {
++ bool iserr, const char *fmt, va_list al) {
+ xc_interface *xch = caller_data;
+
+ xc_reportv(xch,
+@@ -46,7 +47,7 @@ static void log_callback(struct elf_binary *elf, void *caller_data,
+
+ void xc_elf_set_logfile(xc_interface *xch, struct elf_binary *elf,
+ int verbose) {
+- elf_set_log(elf, log_callback, xch, verbose);
++ elf_set_log(elf, log_callback, xch, verbose /* convert to bool */);
+ }
+
+ /* ------------------------------------------------------------------------ */
+@@ -84,7 +85,7 @@ static char *xc_dom_guest_type(struct xc_dom_image *dom,
+ /* ------------------------------------------------------------------------ */
+ /* parse elf binary */
+
+-static int check_elf_kernel(struct xc_dom_image *dom, int verbose)
++static elf_negerrnoval check_elf_kernel(struct xc_dom_image *dom, bool verbose)
+ {
+ if ( dom->kernel_blob == NULL )
+ {
+@@ -95,7 +96,7 @@ static int check_elf_kernel(struct xc_dom_image *dom, int verbose)
+ return -EINVAL;
+ }
+
+- if ( !elf_is_elfbinary(dom->kernel_blob) )
++ if ( !elf_is_elfbinary(dom->kernel_blob, dom->kernel_size) )
+ {
+ if ( verbose )
+ xc_dom_panic(dom->xch,
+@@ -106,20 +107,21 @@ static int check_elf_kernel(struct xc_dom_image *dom, int verbose)
+ return 0;
+ }
+
+-static int xc_dom_probe_elf_kernel(struct xc_dom_image *dom)
++static elf_negerrnoval xc_dom_probe_elf_kernel(struct xc_dom_image *dom)
+ {
+ return check_elf_kernel(dom, 0);
+ }
+
+-static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+- struct elf_binary *elf, int load)
++static elf_errorstatus xc_dom_load_elf_symtab(struct xc_dom_image *dom,
++ struct elf_binary *elf, bool load)
+ {
+ struct elf_binary syms;
+- const elf_shdr *shdr, *shdr2;
++ ELF_HANDLE_DECL(elf_shdr) shdr; ELF_HANDLE_DECL(elf_shdr) shdr2;
+ xen_vaddr_t symtab, maxaddr;
+- char *hdr;
++ elf_ptrval hdr;
+ size_t size;
+- int h, count, type, i, tables = 0;
++ unsigned h, count, type, i, tables = 0;
++ unsigned long *strtab_referenced = NULL;
+
+ if ( elf_swap(elf) )
+ {
+@@ -130,31 +132,48 @@ static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+
+ if ( load )
+ {
++ char *hdr_ptr;
++ size_t allow_size;
++
+ if ( !dom->bsd_symtab_start )
+ return 0;
+ size = dom->kernel_seg.vend - dom->bsd_symtab_start;
+- hdr = xc_dom_vaddr_to_ptr(dom, dom->bsd_symtab_start);
+- *(int *)hdr = size - sizeof(int);
++ hdr_ptr = xc_dom_vaddr_to_ptr(dom, dom->bsd_symtab_start, &allow_size);
++ if ( hdr_ptr == NULL )
++ {
++ DOMPRINTF("%s/load: xc_dom_vaddr_to_ptr(dom,dom->bsd_symtab_start"
++ " => NULL", __FUNCTION__);
++ return -1;
++ }
++ elf->caller_xdest_base = hdr_ptr;
++ elf->caller_xdest_size = allow_size;
++ hdr = ELF_REALPTR2PTRVAL(hdr_ptr);
++ elf_store_val(elf, unsigned, hdr, size - sizeof(unsigned));
+ }
+ else
+ {
+- size = sizeof(int) + elf_size(elf, elf->ehdr) +
++ char *hdr_ptr;
++
++ size = sizeof(unsigned) + elf_size(elf, elf->ehdr) +
+ elf_shdr_count(elf) * elf_size(elf, shdr);
+- hdr = xc_dom_malloc(dom, size);
+- if ( hdr == NULL )
++ hdr_ptr = xc_dom_malloc(dom, size);
++ if ( hdr_ptr == NULL )
+ return 0;
+- dom->bsd_symtab_start = elf_round_up(&syms, dom->kernel_seg.vend);
++ elf->caller_xdest_base = hdr_ptr;
++ elf->caller_xdest_size = size;
++ hdr = ELF_REALPTR2PTRVAL(hdr_ptr);
++ dom->bsd_symtab_start = elf_round_up(elf, dom->kernel_seg.vend);
+ }
+
+- memcpy(hdr + sizeof(int),
+- elf->image,
++ elf_memcpy_safe(elf, hdr + sizeof(unsigned),
++ ELF_IMAGE_BASE(elf),
+ elf_size(elf, elf->ehdr));
+- memcpy(hdr + sizeof(int) + elf_size(elf, elf->ehdr),
+- elf->image + elf_uval(elf, elf->ehdr, e_shoff),
++ elf_memcpy_safe(elf, hdr + sizeof(unsigned) + elf_size(elf, elf->ehdr),
++ ELF_IMAGE_BASE(elf) + elf_uval(elf, elf->ehdr, e_shoff),
+ elf_shdr_count(elf) * elf_size(elf, shdr));
+ if ( elf_64bit(elf) )
+ {
+- Elf64_Ehdr *ehdr = (Elf64_Ehdr *)(hdr + sizeof(int));
++ Elf64_Ehdr *ehdr = (Elf64_Ehdr *)(hdr + sizeof(unsigned));
+ ehdr->e_phoff = 0;
+ ehdr->e_phentsize = 0;
+ ehdr->e_phnum = 0;
+@@ -163,19 +182,42 @@ static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+ }
+ else
+ {
+- Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(hdr + sizeof(int));
++ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(hdr + sizeof(unsigned));
+ ehdr->e_phoff = 0;
+ ehdr->e_phentsize = 0;
+ ehdr->e_phnum = 0;
+ ehdr->e_shoff = elf_size(elf, elf->ehdr);
+ ehdr->e_shstrndx = SHN_UNDEF;
+ }
+- if ( elf_init(&syms, hdr + sizeof(int), size - sizeof(int)) )
++ if ( elf->caller_xdest_size < sizeof(unsigned) )
++ {
++ DOMPRINTF("%s/%s: header size %"PRIx64" too small",
++ __FUNCTION__, load ? "load" : "parse",
++ (uint64_t)elf->caller_xdest_size);
++ return -1;
++ }
++ if ( elf_init(&syms, elf->caller_xdest_base + sizeof(unsigned),
++ elf->caller_xdest_size - sizeof(unsigned)) )
+ return -1;
+
++ /*
++ * The caller_xdest_{base,size} and dest_{base,size} need to
++ * remain valid so long as each struct elf_image does. The
++ * principle we adopt is that these values are set when the
++ * memory is allocated or mapped, and cleared when (and if)
++ * they are unmapped.
++ *
++ * Mappings of the guest are normally undone by xc_dom_unmap_all
++ * (directly or via xc_dom_release). We do not explicitly clear
++ * these because in fact that happens only at the end of
++ * xc_dom_boot_image, at which time all of these ELF loading
++ * functions have returned. No relevant struct elf_binary*
++ * escapes this file.
++ */
++
+ xc_elf_set_logfile(dom->xch, &syms, 1);
+
+- symtab = dom->bsd_symtab_start + sizeof(int);
++ symtab = dom->bsd_symtab_start + sizeof(unsigned);
+ maxaddr = elf_round_up(&syms, symtab + elf_size(&syms, syms.ehdr) +
+ elf_shdr_count(&syms) * elf_size(&syms, shdr));
+
+@@ -186,27 +228,40 @@ static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+ symtab, maxaddr);
+
+ count = elf_shdr_count(&syms);
++ /* elf_shdr_count guarantees that count is reasonable */
++
++ strtab_referenced = xc_dom_malloc(dom, bitmap_size(count));
++ if ( strtab_referenced == NULL )
++ return -1;
++ bitmap_clear(strtab_referenced, count);
++ /* Note the symtabs @h linked to by any strtab @i. */
++ for ( i = 0; i < count; i++ )
++ {
++ shdr2 = elf_shdr_by_index(&syms, i);
++ if ( elf_uval(&syms, shdr2, sh_type) == SHT_SYMTAB )
++ {
++ h = elf_uval(&syms, shdr2, sh_link);
++ if (h < count)
++ set_bit(h, strtab_referenced);
++ }
++ }
++
+ for ( h = 0; h < count; h++ )
+ {
+ shdr = elf_shdr_by_index(&syms, h);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
++ /* input has an insane section header count field */
++ break;
+ type = elf_uval(&syms, shdr, sh_type);
+ if ( type == SHT_STRTAB )
+ {
+- /* Look for a strtab @i linked to symtab @h. */
+- for ( i = 0; i < count; i++ )
+- {
+- shdr2 = elf_shdr_by_index(&syms, i);
+- if ( (elf_uval(&syms, shdr2, sh_type) == SHT_SYMTAB) &&
+- (elf_uval(&syms, shdr2, sh_link) == h) )
+- break;
+- }
+ /* Skip symtab @h if we found no corresponding strtab @i. */
+- if ( i == count )
++ if ( !test_bit(h, strtab_referenced) )
+ {
+ if ( elf_64bit(&syms) )
+- *(Elf64_Off*)(&shdr->e64.sh_offset) = 0;
++ elf_store_field(elf, shdr, e64.sh_offset, 0);
+ else
+- *(Elf32_Off*)(&shdr->e32.sh_offset) = 0;
++ elf_store_field(elf, shdr, e32.sh_offset, 0);
+ continue;
+ }
+ }
+@@ -215,13 +270,13 @@ static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+ {
+ /* Mangled to be based on ELF header location. */
+ if ( elf_64bit(&syms) )
+- *(Elf64_Off*)(&shdr->e64.sh_offset) = maxaddr - symtab;
++ elf_store_field(elf, shdr, e64.sh_offset, maxaddr - symtab);
+ else
+- *(Elf32_Off*)(&shdr->e32.sh_offset) = maxaddr - symtab;
++ elf_store_field(elf, shdr, e32.sh_offset, maxaddr - symtab);
+ size = elf_uval(&syms, shdr, sh_size);
+ maxaddr = elf_round_up(&syms, maxaddr + size);
+ tables++;
+- DOMPRINTF("%s: h=%d %s, size=0x%zx, maxaddr=0x%" PRIx64 "",
++ DOMPRINTF("%s: h=%u %s, size=0x%zx, maxaddr=0x%" PRIx64 "",
+ __FUNCTION__, h,
+ type == SHT_SYMTAB ? "symtab" : "strtab",
+ size, maxaddr);
+@@ -229,7 +284,7 @@ static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+ if ( load )
+ {
+ shdr2 = elf_shdr_by_index(elf, h);
+- memcpy((void*)elf_section_start(&syms, shdr),
++ elf_memcpy_safe(elf, elf_section_start(&syms, shdr),
+ elf_section_start(elf, shdr2),
+ size);
+ }
+@@ -237,11 +292,18 @@ static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+
+ /* Name is NULL. */
+ if ( elf_64bit(&syms) )
+- *(Elf64_Half*)(&shdr->e64.sh_name) = 0;
++ elf_store_field(elf, shdr, e64.sh_name, 0);
+ else
+- *(Elf32_Word*)(&shdr->e32.sh_name) = 0;
++ elf_store_field(elf, shdr, e32.sh_name, 0);
+ }
+
++ if ( elf_check_broken(&syms) )
++ DOMPRINTF("%s: symbols ELF broken: %s", __FUNCTION__,
++ elf_check_broken(&syms));
++ if ( elf_check_broken(elf) )
++ DOMPRINTF("%s: ELF broken: %s", __FUNCTION__,
++ elf_check_broken(elf));
++
+ if ( tables == 0 )
+ {
+ DOMPRINTF("%s: no symbol table present", __FUNCTION__);
+@@ -253,16 +315,22 @@ static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+ return 0;
+ }
+
+-static int xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
++static elf_errorstatus xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
++ /*
++ * This function sometimes returns -1 for error and sometimes
++ * an errno value. ?!?!
++ */
+ {
+ struct elf_binary *elf;
+- int rc;
++ elf_errorstatus rc;
+
+ rc = check_elf_kernel(dom, 1);
+ if ( rc != 0 )
+ 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);
+@@ -274,17 +342,20 @@ static int xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
+ }
+
+ /* Find the section-header strings table. */
+- if ( elf->sec_strtab == NULL )
++ if ( ELF_PTRVAL_INVALID(elf->sec_strtab) )
+ {
+ xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: ELF image"
+ " has no shstrtab", __FUNCTION__);
+- return -EINVAL;
++ rc = -EINVAL;
++ goto out;
+ }
+
+ /* parse binary and get xen meta info */
+ elf_parse_binary(elf);
+ if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 )
+- return rc;
++ {
++ goto out;
++ }
+
+ /* find kernel segment */
+ dom->kernel_seg.vstart = dom->parms.virt_kstart;
+@@ -297,14 +368,28 @@ static int xc_dom_parse_elf_kernel(struct xc_dom_image *dom)
+ DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "",
+ __FUNCTION__, dom->guest_type,
+ dom->kernel_seg.vstart, dom->kernel_seg.vend);
+- return 0;
++ rc = 0;
++out:
++ if ( elf_check_broken(elf) )
++ DOMPRINTF("%s: ELF broken: %s", __FUNCTION__,
++ elf_check_broken(elf));
++
++ return rc;
+ }
+
+-static int xc_dom_load_elf_kernel(struct xc_dom_image *dom)
++static elf_errorstatus xc_dom_load_elf_kernel(struct xc_dom_image *dom)
+ {
+ struct elf_binary *elf = dom->private_loader;
++ xen_pfn_t pages;
+
+- elf->dest = xc_dom_seg_to_ptr(dom, &dom->kernel_seg);
++ elf->dest_base = xc_dom_seg_to_ptr_pages(dom, &dom->kernel_seg, &pages);
++ if ( elf->dest_base == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->kernel_seg)"
++ " => NULL", __FUNCTION__);
++ return -1;
++ }
++ elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom);
+ elf_load_binary(elf);
+ if ( dom->parms.bsd_symtab )
+ xc_dom_load_elf_symtab(dom, elf, 1);
+diff --git a/tools/libxc/xc_dom_ia64.c b/tools/libxc/xc_dom_ia64.c
+index dcd1523..076821c 100644
+--- a/tools/libxc/xc_dom_ia64.c
++++ b/tools/libxc/xc_dom_ia64.c
+@@ -60,6 +60,12 @@ int start_info_ia64(struct xc_dom_image *dom)
+
+ DOMPRINTF_CALLED(dom->xch);
+
++ if ( start_info == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_pfn_to_ptr failed on start_info", __FUNCTION__);
++ return -1; /* our caller throws away our return value :-/ */
++ }
++
+ memset(start_info, 0, sizeof(*start_info));
+ sprintf(start_info->magic, dom->guest_type);
+ start_info->flags = dom->flags;
+@@ -182,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 0cf1687..448d9a1 100644
+--- a/tools/libxc/xc_dom_x86.c
++++ b/tools/libxc/xc_dom_x86.c
+@@ -144,6 +144,9 @@ static int setup_pgtables_x86_32(struct xc_dom_image *dom)
+ xen_vaddr_t addr;
+ xen_pfn_t pgpfn;
+
++ if ( l2tab == NULL )
++ goto pfn_error;
++
+ for ( addr = dom->parms.virt_base; addr < dom->virt_pgtab_end;
+ addr += PAGE_SIZE_X86 )
+ {
+@@ -151,6 +154,8 @@ static int setup_pgtables_x86_32(struct xc_dom_image *dom)
+ {
+ /* get L1 tab, make L2 entry */
+ l1tab = xc_dom_pfn_to_ptr(dom, l1pfn, 1);
++ if ( l1tab == NULL )
++ goto pfn_error;
+ l2off = l2_table_offset_i386(addr);
+ l2tab[l2off] =
+ pfn_to_paddr(xc_dom_p2m_guest(dom, l1pfn)) | L2_PROT;
+@@ -169,6 +174,11 @@ static int setup_pgtables_x86_32(struct xc_dom_image *dom)
+ l1tab = NULL;
+ }
+ return 0;
++
++pfn_error:
++ xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
++ "%s: xc_dom_pfn_to_ptr failed", __FUNCTION__);
++ return -EINVAL;
+ }
+
+ /*
+@@ -219,6 +229,12 @@ static xen_pfn_t move_l3_below_4G(struct xc_dom_image *dom,
+ goto out;
+
+ l3tab = xc_dom_pfn_to_ptr(dom, l3pfn, 1);
++ if ( l3tab == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_pfn_to_ptr(dom, l3pfn, 1) => NULL",
++ __FUNCTION__);
++ return l3mfn; /* our one call site will call xc_dom_panic and fail */
++ }
+ memset(l3tab, 0, XC_DOM_PAGE_SIZE(dom));
+
+ DOMPRINTF("%s: successfully relocated L3 below 4G. "
+@@ -262,6 +278,8 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
+ }
+
+ l3tab = xc_dom_pfn_to_ptr(dom, l3pfn, 1);
++ if ( l3tab == NULL )
++ goto pfn_error;
+
+ for ( addr = dom->parms.virt_base; addr < dom->virt_pgtab_end;
+ addr += PAGE_SIZE_X86 )
+@@ -270,6 +288,8 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
+ {
+ /* get L2 tab, make L3 entry */
+ l2tab = xc_dom_pfn_to_ptr(dom, l2pfn, 1);
++ if ( l2tab == NULL )
++ goto pfn_error;
+ l3off = l3_table_offset_pae(addr);
+ l3tab[l3off] =
+ pfn_to_paddr(xc_dom_p2m_guest(dom, l2pfn)) | L3_PROT;
+@@ -280,6 +300,8 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
+ {
+ /* get L1 tab, make L2 entry */
+ l1tab = xc_dom_pfn_to_ptr(dom, l1pfn, 1);
++ if ( l1tab == NULL )
++ goto pfn_error;
+ l2off = l2_table_offset_pae(addr);
+ l2tab[l2off] =
+ pfn_to_paddr(xc_dom_p2m_guest(dom, l1pfn)) | L2_PROT;
+@@ -306,6 +328,11 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
+ l3tab[3] = pfn_to_paddr(xc_dom_p2m_guest(dom, l2pfn)) | L3_PROT;
+ }
+ return 0;
++
++pfn_error:
++ xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
++ "%s: xc_dom_pfn_to_ptr failed", __FUNCTION__);
++ return -EINVAL;
+ }
+
+ #undef L1_PROT
+@@ -344,6 +371,9 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
+ uint64_t addr;
+ xen_pfn_t pgpfn;
+
++ if ( l4tab == NULL )
++ goto pfn_error;
++
+ for ( addr = dom->parms.virt_base; addr < dom->virt_pgtab_end;
+ addr += PAGE_SIZE_X86 )
+ {
+@@ -351,6 +381,8 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
+ {
+ /* get L3 tab, make L4 entry */
+ l3tab = xc_dom_pfn_to_ptr(dom, l3pfn, 1);
++ if ( l3tab == NULL )
++ goto pfn_error;
+ l4off = l4_table_offset_x86_64(addr);
+ l4tab[l4off] =
+ pfn_to_paddr(xc_dom_p2m_guest(dom, l3pfn)) | L4_PROT;
+@@ -361,6 +393,8 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
+ {
+ /* get L2 tab, make L3 entry */
+ l2tab = xc_dom_pfn_to_ptr(dom, l2pfn, 1);
++ if ( l2tab == NULL )
++ goto pfn_error;
+ l3off = l3_table_offset_x86_64(addr);
+ l3tab[l3off] =
+ pfn_to_paddr(xc_dom_p2m_guest(dom, l2pfn)) | L3_PROT;
+@@ -373,6 +407,8 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
+ {
+ /* get L1 tab, make L2 entry */
+ l1tab = xc_dom_pfn_to_ptr(dom, l1pfn, 1);
++ if ( l1tab == NULL )
++ goto pfn_error;
+ l2off = l2_table_offset_x86_64(addr);
+ l2tab[l2off] =
+ pfn_to_paddr(xc_dom_p2m_guest(dom, l1pfn)) | L2_PROT;
+@@ -393,6 +429,11 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
+ l1tab = NULL;
+ }
+ return 0;
++
++pfn_error:
++ xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
++ "%s: xc_dom_pfn_to_ptr failed", __FUNCTION__);
++ return -EINVAL;
+ }
+
+ #undef L1_PROT
+@@ -410,6 +451,8 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
+ if ( xc_dom_alloc_segment(dom, &dom->p2m_seg, "phys2mach", 0, p2m_size) )
+ return -1;
+ dom->p2m_guest = xc_dom_seg_to_ptr(dom, &dom->p2m_seg);
++ if ( dom->p2m_guest == NULL )
++ return -1;
+
+ /* allocate special pages */
+ dom->start_info_pfn = xc_dom_alloc_page(dom, "start info");
+@@ -434,6 +477,12 @@ static int start_info_x86_32(struct xc_dom_image *dom)
+
+ DOMPRINTF_CALLED(dom->xch);
+
++ if ( start_info == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_pfn_to_ptr failed on start_info", __FUNCTION__);
++ return -1; /* our caller throws away our return value :-/ */
++ }
++
+ memset(start_info, 0, sizeof(*start_info));
+ strncpy(start_info->magic, dom->guest_type, sizeof(start_info->magic));
+ start_info->magic[sizeof(start_info->magic) - 1] = '\0';
+@@ -474,6 +523,12 @@ static int start_info_x86_64(struct xc_dom_image *dom)
+
+ DOMPRINTF_CALLED(dom->xch);
+
++ if ( start_info == NULL )
++ {
++ DOMPRINTF("%s: xc_dom_pfn_to_ptr failed on start_info", __FUNCTION__);
++ return -1; /* our caller throws away our return value :-/ */
++ }
++
+ memset(start_info, 0, sizeof(*start_info));
+ strncpy(start_info->magic, dom->guest_type, sizeof(start_info->magic));
+ start_info->magic[sizeof(start_info->magic) - 1] = '\0';
+@@ -725,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 9564480..0f1e2d1 100644
+--- a/tools/libxc/xc_domain_restore.c
++++ b/tools/libxc/xc_domain_restore.c
+@@ -967,6 +967,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);
+
+@@ -1434,6 +1439,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
+ l3tab = (uint64_t *)
+ xc_map_foreign_range(xch, dom, PAGE_SIZE,
+ PROT_READ, ctx->p2m[i]);
++ if ( l3tab == NULL )
++ {
++ PERROR("xc_map_foreign_range failed (for l3tab)");
++ goto out;
++ }
+
+ for ( j = 0; j < 4; j++ )
+ l3ptes[j] = l3tab[j];
+@@ -1460,6 +1470,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
+ l3tab = (uint64_t *)
+ xc_map_foreign_range(xch, dom, PAGE_SIZE,
+ PROT_READ | PROT_WRITE, ctx->p2m[i]);
++ if ( l3tab == NULL )
++ {
++ PERROR("xc_map_foreign_range failed (for l3tab, 2nd)");
++ goto out;
++ }
+
+ for ( j = 0; j < 4; j++ )
+ l3tab[j] = l3ptes[j];
+@@ -1630,6 +1645,12 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
+ SET_FIELD(ctxt, user_regs.edx, mfn);
+ start_info = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
++ if ( start_info == NULL )
++ {
++ PERROR("xc_map_foreign_range failed (for start_info)");
++ goto out;
++ }
++
+ SET_FIELD(start_info, nr_pages, dinfo->p2m_size);
+ SET_FIELD(start_info, shared_info, shared_info_frame<<PAGE_SHIFT);
+ SET_FIELD(start_info, flags, 0);
+@@ -1765,6 +1786,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
+ /* Restore contents of shared-info page. No checking needed. */
+ new_shared_info = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, shared_info_frame);
++ if ( new_shared_info == NULL )
++ {
++ PERROR("xc_map_foreign_range failed (for new_shared_info)");
++ goto out;
++ }
+
+ /* restore saved vcpu_info and arch specific info */
+ MEMCPY_FIELD(new_shared_info, old_shared_info, vcpu_info);
+diff --git a/tools/libxc/xc_flask.c b/tools/libxc/xc_flask.c
+index 27794a8..78c243c 100644
+--- a/tools/libxc/xc_flask.c
++++ b/tools/libxc/xc_flask.c
+@@ -284,6 +284,8 @@ int xc_flask_access(xc_interface *xc_handle, const char *scon, const char *tcon,
+ MAX_SHORT_DEC_LEN + 1 +
+ sizeof(req)*2 + 1;
+ buf = malloc(bufLen);
++ if ( buf == NULL )
++ return -ENOMEM;
+ snprintf(buf, bufLen, "%s %s %hu %x", scon, tcon, tclass, req);
+
+ op.cmd = FLASK_ACCESS;
+diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c
+index 4af08c7..6c4e41e 100644
+--- a/tools/libxc/xc_hvm_build.c
++++ b/tools/libxc/xc_hvm_build.c
+@@ -99,18 +99,20 @@ static int loadelfimage(
+ for ( i = 0; i < pages; i++ )
+ entries[i].mfn = parray[(elf->pstart >> PAGE_SHIFT) + i];
+
+- elf->dest = xc_map_foreign_ranges(
++ elf->dest_base = xc_map_foreign_ranges(
+ xch, dom, pages << PAGE_SHIFT, PROT_READ | PROT_WRITE, 1 << PAGE_SHIFT,
+ entries, pages);
+- if ( elf->dest == NULL )
++ if ( elf->dest_base == NULL )
+ goto err;
++ elf->dest_size = pages * PAGE_SIZE;
+
+ /* Load the initial elf image. */
+ elf_load_binary(elf);
+ rc = 0;
+
+- munmap(elf->dest, pages << PAGE_SHIFT);
+- elf->dest = NULL;
++ munmap(elf->dest_base, pages << PAGE_SHIFT);
++ elf->dest_base = NULL;
++ elf->dest_size = 0;
+
+ err:
+ free(entries);
+@@ -391,11 +393,16 @@ static int setup_guest(xc_interface *xch,
+ munmap(page0, PAGE_SIZE);
+ }
+
++ if ( elf_check_broken(&elf) )
++ ERROR("HVM ELF broken: %s", elf_check_broken(&elf));
++
+ free(page_array);
+ return 0;
+
+ error_out:
+ free(page_array);
++ if ( elf_check_broken(&elf) )
++ ERROR("HVM ELF broken, failing: %s", elf_check_broken(&elf));
+ return -1;
+ }
+
+diff --git a/tools/libxc/xc_linux_osdep.c b/tools/libxc/xc_linux_osdep.c
+index 6477ad8..fa7bb7c 100644
+--- a/tools/libxc/xc_linux_osdep.c
++++ b/tools/libxc/xc_linux_osdep.c
+@@ -294,6 +294,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;
+@@ -318,6 +320,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_offline_page.c b/tools/libxc/xc_offline_page.c
+index ad8e24c..7b39b59 100644
+--- a/tools/libxc/xc_offline_page.c
++++ b/tools/libxc/xc_offline_page.c
+@@ -715,6 +715,11 @@ int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn)
+
+ new_p = xc_map_foreign_range(xch, domid, PAGE_SIZE,
+ PROT_READ|PROT_WRITE, new_mfn);
++ if ( new_p == NULL )
++ {
++ ERROR("failed to map new_p for copy, guest may be broken?");
++ goto failed;
++ }
+ memcpy(new_p, backup, PAGE_SIZE);
+ munmap(new_p, PAGE_SIZE);
+ mops.arg1.mfn = new_mfn;
+diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
+index 09c8f23..1bf25d2 100644
+--- a/tools/libxc/xc_private.c
++++ b/tools/libxc/xc_private.c
+@@ -742,6 +742,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 570c6d4..9bc9172 100644
+--- a/tools/libxc/xenctrl.h
++++ b/tools/libxc/xenctrl.h
+@@ -1608,7 +1608,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
+
+diff --git a/tools/xcutils/readnotes.c b/tools/xcutils/readnotes.c
+index 2637685..b534001 100644
+--- a/tools/xcutils/readnotes.c
++++ b/tools/xcutils/readnotes.c
+@@ -19,51 +19,56 @@
+ static xc_interface *xch;
+
+ static void print_string_note(const char *prefix, struct elf_binary *elf,
+- const elf_note *note)
++ ELF_HANDLE_DECL(elf_note) note)
+ {
+- printf("%s: %s\n", prefix, (char*)elf_note_desc(elf, note));
++ printf("%s: %s\n", prefix, elf_strfmt(elf, elf_note_desc(elf, note)));
+ }
+
+ static void print_numeric_note(const char *prefix, struct elf_binary *elf,
+- const elf_note *note)
++ ELF_HANDLE_DECL(elf_note) note)
+ {
+ uint64_t value = elf_note_numeric(elf, note);
+- int descsz = elf_uval(elf, note, descsz);
++ unsigned descsz = elf_uval(elf, note, descsz);
+
+ printf("%s: %#*" PRIx64 " (%d bytes)\n",
+ prefix, 2+2*descsz, value, descsz);
+ }
+
+ static void print_l1_mfn_valid_note(const char *prefix, struct elf_binary *elf,
+- const elf_note *note)
++ ELF_HANDLE_DECL(elf_note) note)
+ {
+- int descsz = elf_uval(elf, note, descsz);
+- const uint32_t *desc32 = elf_note_desc(elf, note);
+- const uint64_t *desc64 = elf_note_desc(elf, note);
++ unsigned descsz = elf_uval(elf, note, descsz);
++ elf_ptrval desc = elf_note_desc(elf, note);
+
+ /* XXX should be able to cope with a list of values. */
+ switch ( descsz / 2 )
+ {
+ case 8:
+ printf("%s: mask=%#"PRIx64" value=%#"PRIx64"\n", prefix,
+- desc64[0], desc64[1]);
++ elf_access_unsigned(elf, desc, 0, 8),
++ elf_access_unsigned(elf, desc, 8, 8));
+ break;
+ case 4:
+ printf("%s: mask=%#"PRIx32" value=%#"PRIx32"\n", prefix,
+- desc32[0],desc32[1]);
++ (uint32_t)elf_access_unsigned(elf, desc, 0, 4),
++ (uint32_t)elf_access_unsigned(elf, desc, 4, 4));
+ break;
+ }
+
+ }
+
+-static int print_notes(struct elf_binary *elf, const elf_note *start, const elf_note *end)
++static unsigned print_notes(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) start, ELF_HANDLE_DECL(elf_note) end)
+ {
+- const elf_note *note;
+- int notes_found = 0;
++ ELF_HANDLE_DECL(elf_note) note;
++ unsigned notes_found = 0;
++ const char *this_note_name;
+
+- for ( note = start; note < end; note = elf_note_next(elf, note) )
++ for ( note = start; ELF_HANDLE_PTRVAL(note) < ELF_HANDLE_PTRVAL(end); note = elf_note_next(elf, note) )
+ {
+- if (0 != strcmp(elf_note_name(elf, note), "Xen"))
++ this_note_name = elf_note_name(elf, note);
++ if (NULL == this_note_name)
++ continue;
++ if (0 != strcmp(this_note_name, "Xen"))
+ continue;
+
+ notes_found++;
+@@ -114,7 +119,7 @@ static int print_notes(struct elf_binary *elf, const elf_note *start, const elf_
+ break;
+ default:
+ printf("unknown note type %#x\n",
+- (int)elf_uval(elf, note, type));
++ (unsigned)elf_uval(elf, note, type));
+ break;
+ }
+ }
+@@ -124,12 +129,13 @@ static int print_notes(struct elf_binary *elf, const elf_note *start, const elf_
+ int main(int argc, char **argv)
+ {
+ const char *f;
+- int fd,h,size,usize,count;
++ int fd;
++ unsigned h,size,usize,count;
+ void *image,*tmp;
+ struct stat st;
+ struct elf_binary elf;
+- const elf_shdr *shdr;
+- int notes_found = 0;
++ ELF_HANDLE_DECL(elf_shdr) shdr;
++ unsigned notes_found = 0;
+
+ if (argc != 2)
+ {
+@@ -180,7 +186,7 @@ int main(int argc, char **argv)
+ count = elf_phdr_count(&elf);
+ for ( h=0; h < count; h++)
+ {
+- const elf_phdr *phdr;
++ ELF_HANDLE_DECL(elf_phdr) phdr;
+ phdr = elf_phdr_by_index(&elf, h);
+ if (elf_uval(&elf, phdr, p_type) != PT_NOTE)
+ continue;
+@@ -192,8 +198,8 @@ int main(int argc, char **argv)
+ continue;
+
+ notes_found = print_notes(&elf,
+- elf_segment_start(&elf, phdr),
+- elf_segment_end(&elf, phdr));
++ ELF_MAKE_HANDLE(elf_note, elf_segment_start(&elf, phdr)),
++ ELF_MAKE_HANDLE(elf_note, elf_segment_end(&elf, phdr)));
+ }
+
+ if ( notes_found == 0 )
+@@ -201,13 +207,13 @@ int main(int argc, char **argv)
+ count = elf_shdr_count(&elf);
+ for ( h=0; h < count; h++)
+ {
+- const elf_shdr *shdr;
++ ELF_HANDLE_DECL(elf_shdr) shdr;
+ shdr = elf_shdr_by_index(&elf, h);
+ if (elf_uval(&elf, shdr, sh_type) != SHT_NOTE)
+ continue;
+ notes_found = print_notes(&elf,
+- elf_section_start(&elf, shdr),
+- elf_section_end(&elf, shdr));
++ ELF_MAKE_HANDLE(elf_note, elf_section_start(&elf, shdr)),
++ ELF_MAKE_HANDLE(elf_note, elf_section_end(&elf, shdr)));
+ if ( notes_found )
+ fprintf(stderr, "using notes from SHT_NOTE section\n");
+
+@@ -215,8 +221,12 @@ int main(int argc, char **argv)
+ }
+
+ shdr = elf_shdr_by_name(&elf, "__xen_guest");
+- if (shdr)
+- printf("__xen_guest: %s\n", (char*)elf_section_start(&elf, shdr));
++ if (ELF_HANDLE_VALID(shdr))
++ printf("__xen_guest: %s\n",
++ elf_strfmt(&elf, elf_section_start(&elf, shdr)));
++
++ if (elf_check_broken(&elf))
++ printf("warning: broken ELF: %s\n", elf_check_broken(&elf));
+
+ return 0;
+ }
+diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c
+index 8285048..2aaa4a3 100644
+--- a/xen/arch/x86/domain_build.c
++++ b/xen/arch/x86/domain_build.c
+@@ -374,7 +374,7 @@ int __init construct_dom0(
+ #endif
+ elf_parse_binary(&elf);
+ if ( (rc = elf_xen_parse(&elf, &parms)) != 0 )
+- return rc;
++ goto out;
+
+ /* compatibility check */
+ compatible = 0;
+@@ -413,7 +413,8 @@ int __init construct_dom0(
+ if ( !compatible )
+ {
+ printk("Mismatch between Xen and DOM0 kernel\n");
+- return -EINVAL;
++ rc = -EINVAL;
++ goto out;
+ }
+
+ #if defined(__x86_64__)
+@@ -727,7 +728,8 @@ int __init construct_dom0(
+ (v_end > HYPERVISOR_COMPAT_VIRT_START(d)) )
+ {
+ printk("DOM0 image overlaps with Xen private area.\n");
+- return -EINVAL;
++ rc = -EINVAL;
++ goto out;
+ }
+
+ if ( is_pv_32on64_domain(d) )
+@@ -895,7 +897,8 @@ int __init construct_dom0(
+ write_ptbase(v);
+
+ /* Copy the OS image and free temporary buffer. */
+- elf.dest = (void*)vkern_start;
++ elf.dest_base = (void*)vkern_start;
++ elf.dest_size = vkern_end - vkern_start;
+ elf_load_binary(&elf);
+ bootstrap_map(NULL);
+
+@@ -906,7 +909,8 @@ int __init construct_dom0(
+ {
+ write_ptbase(current);
+ printk("Invalid HYPERCALL_PAGE field in ELF notes.\n");
+- return -1;
++ rc = -1;
++ goto out;
+ }
+ hypercall_page_initialise(
+ d, (void *)(unsigned long)parms.virt_hypercall);
+@@ -1253,9 +1257,19 @@ int __init construct_dom0(
+
+ BUG_ON(rc != 0);
+
+- iommu_dom0_init(dom0);
++ if ( elf_check_broken(&elf) )
++ printk(" Xen warning: dom0 kernel broken ELF: %s\n",
++ elf_check_broken(&elf));
+
++ iommu_dom0_init(dom0);
+ return 0;
++
++out:
++ if ( elf_check_broken(&elf) )
++ printk(" Xen dom0 kernel broken ELF: %s\n",
++ elf_check_broken(&elf));
++
++ return rc;
+ }
+
+ /*
+diff --git a/xen/common/libelf/Makefile b/xen/common/libelf/Makefile
+index 854e738..e788705 100644
+--- a/xen/common/libelf/Makefile
++++ b/xen/common/libelf/Makefile
+@@ -2,6 +2,8 @@ obj-y := libelf.o
+
+ SECTIONS := text data rodata $(foreach n,1 2 4 8,rodata.str1.$(n)) $(foreach r,rel rel.ro,data.$(r) data.$(r).local)
+
++CFLAGS += -Wno-pointer-sign
++
+ libelf.o: libelf-temp.o Makefile
+ $(OBJCOPY) $(foreach s,$(SECTIONS),--rename-section .$(s)=.init.$(s)) $< $@
+
+diff --git a/xen/common/libelf/libelf-dominfo.c b/xen/common/libelf/libelf-dominfo.c
+index 29c3339..fda19e7 100644
+--- a/xen/common/libelf/libelf-dominfo.c
++++ b/xen/common/libelf/libelf-dominfo.c
+@@ -28,22 +28,22 @@ static const char *const elf_xen_feature_names[] = {
+ [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
+ [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
+ };
+-static const int elf_xen_features =
++static const unsigned elf_xen_features =
+ sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
+
+-int elf_xen_parse_features(const char *features,
++elf_errorstatus elf_xen_parse_features(const char *features,
+ uint32_t *supported,
+ uint32_t *required)
+ {
+- char feature[64];
+- int pos, len, i;
++ unsigned char feature[64];
++ unsigned pos, len, i;
+
+ if ( features == NULL )
+ return 0;
+
+ for ( pos = 0; features[pos] != '\0'; pos += len )
+ {
+- memset(feature, 0, sizeof(feature));
++ elf_memset_unchecked(feature, 0, sizeof(feature));
+ for ( len = 0;; len++ )
+ {
+ if ( len >= sizeof(feature)-1 )
+@@ -92,14 +92,14 @@ int elf_xen_parse_features(const char *features,
+ /* ------------------------------------------------------------------------ */
+ /* xen elf notes */
+
+-int elf_xen_parse_note(struct elf_binary *elf,
++elf_errorstatus elf_xen_parse_note(struct elf_binary *elf,
+ struct elf_dom_parms *parms,
+- const elf_note *note)
++ ELF_HANDLE_DECL(elf_note) note)
+ {
+ /* *INDENT-OFF* */
+ static const struct {
+ char *name;
+- int str;
++ bool str;
+ } note_desc[] = {
+ [XEN_ELFNOTE_ENTRY] = { "ENTRY", 0},
+ [XEN_ELFNOTE_HYPERCALL_PAGE] = { "HYPERCALL_PAGE", 0},
+@@ -121,7 +121,7 @@ int elf_xen_parse_note(struct elf_binary *elf,
+
+ const char *str = NULL;
+ uint64_t val = 0;
+- int type = elf_uval(elf, note, type);
++ unsigned type = elf_uval(elf, note, type);
+
+ if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
+ (note_desc[type].name == NULL) )
+@@ -133,7 +133,10 @@ int elf_xen_parse_note(struct elf_binary *elf,
+
+ if ( note_desc[type].str )
+ {
+- str = elf_note_desc(elf, note);
++ str = elf_strval(elf, elf_note_desc(elf, note));
++ if (str == NULL)
++ /* elf_strval will mark elf broken if it fails so no need to log */
++ return 0;
+ elf_msg(elf, "%s: %s = \"%s\"\n", __FUNCTION__,
+ note_desc[type].name, str);
+ parms->elf_notes[type].type = XEN_ENT_STR;
+@@ -203,23 +206,37 @@ int elf_xen_parse_note(struct elf_binary *elf,
+ return 0;
+ }
+
+-static int elf_xen_parse_notes(struct elf_binary *elf,
++#define ELF_NOTE_INVALID (~0U)
++
++static unsigned elf_xen_parse_notes(struct elf_binary *elf,
+ struct elf_dom_parms *parms,
+- const void *start, const void *end)
++ elf_ptrval start,
++ elf_ptrval end,
++ unsigned *total_note_count)
+ {
+- int xen_elfnotes = 0;
+- const elf_note *note;
++ unsigned xen_elfnotes = 0;
++ ELF_HANDLE_DECL(elf_note) note;
++ const char *note_name;
+
+ parms->elf_note_start = start;
+ parms->elf_note_end = end;
+- for ( note = parms->elf_note_start;
+- (void *)note < parms->elf_note_end;
++ for ( note = ELF_MAKE_HANDLE(elf_note, parms->elf_note_start);
++ ELF_HANDLE_PTRVAL(note) < parms->elf_note_end;
+ note = elf_note_next(elf, note) )
+ {
+- if ( strcmp(elf_note_name(elf, note), "Xen") )
++ if ( *total_note_count >= ELF_MAX_TOTAL_NOTE_COUNT )
++ {
++ elf_mark_broken(elf, "too many ELF notes");
++ break;
++ }
++ (*total_note_count)++;
++ note_name = elf_note_name(elf, note);
++ if ( note_name == NULL )
++ continue;
++ if ( strcmp(note_name, "Xen") )
+ continue;
+ if ( elf_xen_parse_note(elf, parms, note) )
+- return -1;
++ return ELF_NOTE_INVALID;
+ xen_elfnotes++;
+ }
+ return xen_elfnotes;
+@@ -228,48 +245,49 @@ static int elf_xen_parse_notes(struct elf_binary *elf,
+ /* ------------------------------------------------------------------------ */
+ /* __xen_guest section */
+
+-int elf_xen_parse_guest_info(struct elf_binary *elf,
++elf_errorstatus elf_xen_parse_guest_info(struct elf_binary *elf,
+ struct elf_dom_parms *parms)
+ {
+- const char *h;
+- char name[32], value[128];
+- int len;
++ elf_ptrval h;
++ unsigned char name[32], value[128];
++ unsigned len;
+
+ h = parms->guest_info;
+- while ( *h )
++#define STAR(h) (elf_access_unsigned(elf, (h), 0, 1))
++ while ( STAR(h) )
+ {
+- memset(name, 0, sizeof(name));
+- memset(value, 0, sizeof(value));
++ elf_memset_unchecked(name, 0, sizeof(name));
++ elf_memset_unchecked(value, 0, sizeof(value));
+ for ( len = 0;; len++, h++ )
+ {
+ if ( len >= sizeof(name)-1 )
+ break;
+- if ( *h == '\0' )
++ if ( STAR(h) == '\0' )
+ break;
+- if ( *h == ',' )
++ if ( STAR(h) == ',' )
+ {
+ h++;
+ break;
+ }
+- if ( *h == '=' )
++ if ( STAR(h) == '=' )
+ {
+ h++;
+ for ( len = 0;; len++, h++ )
+ {
+ if ( len >= sizeof(value)-1 )
+ break;
+- if ( *h == '\0' )
++ if ( STAR(h) == '\0' )
+ break;
+- if ( *h == ',' )
++ if ( STAR(h) == ',' )
+ {
+ h++;
+ break;
+ }
+- value[len] = *h;
++ value[len] = STAR(h);
+ }
+ break;
+ }
+- name[len] = *h;
++ name[len] = STAR(h);
+ }
+ elf_msg(elf, "%s: %s=\"%s\"\n", __FUNCTION__, name, value);
+
+@@ -315,12 +333,13 @@ int elf_xen_parse_guest_info(struct elf_binary *elf,
+ /* ------------------------------------------------------------------------ */
+ /* sanity checks */
+
+-static int elf_xen_note_check(struct elf_binary *elf,
++static elf_errorstatus elf_xen_note_check(struct elf_binary *elf,
+ struct elf_dom_parms *parms)
+ {
+- if ( (parms->elf_note_start == NULL) && (parms->guest_info == NULL) )
++ if ( (ELF_PTRVAL_INVALID(parms->elf_note_start)) &&
++ (ELF_PTRVAL_INVALID(parms->guest_info)) )
+ {
+- int machine = elf_uval(elf, elf->ehdr, e_machine);
++ unsigned machine = elf_uval(elf, elf->ehdr, e_machine);
+ if ( (machine == EM_386) || (machine == EM_X86_64) )
+ {
+ elf_err(elf, "%s: ERROR: Not a Xen-ELF image: "
+@@ -352,7 +371,7 @@ static int elf_xen_note_check(struct elf_binary *elf,
+ return 0;
+ }
+
+-static int elf_xen_addr_calc_check(struct elf_binary *elf,
++static elf_errorstatus elf_xen_addr_calc_check(struct elf_binary *elf,
+ struct elf_dom_parms *parms)
+ {
+ if ( (parms->elf_paddr_offset != UNSET_ADDR) &&
+@@ -438,15 +457,16 @@ static int elf_xen_addr_calc_check(struct elf_binary *elf,
+ /* ------------------------------------------------------------------------ */
+ /* glue it all together ... */
+
+-int elf_xen_parse(struct elf_binary *elf,
++elf_errorstatus elf_xen_parse(struct elf_binary *elf,
+ struct elf_dom_parms *parms)
+ {
+- const elf_shdr *shdr;
+- const elf_phdr *phdr;
+- int xen_elfnotes = 0;
+- int i, count, rc;
++ ELF_HANDLE_DECL(elf_shdr) shdr;
++ ELF_HANDLE_DECL(elf_phdr) phdr;
++ unsigned xen_elfnotes = 0;
++ unsigned i, count, more_notes;
++ unsigned total_note_count = 0;
+
+- memset(parms, 0, sizeof(*parms));
++ elf_memset_unchecked(parms, 0, sizeof(*parms));
+ parms->virt_base = UNSET_ADDR;
+ parms->virt_entry = UNSET_ADDR;
+ parms->virt_hypercall = UNSET_ADDR;
+@@ -459,6 +479,9 @@ int elf_xen_parse(struct elf_binary *elf,
+ for ( i = 0; i < count; i++ )
+ {
+ phdr = elf_phdr_by_index(elf, i);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(phdr), 1) )
++ /* input has an insane program header count field */
++ break;
+ if ( elf_uval(elf, phdr, p_type) != PT_NOTE )
+ continue;
+
+@@ -469,13 +492,14 @@ int elf_xen_parse(struct elf_binary *elf,
+ if (elf_uval(elf, phdr, p_offset) == 0)
+ continue;
+
+- rc = elf_xen_parse_notes(elf, parms,
++ more_notes = elf_xen_parse_notes(elf, parms,
+ elf_segment_start(elf, phdr),
+- elf_segment_end(elf, phdr));
+- if ( rc == -1 )
++ elf_segment_end(elf, phdr),
++ &total_note_count);
++ if ( more_notes == ELF_NOTE_INVALID )
+ return -1;
+
+- xen_elfnotes += rc;
++ xen_elfnotes += more_notes;
+ }
+
+ /*
+@@ -488,21 +512,25 @@ int elf_xen_parse(struct elf_binary *elf,
+ for ( i = 0; i < count; i++ )
+ {
+ shdr = elf_shdr_by_index(elf, i);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
++ /* input has an insane section header count field */
++ break;
+
+ if ( elf_uval(elf, shdr, sh_type) != SHT_NOTE )
+ continue;
+
+- rc = elf_xen_parse_notes(elf, parms,
++ more_notes = elf_xen_parse_notes(elf, parms,
+ elf_section_start(elf, shdr),
+- elf_section_end(elf, shdr));
++ elf_section_end(elf, shdr),
++ &total_note_count);
+
+- if ( rc == -1 )
++ if ( more_notes == ELF_NOTE_INVALID )
+ return -1;
+
+- if ( xen_elfnotes == 0 && rc > 0 )
++ if ( xen_elfnotes == 0 && more_notes > 0 )
+ elf_msg(elf, "%s: using notes from SHT_NOTE section\n", __FUNCTION__);
+
+- xen_elfnotes += rc;
++ xen_elfnotes += more_notes;
+ }
+
+ }
+@@ -512,20 +540,15 @@ int elf_xen_parse(struct elf_binary *elf,
+ */
+ if ( xen_elfnotes == 0 )
+ {
+- count = elf_shdr_count(elf);
+- for ( i = 0; i < count; i++ )
++ shdr = elf_shdr_by_name(elf, "__xen_guest");
++ if ( ELF_HANDLE_VALID(shdr) )
+ {
+- shdr = elf_shdr_by_name(elf, "__xen_guest");
+- if ( shdr )
+- {
+- parms->guest_info = elf_section_start(elf, shdr);
+- parms->elf_note_start = NULL;
+- parms->elf_note_end = NULL;
+- elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
+- parms->guest_info);
+- elf_xen_parse_guest_info(elf, parms);
+- break;
+- }
++ parms->guest_info = elf_section_start(elf, shdr);
++ parms->elf_note_start = ELF_INVALID_PTRVAL;
++ parms->elf_note_end = ELF_INVALID_PTRVAL;
++ elf_msg(elf, "%s: __xen_guest: \"%s\"\n", __FUNCTION__,
++ elf_strfmt(elf, parms->guest_info));
++ elf_xen_parse_guest_info(elf, parms);
+ }
+ }
+
+diff --git a/xen/common/libelf/libelf-loader.c b/xen/common/libelf/libelf-loader.c
+index 1ccf7d3..2698d44 100644
+--- a/xen/common/libelf/libelf-loader.c
++++ b/xen/common/libelf/libelf-loader.c
+@@ -20,23 +20,25 @@
+
+ /* ------------------------------------------------------------------------ */
+
+-int elf_init(struct elf_binary *elf, const char *image, size_t size)
++elf_errorstatus elf_init(struct elf_binary *elf, const char *image_input, size_t size)
+ {
+- const elf_shdr *shdr;
++ ELF_HANDLE_DECL(elf_shdr) shdr;
+ uint64_t i, count, section, offset;
+
+- if ( !elf_is_elfbinary(image) )
++ if ( !elf_is_elfbinary(image_input, size) )
+ {
+ elf_err(elf, "%s: not an ELF binary\n", __FUNCTION__);
+ return -1;
+ }
+
+- memset(elf, 0, sizeof(*elf));
+- elf->image = image;
++ elf_memset_unchecked(elf, 0, sizeof(*elf));
++ elf->image_base = image_input;
+ elf->size = size;
+- elf->ehdr = (elf_ehdr *)image;
+- elf->class = elf->ehdr->e32.e_ident[EI_CLASS];
+- elf->data = elf->ehdr->e32.e_ident[EI_DATA];
++ elf->ehdr = ELF_MAKE_HANDLE(elf_ehdr, (elf_ptrval)image_input);
++ elf->class = elf_uval_3264(elf, elf->ehdr, e32.e_ident[EI_CLASS]);
++ elf->data = elf_uval_3264(elf, elf->ehdr, e32.e_ident[EI_DATA]);
++ elf->caller_xdest_base = NULL;
++ elf->caller_xdest_size = 0;
+
+ /* Sanity check phdr. */
+ offset = elf_uval(elf, elf->ehdr, e_phoff) +
+@@ -61,7 +63,7 @@ int elf_init(struct elf_binary *elf, const char *image, size_t size)
+ /* Find section string table. */
+ section = elf_uval(elf, elf->ehdr, e_shstrndx);
+ shdr = elf_shdr_by_index(elf, section);
+- if ( shdr != NULL )
++ if ( ELF_HANDLE_VALID(shdr) )
+ elf->sec_strtab = elf_section_start(elf, shdr);
+
+ /* Find symbol table and symbol string table. */
+@@ -69,13 +71,16 @@ int elf_init(struct elf_binary *elf, const char *image, size_t size)
+ for ( i = 0; i < count; i++ )
+ {
+ shdr = elf_shdr_by_index(elf, i);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
++ /* input has an insane section header count field */
++ break;
+ if ( elf_uval(elf, shdr, sh_type) != SHT_SYMTAB )
+ continue;
+ elf->sym_tab = shdr;
+ shdr = elf_shdr_by_index(elf, elf_uval(elf, shdr, sh_link));
+- if ( shdr == NULL )
++ if ( !ELF_HANDLE_VALID(shdr) )
+ {
+- elf->sym_tab = NULL;
++ elf->sym_tab = ELF_INVALID_HANDLE(elf_shdr);
+ continue;
+ }
+ elf->sym_strtab = elf_section_start(elf, shdr);
+@@ -86,7 +91,7 @@ int elf_init(struct elf_binary *elf, const char *image, size_t size)
+ }
+
+ #ifndef __XEN__
+-void elf_call_log_callback(struct elf_binary *elf, int iserr,
++void elf_call_log_callback(struct elf_binary *elf, bool iserr,
+ const char *fmt,...) {
+ va_list al;
+
+@@ -101,7 +106,7 @@ void elf_call_log_callback(struct elf_binary *elf, int iserr,
+ }
+
+ void elf_set_log(struct elf_binary *elf, elf_log_callback *log_callback,
+- void *log_caller_data, int verbose)
++ void *log_caller_data, bool verbose)
+ {
+ elf->log_callback = log_callback;
+ elf->log_caller_data = log_caller_data;
+@@ -118,10 +123,10 @@ void elf_set_verbose(struct elf_binary *elf)
+ void elf_parse_bsdsyms(struct elf_binary *elf, uint64_t pstart)
+ {
+ uint64_t sz;
+- const elf_shdr *shdr;
+- int i, type;
++ ELF_HANDLE_DECL(elf_shdr) shdr;
++ unsigned i, type;
+
+- if ( !elf->sym_tab )
++ if ( !ELF_HANDLE_VALID(elf->sym_tab) )
+ return;
+
+ pstart = elf_round_up(elf, pstart);
+@@ -138,7 +143,10 @@ void elf_parse_bsdsyms(struct elf_binary *elf, uint64_t pstart)
+ for ( i = 0; i < elf_shdr_count(elf); i++ )
+ {
+ shdr = elf_shdr_by_index(elf, i);
+- type = elf_uval(elf, (elf_shdr *)shdr, sh_type);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
++ /* input has an insane section header count field */
++ break;
++ type = elf_uval(elf, shdr, sh_type);
+ if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) )
+ sz = elf_round_up(elf, sz + elf_uval(elf, shdr, sh_size));
+ }
+@@ -149,11 +157,13 @@ void elf_parse_bsdsyms(struct elf_binary *elf, uint64_t pstart)
+
+ static void elf_load_bsdsyms(struct elf_binary *elf)
+ {
+- elf_ehdr *sym_ehdr;
++ ELF_HANDLE_DECL(elf_ehdr) sym_ehdr;
+ unsigned long sz;
+- char *maxva, *symbase, *symtab_addr;
+- elf_shdr *shdr;
+- int i, type;
++ elf_ptrval maxva;
++ elf_ptrval symbase;
++ elf_ptrval symtab_addr;
++ ELF_HANDLE_DECL(elf_shdr) shdr;
++ unsigned i, type;
+
+ if ( !elf->bsd_symtab_pstart )
+ return;
+@@ -161,18 +171,18 @@ static void elf_load_bsdsyms(struct elf_binary *elf)
+ #define elf_hdr_elm(_elf, _hdr, _elm, _val) \
+ do { \
+ if ( elf_64bit(_elf) ) \
+- (_hdr)->e64._elm = _val; \
++ elf_store_field(_elf, _hdr, e64._elm, _val); \
+ else \
+- (_hdr)->e32._elm = _val; \
++ elf_store_field(_elf, _hdr, e32._elm, _val); \
+ } while ( 0 )
+
+ symbase = elf_get_ptr(elf, elf->bsd_symtab_pstart);
+ symtab_addr = maxva = symbase + sizeof(uint32_t);
+
+ /* Set up Elf header. */
+- sym_ehdr = (elf_ehdr *)symtab_addr;
++ sym_ehdr = ELF_MAKE_HANDLE(elf_ehdr, symtab_addr);
+ sz = elf_uval(elf, elf->ehdr, e_ehsize);
+- memcpy(sym_ehdr, elf->ehdr, sz);
++ elf_memcpy_safe(elf, ELF_HANDLE_PTRVAL(sym_ehdr), ELF_HANDLE_PTRVAL(elf->ehdr), sz);
+ maxva += sz; /* no round up */
+
+ elf_hdr_elm(elf, sym_ehdr, e_phoff, 0);
+@@ -181,37 +191,50 @@ do { \
+ elf_hdr_elm(elf, sym_ehdr, e_phnum, 0);
+
+ /* Copy Elf section headers. */
+- shdr = (elf_shdr *)maxva;
++ shdr = ELF_MAKE_HANDLE(elf_shdr, maxva);
+ sz = elf_shdr_count(elf) * elf_uval(elf, elf->ehdr, e_shentsize);
+- memcpy(shdr, elf->image + elf_uval(elf, elf->ehdr, e_shoff), sz);
+- maxva = (char *)(long)elf_round_up(elf, (long)maxva + sz);
++ elf_memcpy_safe(elf, ELF_HANDLE_PTRVAL(shdr),
++ ELF_IMAGE_BASE(elf) + elf_uval(elf, elf->ehdr, e_shoff),
++ sz);
++ maxva = elf_round_up(elf, (unsigned long)maxva + sz);
+
+ for ( i = 0; i < elf_shdr_count(elf); i++ )
+ {
++ elf_ptrval old_shdr_p;
++ elf_ptrval new_shdr_p;
++
+ type = elf_uval(elf, shdr, sh_type);
+ if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) )
+ {
+- elf_msg(elf, "%s: shdr %i at 0x%p -> 0x%p\n", __func__, i,
++ elf_msg(elf, "%s: shdr %i at 0x%"ELF_PRPTRVAL" -> 0x%"ELF_PRPTRVAL"\n", __func__, i,
+ elf_section_start(elf, shdr), maxva);
+ sz = elf_uval(elf, shdr, sh_size);
+- memcpy(maxva, elf_section_start(elf, shdr), sz);
++ elf_memcpy_safe(elf, maxva, elf_section_start(elf, shdr), sz);
+ /* Mangled to be based on ELF header location. */
+ elf_hdr_elm(elf, shdr, sh_offset, maxva - symtab_addr);
+- maxva = (char *)(long)elf_round_up(elf, (long)maxva + sz);
++ maxva = elf_round_up(elf, (unsigned long)maxva + sz);
++ }
++ old_shdr_p = ELF_HANDLE_PTRVAL(shdr);
++ new_shdr_p = old_shdr_p + elf_uval(elf, elf->ehdr, e_shentsize);
++ if ( new_shdr_p <= old_shdr_p ) /* wrapped or stuck */
++ {
++ elf_mark_broken(elf, "bad section header length");
++ break;
+ }
+- shdr = (elf_shdr *)((long)shdr +
+- (long)elf_uval(elf, elf->ehdr, e_shentsize));
++ if ( !elf_access_ok(elf, new_shdr_p, 1) ) /* outside image */
++ break;
++ shdr = ELF_MAKE_HANDLE(elf_shdr, new_shdr_p);
+ }
+
+ /* Write down the actual sym size. */
+- *(uint32_t *)symbase = maxva - symtab_addr;
++ elf_store_val(elf, uint32_t, symbase, maxva - symtab_addr);
+
+ #undef elf_ehdr_elm
+ }
+
+ void elf_parse_binary(struct elf_binary *elf)
+ {
+- const elf_phdr *phdr;
++ ELF_HANDLE_DECL(elf_phdr) phdr;
+ uint64_t low = -1;
+ uint64_t high = 0;
+ uint64_t i, count, paddr, memsz;
+@@ -220,6 +243,9 @@ void elf_parse_binary(struct elf_binary *elf)
+ for ( i = 0; i < count; i++ )
+ {
+ phdr = elf_phdr_by_index(elf, i);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(phdr), 1) )
++ /* input has an insane program header count field */
++ break;
+ if ( !elf_phdr_is_loadable(elf, phdr) )
+ continue;
+ paddr = elf_uval(elf, phdr, p_paddr);
+@@ -239,14 +265,23 @@ void elf_parse_binary(struct elf_binary *elf)
+
+ void elf_load_binary(struct elf_binary *elf)
+ {
+- const elf_phdr *phdr;
++ ELF_HANDLE_DECL(elf_phdr) phdr;
+ uint64_t i, count, paddr, offset, filesz, memsz;
+- char *dest;
++ elf_ptrval dest;
++ /*
++ * Let bizarre ELFs write the output image up to twice; this
++ * calculation is just to ensure our copying loop is no worse than
++ * O(domain_size).
++ */
++ uint64_t remain_allow_copy = (uint64_t)elf->dest_size * 2;
+
+ count = elf_uval(elf, elf->ehdr, e_phnum);
+ for ( i = 0; i < count; i++ )
+ {
+ phdr = elf_phdr_by_index(elf, i);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(phdr), 1) )
++ /* input has an insane program header count field */
++ break;
+ if ( !elf_phdr_is_loadable(elf, phdr) )
+ continue;
+ paddr = elf_uval(elf, phdr, p_paddr);
+@@ -254,27 +289,41 @@ void elf_load_binary(struct elf_binary *elf)
+ filesz = elf_uval(elf, phdr, p_filesz);
+ memsz = elf_uval(elf, phdr, p_memsz);
+ dest = elf_get_ptr(elf, paddr);
+- elf_msg(elf, "%s: phdr %" PRIu64 " at 0x%p -> 0x%p\n",
+- __func__, i, dest, dest + filesz);
+- memcpy(dest, elf->image + offset, filesz);
+- memset(dest + filesz, 0, memsz - filesz);
++
++ /*
++ * We need to check that the input image doesn't have us copy
++ * the whole image zillions of times, as that could lead to
++ * O(n^2) time behaviour and possible DoS by a malicous ELF.
++ */
++ if ( remain_allow_copy < memsz )
++ {
++ elf_mark_broken(elf, "program segments total to more"
++ " than the input image size");
++ break;
++ }
++ remain_allow_copy -= memsz;
++
++ elf_msg(elf, "%s: phdr %" PRIu64 " at 0x%"ELF_PRPTRVAL" -> 0x%"ELF_PRPTRVAL"\n",
++ __func__, i, dest, (elf_ptrval)(dest + filesz));
++ elf_memcpy_safe(elf, dest, ELF_IMAGE_BASE(elf) + offset, filesz);
++ elf_memset_safe(elf, dest + filesz, 0, memsz - filesz);
+ }
+
+ elf_load_bsdsyms(elf);
+ }
+
+-void *elf_get_ptr(struct elf_binary *elf, unsigned long addr)
++elf_ptrval elf_get_ptr(struct elf_binary *elf, unsigned long addr)
+ {
+- return elf->dest + addr - elf->pstart;
++ return ELF_REALPTR2PTRVAL(elf->dest_base) + addr - elf->pstart;
+ }
+
+ uint64_t elf_lookup_addr(struct elf_binary * elf, const char *symbol)
+ {
+- const elf_sym *sym;
++ ELF_HANDLE_DECL(elf_sym) sym;
+ uint64_t value;
+
+ sym = elf_sym_by_name(elf, symbol);
+- if ( sym == NULL )
++ if ( !ELF_HANDLE_VALID(sym) )
+ {
+ elf_err(elf, "%s: not found: %s\n", __FUNCTION__, symbol);
+ return -1;
+diff --git a/xen/common/libelf/libelf-private.h b/xen/common/libelf/libelf-private.h
+index 3ef753c..277be04 100644
+--- a/xen/common/libelf/libelf-private.h
++++ b/xen/common/libelf/libelf-private.h
+@@ -77,7 +77,7 @@
+ #define elf_err(elf, fmt, args ... ) \
+ elf_call_log_callback(elf, 1, fmt , ## args );
+
+-void elf_call_log_callback(struct elf_binary*, int iserr, const char *fmt,...);
++void elf_call_log_callback(struct elf_binary*, bool iserr, const char *fmt,...);
+
+ #define safe_strcpy(d,s) \
+ do { strncpy((d),(s),sizeof((d))-1); \
+@@ -86,6 +86,19 @@ do { strncpy((d),(s),sizeof((d))-1); \
+
+ #endif
+
++#undef memcpy
++#undef memset
++#undef memmove
++#undef strcpy
++
++#define memcpy MISTAKE_unspecified_memcpy
++#define memset MISTAKE_unspecified_memset
++#define memmove MISTAKE_unspecified_memmove
++#define strcpy MISTAKE_unspecified_strcpy
++ /* This prevents libelf from using these undecorated versions
++ * of memcpy, memset, memmove and strcpy. Every call site
++ * must either use elf_mem*_unchecked, or elf_mem*_safe. */
++
+ #endif /* __LIBELF_PRIVATE_H_ */
+
+ /*
+diff --git a/xen/common/libelf/libelf-relocate.c b/xen/common/libelf/libelf-relocate.c
+deleted file mode 100644
+index 7ef4b01..0000000
+--- a/xen/common/libelf/libelf-relocate.c
++++ /dev/null
+@@ -1,372 +0,0 @@
+-/*
+- * ELF relocation code (not used by xen kernel right now).
+- *
+- * This library is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU Lesser General Public
+- * License as published by the Free Software Foundation;
+- * version 2.1 of the License.
+- *
+- * This library is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * Lesser General Public License for more details.
+- *
+- * You should have received a copy of the GNU Lesser General Public
+- * License along with this library; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+- */
+-
+-#include "libelf-private.h"
+-
+-/* ------------------------------------------------------------------------ */
+-
+-static const char *rel_names_i386[] = {
+- "R_386_NONE",
+- "R_386_32",
+- "R_386_PC32",
+- "R_386_GOT32",
+- "R_386_PLT32",
+- "R_386_COPY",
+- "R_386_GLOB_DAT",
+- "R_386_JMP_SLOT",
+- "R_386_RELATIVE",
+- "R_386_GOTOFF",
+- "R_386_GOTPC",
+- "R_386_32PLT",
+- "R_386_TLS_TPOFF",
+- "R_386_TLS_IE",
+- "R_386_TLS_GOTIE",
+- "R_386_TLS_LE",
+- "R_386_TLS_GD",
+- "R_386_TLS_LDM",
+- "R_386_16",
+- "R_386_PC16",
+- "R_386_8",
+- "R_386_PC8",
+- "R_386_TLS_GD_32",
+- "R_386_TLS_GD_PUSH",
+- "R_386_TLS_GD_CALL",
+- "R_386_TLS_GD_POP",
+- "R_386_TLS_LDM_32",
+- "R_386_TLS_LDM_PUSH",
+- "R_386_TLS_LDM_CALL",
+- "R_386_TLS_LDM_POP",
+- "R_386_TLS_LDO_32",
+- "R_386_TLS_IE_32",
+- "R_386_TLS_LE_32",
+- "R_386_TLS_DTPMOD32",
+- "R_386_TLS_DTPOFF32",
+- "R_386_TLS_TPOFF32",
+-};
+-
+-static int elf_reloc_i386(struct elf_binary *elf, int type,
+- uint64_t addr, uint64_t value)
+-{
+- void *ptr = elf_get_ptr(elf, addr);
+- uint32_t *u32;
+-
+- switch ( type )
+- {
+- case 1 /* R_386_32 */ :
+- u32 = ptr;
+- *u32 += elf->reloc_offset;
+- break;
+- case 2 /* R_386_PC32 */ :
+- /* nothing */
+- break;
+- default:
+- return -1;
+- }
+- return 0;
+-}
+-
+-/* ------------------------------------------------------------------------ */
+-
+-static const char *rel_names_x86_64[] = {
+- "R_X86_64_NONE",
+- "R_X86_64_64",
+- "R_X86_64_PC32",
+- "R_X86_64_GOT32",
+- "R_X86_64_PLT32",
+- "R_X86_64_COPY",
+- "R_X86_64_GLOB_DAT",
+- "R_X86_64_JUMP_SLOT",
+- "R_X86_64_RELATIVE",
+- "R_X86_64_GOTPCREL",
+- "R_X86_64_32",
+- "R_X86_64_32S",
+- "R_X86_64_16",
+- "R_X86_64_PC16",
+- "R_X86_64_8",
+- "R_X86_64_PC8",
+- "R_X86_64_DTPMOD64",
+- "R_X86_64_DTPOFF64",
+- "R_X86_64_TPOFF64",
+- "R_X86_64_TLSGD",
+- "R_X86_64_TLSLD",
+- "R_X86_64_DTPOFF32",
+- "R_X86_64_GOTTPOFF",
+- "R_X86_64_TPOFF32",
+-};
+-
+-static int elf_reloc_x86_64(struct elf_binary *elf, int type,
+- uint64_t addr, uint64_t value)
+-{
+- void *ptr = elf_get_ptr(elf, addr);
+- uint64_t *u64;
+- uint32_t *u32;
+- int32_t *s32;
+-
+- switch ( type )
+- {
+- case 1 /* R_X86_64_64 */ :
+- u64 = ptr;
+- value += elf->reloc_offset;
+- *u64 = value;
+- break;
+- case 2 /* R_X86_64_PC32 */ :
+- u32 = ptr;
+- *u32 = value - addr;
+- if ( *u32 != (uint32_t)(value - addr) )
+- {
+- elf_err(elf, "R_X86_64_PC32 overflow: 0x%" PRIx32
+- " != 0x%" PRIx32 "\n",
+- *u32, (uint32_t) (value - addr));
+- return -1;
+- }
+- break;
+- case 10 /* R_X86_64_32 */ :
+- u32 = ptr;
+- value += elf->reloc_offset;
+- *u32 = value;
+- if ( *u32 != value )
+- {
+- elf_err(elf, "R_X86_64_32 overflow: 0x%" PRIx32
+- " != 0x%" PRIx64 "\n",
+- *u32, value);
+- return -1;
+- }
+- break;
+- case 11 /* R_X86_64_32S */ :
+- s32 = ptr;
+- value += elf->reloc_offset;
+- *s32 = value;
+- if ( *s32 != (int64_t) value )
+- {
+- elf_err(elf, "R_X86_64_32S overflow: 0x%" PRIx32
+- " != 0x%" PRIx64 "\n",
+- *s32, (int64_t) value);
+- return -1;
+- }
+- break;
+- default:
+- return -1;
+- }
+- return 0;
+-}
+-
+-/* ------------------------------------------------------------------------ */
+-
+-static struct relocs {
+- const char **names;
+- int count;
+- int (*func) (struct elf_binary * elf, int type, uint64_t addr,
+- uint64_t value);
+-} relocs[] =
+-/* *INDENT-OFF* */
+-{
+- [EM_386] = {
+- .names = rel_names_i386,
+- .count = sizeof(rel_names_i386) / sizeof(rel_names_i386[0]),
+- .func = elf_reloc_i386,
+- },
+- [EM_X86_64] = {
+- .names = rel_names_x86_64,
+- .count = sizeof(rel_names_x86_64) / sizeof(rel_names_x86_64[0]),
+- .func = elf_reloc_x86_64,
+- }
+-};
+-/* *INDENT-ON* */
+-
+-/* ------------------------------------------------------------------------ */
+-
+-static const char *rela_name(int machine, int type)
+-{
+- if ( machine > sizeof(relocs) / sizeof(relocs[0]) )
+- return "unknown mach";
+- if ( !relocs[machine].names )
+- return "unknown mach";
+- if ( type > relocs[machine].count )
+- return "unknown rela";
+- return relocs[machine].names[type];
+-}
+-
+-static int elf_reloc_section(struct elf_binary *elf,
+- const elf_shdr * rels,
+- const elf_shdr * sect, const elf_shdr * syms)
+-{
+- const void *ptr, *end;
+- const elf_shdr *shdr;
+- const elf_rela *rela;
+- const elf_rel *rel;
+- const elf_sym *sym;
+- uint64_t s_type;
+- uint64_t r_offset;
+- uint64_t r_info;
+- uint64_t r_addend;
+- int r_type, r_sym;
+- size_t rsize;
+- uint64_t shndx, sbase, addr, value;
+- const char *sname;
+- int machine;
+-
+- machine = elf_uval(elf, elf->ehdr, e_machine);
+- if ( (machine >= (sizeof(relocs) / sizeof(relocs[0]))) ||
+- (relocs[machine].func == NULL) )
+- {
+- elf_err(elf, "%s: can't handle machine %d\n",
+- __FUNCTION__, machine);
+- return -1;
+- }
+- if ( elf_swap(elf) )
+- {
+- elf_err(elf, "%s: non-native byte order, relocation not supported\n",
+- __FUNCTION__);
+- return -1;
+- }
+-
+- s_type = elf_uval(elf, rels, sh_type);
+- rsize = (SHT_REL == s_type) ? elf_size(elf, rel) : elf_size(elf, rela);
+- ptr = elf_section_start(elf, rels);
+- end = elf_section_end(elf, rels);
+-
+- for ( ; ptr < end; ptr += rsize )
+- {
+- switch ( s_type )
+- {
+- case SHT_REL:
+- rel = ptr;
+- r_offset = elf_uval(elf, rel, r_offset);
+- r_info = elf_uval(elf, rel, r_info);
+- r_addend = 0;
+- break;
+- case SHT_RELA:
+- rela = ptr;
+- r_offset = elf_uval(elf, rela, r_offset);
+- r_info = elf_uval(elf, rela, r_info);
+- r_addend = elf_uval(elf, rela, r_addend);
+- break;
+- default:
+- /* can't happen */
+- return -1;
+- }
+- if ( elf_64bit(elf) )
+- {
+- r_type = ELF64_R_TYPE(r_info);
+- r_sym = ELF64_R_SYM(r_info);
+- }
+- else
+- {
+- r_type = ELF32_R_TYPE(r_info);
+- r_sym = ELF32_R_SYM(r_info);
+- }
+-
+- sym = elf_sym_by_index(elf, r_sym);
+- shndx = elf_uval(elf, sym, st_shndx);
+- switch ( shndx )
+- {
+- case SHN_UNDEF:
+- sname = "*UNDEF*";
+- sbase = 0;
+- break;
+- case SHN_COMMON:
+- elf_err(elf, "%s: invalid section: %" PRId64 "\n",
+- __FUNCTION__, shndx);
+- return -1;
+- case SHN_ABS:
+- sname = "*ABS*";
+- sbase = 0;
+- break;
+- default:
+- shdr = elf_shdr_by_index(elf, shndx);
+- if ( shdr == NULL )
+- {
+- elf_err(elf, "%s: invalid section: %" PRId64 "\n",
+- __FUNCTION__, shndx);
+- return -1;
+- }
+- sname = elf_section_name(elf, shdr);
+- sbase = elf_uval(elf, shdr, sh_addr);
+- }
+-
+- addr = r_offset;
+- value = elf_uval(elf, sym, st_value);
+- value += r_addend;
+-
+- if ( elf->log_callback && (elf->verbose > 1) )
+- {
+- uint64_t st_name = elf_uval(elf, sym, st_name);
+- const char *name = st_name ? elf->sym_strtab + st_name : "*NONE*";
+-
+- elf_msg(elf,
+- "%s: type %s [%d], off 0x%" PRIx64 ", add 0x%" PRIx64 ","
+- " sym %s [0x%" PRIx64 "], sec %s [0x%" PRIx64 "]"
+- " -> addr 0x%" PRIx64 " value 0x%" PRIx64 "\n",
+- __FUNCTION__, rela_name(machine, r_type), r_type, r_offset,
+- r_addend, name, elf_uval(elf, sym, st_value), sname, sbase,
+- addr, value);
+- }
+-
+- if ( relocs[machine].func(elf, r_type, addr, value) == -1 )
+- {
+- elf_err(elf, "%s: unknown/unsupported reloc type %s [%d]\n",
+- __FUNCTION__, rela_name(machine, r_type), r_type);
+- return -1;
+- }
+- }
+- return 0;
+-}
+-
+-int elf_reloc(struct elf_binary *elf)
+-{
+- const elf_shdr *rels, *sect, *syms;
+- uint64_t i, count, type;
+-
+- count = elf_shdr_count(elf);
+- for ( i = 0; i < count; i++ )
+- {
+- rels = elf_shdr_by_index(elf, i);
+- type = elf_uval(elf, rels, sh_type);
+- if ( (type != SHT_REL) && (type != SHT_RELA) )
+- continue;
+-
+- sect = elf_shdr_by_index(elf, elf_uval(elf, rels, sh_info));
+- syms = elf_shdr_by_index(elf, elf_uval(elf, rels, sh_link));
+- if ( NULL == sect || NULL == syms )
+- continue;
+-
+- if ( !(elf_uval(elf, sect, sh_flags) & SHF_ALLOC) )
+- {
+- elf_msg(elf, "%s: relocations for %s, skipping\n",
+- __FUNCTION__, elf_section_name(elf, sect));
+- continue;
+- }
+-
+- elf_msg(elf, "%s: relocations for %s @ 0x%" PRIx64 "\n",
+- __FUNCTION__, elf_section_name(elf, sect),
+- elf_uval(elf, sect, sh_addr));
+- if ( elf_reloc_section(elf, rels, sect, syms) != 0 )
+- return -1;
+- }
+- return 0;
+-}
+-
+-/*
+- * Local variables:
+- * mode: C
+- * c-set-style: "BSD"
+- * c-basic-offset: 4
+- * tab-width: 4
+- * indent-tabs-mode: nil
+- * End:
+- */
+diff --git a/xen/common/libelf/libelf-tools.c b/xen/common/libelf/libelf-tools.c
+index 885d5e8..c765fbc 100644
+--- a/xen/common/libelf/libelf-tools.c
++++ b/xen/common/libelf/libelf-tools.c
+@@ -20,201 +20,292 @@
+
+ /* ------------------------------------------------------------------------ */
+
+-uint64_t elf_access_unsigned(struct elf_binary * elf, const void *ptr,
+- uint64_t offset, size_t size)
++void elf_mark_broken(struct elf_binary *elf, const char *msg)
+ {
+- int need_swap = elf_swap(elf);
++ if ( elf->broken == NULL )
++ elf->broken = msg;
++}
++
++const char *elf_check_broken(const struct elf_binary *elf)
++{
++ return elf->broken;
++}
++
++static bool elf_ptrval_in_range(elf_ptrval ptrval, uint64_t size,
++ const void *region, uint64_t regionsize)
++ /*
++ * Returns true if the putative memory area [ptrval,ptrval+size>
++ * is completely inside the region [region,region+regionsize>.
++ *
++ * ptrval and size are the untrusted inputs to be checked.
++ * region and regionsize are trusted and must be correct and valid,
++ * although it is OK for region to perhaps be maliciously NULL
++ * (but not some other malicious value).
++ */
++{
++ elf_ptrval regionp = (elf_ptrval)region;
++
++ if ( (region == NULL) ||
++ (ptrval < regionp) || /* start is before region */
++ (ptrval > regionp + regionsize) || /* start is after region */
++ (size > regionsize - (ptrval - regionp)) ) /* too big */
++ return 0;
++ return 1;
++}
++
++bool elf_access_ok(struct elf_binary * elf,
++ uint64_t ptrval, size_t size)
++{
++ if ( elf_ptrval_in_range(ptrval, size, elf->image_base, elf->size) )
++ return 1;
++ if ( elf_ptrval_in_range(ptrval, size, elf->dest_base, elf->dest_size) )
++ return 1;
++ if ( elf_ptrval_in_range(ptrval, size,
++ elf->caller_xdest_base, elf->caller_xdest_size) )
++ return 1;
++ elf_mark_broken(elf, "out of range access");
++ return 0;
++}
++
++void elf_memcpy_safe(struct elf_binary *elf, elf_ptrval dst,
++ elf_ptrval src, size_t size)
++{
++ if ( elf_access_ok(elf, dst, size) &&
++ elf_access_ok(elf, src, size) )
++ {
++ /* use memmove because these checks do not prove that the
++ * regions don't overlap and overlapping regions grant
++ * permission for compiler malice */
++ elf_memmove_unchecked(ELF_UNSAFE_PTR(dst), ELF_UNSAFE_PTR(src), size);
++ }
++}
++
++void elf_memset_safe(struct elf_binary *elf, elf_ptrval dst, int c, size_t size)
++{
++ if ( elf_access_ok(elf, dst, size) )
++ {
++ elf_memset_unchecked(ELF_UNSAFE_PTR(dst), c, size);
++ }
++}
++
++uint64_t elf_access_unsigned(struct elf_binary * elf, elf_ptrval base,
++ uint64_t moreoffset, size_t size)
++{
++ elf_ptrval ptrval = base + moreoffset;
++ bool need_swap = elf_swap(elf);
+ const uint8_t *u8;
+ const uint16_t *u16;
+ const uint32_t *u32;
+ const uint64_t *u64;
+
++ if ( !elf_access_ok(elf, ptrval, size) )
++ return 0;
++
+ switch ( size )
+ {
+ case 1:
+- u8 = ptr + offset;
++ u8 = (const void*)ptrval;
+ return *u8;
+ case 2:
+- u16 = ptr + offset;
++ u16 = (const void*)ptrval;
+ return need_swap ? bswap_16(*u16) : *u16;
+ case 4:
+- u32 = ptr + offset;
++ u32 = (const void*)ptrval;
+ return need_swap ? bswap_32(*u32) : *u32;
+ case 8:
+- u64 = ptr + offset;
++ u64 = (const void*)ptrval;
+ return need_swap ? bswap_64(*u64) : *u64;
+ default:
+ return 0;
+ }
+ }
+
+-int64_t elf_access_signed(struct elf_binary *elf, const void *ptr,
+- uint64_t offset, size_t size)
+-{
+- int need_swap = elf_swap(elf);
+- const int8_t *s8;
+- const int16_t *s16;
+- const int32_t *s32;
+- const int64_t *s64;
+-
+- switch ( size )
+- {
+- case 1:
+- s8 = ptr + offset;
+- return *s8;
+- case 2:
+- s16 = ptr + offset;
+- return need_swap ? bswap_16(*s16) : *s16;
+- case 4:
+- s32 = ptr + offset;
+- return need_swap ? bswap_32(*s32) : *s32;
+- case 8:
+- s64 = ptr + offset;
+- return need_swap ? bswap_64(*s64) : *s64;
+- default:
+- return 0;
+- }
+-}
+-
+ uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr)
+ {
+- int elf_round = (elf_64bit(elf) ? 8 : 4) - 1;
++ uint64_t elf_round = (elf_64bit(elf) ? 8 : 4) - 1;
+
+ return (addr + elf_round) & ~elf_round;
+ }
+
+ /* ------------------------------------------------------------------------ */
+
+-int elf_shdr_count(struct elf_binary *elf)
++unsigned elf_shdr_count(struct elf_binary *elf)
+ {
+- return elf_uval(elf, elf->ehdr, e_shnum);
++ unsigned count = elf_uval(elf, elf->ehdr, e_shnum);
++ uint64_t max = elf->size / sizeof(Elf32_Shdr);
++ if (max > ~(unsigned)0)
++ max = ~(unsigned)0; /* Xen doesn't have limits.h :-/ */
++ if (count > max)
++ {
++ elf_mark_broken(elf, "far too many section headers");
++ count = max;
++ }
++ return count;
+ }
+
+-int elf_phdr_count(struct elf_binary *elf)
++unsigned elf_phdr_count(struct elf_binary *elf)
+ {
+ return elf_uval(elf, elf->ehdr, e_phnum);
+ }
+
+-const elf_shdr *elf_shdr_by_name(struct elf_binary *elf, const char *name)
++ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *name)
+ {
+ uint64_t count = elf_shdr_count(elf);
+- const elf_shdr *shdr;
++ ELF_HANDLE_DECL(elf_shdr) shdr;
+ const char *sname;
+- int i;
++ unsigned i;
+
+ for ( i = 0; i < count; i++ )
+ {
+ shdr = elf_shdr_by_index(elf, i);
++ if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
++ /* input has an insane section header count field */
++ break;
+ sname = elf_section_name(elf, shdr);
+ if ( sname && !strcmp(sname, name) )
+ return shdr;
+ }
+- return NULL;
++ return ELF_INVALID_HANDLE(elf_shdr);
+ }
+
+-const elf_shdr *elf_shdr_by_index(struct elf_binary *elf, int index)
++ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_index(struct elf_binary *elf, unsigned index)
+ {
+ uint64_t count = elf_shdr_count(elf);
+- const void *ptr;
++ elf_ptrval ptr;
+
+ if ( index >= count )
+- return NULL;
++ return ELF_INVALID_HANDLE(elf_shdr);
+
+- ptr = (elf->image
++ ptr = (ELF_IMAGE_BASE(elf)
+ + elf_uval(elf, elf->ehdr, e_shoff)
+ + elf_uval(elf, elf->ehdr, e_shentsize) * index);
+- return ptr;
++ return ELF_MAKE_HANDLE(elf_shdr, ptr);
+ }
+
+-const elf_phdr *elf_phdr_by_index(struct elf_binary *elf, int index)
++ELF_HANDLE_DECL(elf_phdr) elf_phdr_by_index(struct elf_binary *elf, unsigned index)
+ {
+ uint64_t count = elf_uval(elf, elf->ehdr, e_phnum);
+- const void *ptr;
++ elf_ptrval ptr;
+
+ if ( index >= count )
+- return NULL;
++ return ELF_INVALID_HANDLE(elf_phdr);
+
+- ptr = (elf->image
++ ptr = (ELF_IMAGE_BASE(elf)
+ + elf_uval(elf, elf->ehdr, e_phoff)
+ + elf_uval(elf, elf->ehdr, e_phentsize) * index);
+- return ptr;
++ return ELF_MAKE_HANDLE(elf_phdr, ptr);
+ }
+
+-const char *elf_section_name(struct elf_binary *elf, const elf_shdr * shdr)
++
++const char *elf_section_name(struct elf_binary *elf,
++ ELF_HANDLE_DECL(elf_shdr) shdr)
+ {
+- if ( elf->sec_strtab == NULL )
++ if ( ELF_PTRVAL_INVALID(elf->sec_strtab) )
+ return "unknown";
+- return elf->sec_strtab + elf_uval(elf, shdr, sh_name);
++
++ return elf_strval(elf, elf->sec_strtab + elf_uval(elf, shdr, sh_name));
++}
++
++const char *elf_strval(struct elf_binary *elf, elf_ptrval start)
++{
++ uint64_t length;
++
++ for ( length = 0; ; length++ ) {
++ if ( !elf_access_ok(elf, start + length, 1) )
++ return NULL;
++ if ( !elf_access_unsigned(elf, start, length, 1) )
++ /* ok */
++ return ELF_UNSAFE_PTR(start);
++ if ( length >= ELF_MAX_STRING_LENGTH )
++ {
++ elf_mark_broken(elf, "excessively long string");
++ return NULL;
++ }
++ }
++}
++
++const char *elf_strfmt(struct elf_binary *elf, elf_ptrval start)
++{
++ const char *str = elf_strval(elf, start);
++
++ if ( str == NULL )
++ return "(invalid)";
++ return str;
+ }
+
+-const void *elf_section_start(struct elf_binary *elf, const elf_shdr * shdr)
++elf_ptrval elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr)
+ {
+- return elf->image + elf_uval(elf, shdr, sh_offset);
++ return ELF_IMAGE_BASE(elf) + elf_uval(elf, shdr, sh_offset);
+ }
+
+-const void *elf_section_end(struct elf_binary *elf, const elf_shdr * shdr)
++elf_ptrval elf_section_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr)
+ {
+- return elf->image
++ return ELF_IMAGE_BASE(elf)
+ + elf_uval(elf, shdr, sh_offset) + elf_uval(elf, shdr, sh_size);
+ }
+
+-const void *elf_segment_start(struct elf_binary *elf, const elf_phdr * phdr)
++elf_ptrval elf_segment_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
+ {
+- return elf->image + elf_uval(elf, phdr, p_offset);
++ return ELF_IMAGE_BASE(elf)
++ + elf_uval(elf, phdr, p_offset);
+ }
+
+-const void *elf_segment_end(struct elf_binary *elf, const elf_phdr * phdr)
++elf_ptrval elf_segment_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
+ {
+- return elf->image
++ return ELF_IMAGE_BASE(elf)
+ + elf_uval(elf, phdr, p_offset) + elf_uval(elf, phdr, p_filesz);
+ }
+
+-const elf_sym *elf_sym_by_name(struct elf_binary *elf, const char *symbol)
++ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *symbol)
+ {
+- const void *ptr = elf_section_start(elf, elf->sym_tab);
+- const void *end = elf_section_end(elf, elf->sym_tab);
+- const elf_sym *sym;
++ elf_ptrval ptr = elf_section_start(elf, elf->sym_tab);
++ elf_ptrval end = elf_section_end(elf, elf->sym_tab);
++ ELF_HANDLE_DECL(elf_sym) sym;
+ uint64_t info, name;
++ const char *sym_name;
+
+ for ( ; ptr < end; ptr += elf_size(elf, sym) )
+ {
+- sym = ptr;
++ sym = ELF_MAKE_HANDLE(elf_sym, ptr);
+ info = elf_uval(elf, sym, st_info);
+ name = elf_uval(elf, sym, st_name);
+ if ( ELF32_ST_BIND(info) != STB_GLOBAL )
+ continue;
+- if ( strcmp(elf->sym_strtab + name, symbol) )
++ sym_name = elf_strval(elf, elf->sym_strtab + name);
++ if ( sym_name == NULL ) /* out of range, oops */
++ return ELF_INVALID_HANDLE(elf_sym);
++ if ( strcmp(sym_name, symbol) )
+ continue;
+ return sym;
+ }
+- return NULL;
++ return ELF_INVALID_HANDLE(elf_sym);
+ }
+
+-const elf_sym *elf_sym_by_index(struct elf_binary *elf, int index)
++ELF_HANDLE_DECL(elf_sym) elf_sym_by_index(struct elf_binary *elf, unsigned index)
+ {
+- const void *ptr = elf_section_start(elf, elf->sym_tab);
+- const elf_sym *sym;
++ elf_ptrval ptr = elf_section_start(elf, elf->sym_tab);
++ ELF_HANDLE_DECL(elf_sym) sym;
+
+- sym = ptr + index * elf_size(elf, sym);
++ sym = ELF_MAKE_HANDLE(elf_sym, ptr + index * elf_size(elf, sym));
+ return sym;
+ }
+
+-const char *elf_note_name(struct elf_binary *elf, const elf_note * note)
++const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
+ {
+- return (void *)note + elf_size(elf, note);
++ return elf_strval(elf, ELF_HANDLE_PTRVAL(note) + elf_size(elf, note));
+ }
+
+-const void *elf_note_desc(struct elf_binary *elf, const elf_note * note)
++elf_ptrval elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
+ {
+- int namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
++ unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
+
+- return (void *)note + elf_size(elf, note) + namesz;
++ return ELF_HANDLE_PTRVAL(note) + elf_size(elf, note) + namesz;
+ }
+
+-uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note)
++uint64_t elf_note_numeric(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
+ {
+- const void *desc = elf_note_desc(elf, note);
+- int descsz = elf_uval(elf, note, descsz);
++ elf_ptrval desc = elf_note_desc(elf, note);
++ unsigned descsz = elf_uval(elf, note, descsz);
+
+ switch (descsz)
+ {
+@@ -227,24 +318,35 @@ uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note)
+ return 0;
+ }
+ }
+-const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note)
++
++ELF_HANDLE_DECL(elf_note) elf_note_next(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
+ {
+- int namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
+- int descsz = (elf_uval(elf, note, descsz) + 3) & ~3;
++ unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
++ unsigned descsz = (elf_uval(elf, note, descsz) + 3) & ~3;
++
++ elf_ptrval ptrval = ELF_HANDLE_PTRVAL(note)
++ + elf_size(elf, note) + namesz + descsz;
+
+- return (void *)note + elf_size(elf, note) + namesz + descsz;
++ if ( ( ptrval <= ELF_HANDLE_PTRVAL(note) || /* wrapped or stuck */
++ !elf_access_ok(elf, ELF_HANDLE_PTRVAL(note), 1) ) )
++ ptrval = ELF_MAX_PTRVAL; /* terminate caller's loop */
++
++ return ELF_MAKE_HANDLE(elf_note, ptrval);
+ }
+
+ /* ------------------------------------------------------------------------ */
+
+-int elf_is_elfbinary(const void *image)
++bool elf_is_elfbinary(const void *image_start, size_t image_size)
+ {
+- const Elf32_Ehdr *ehdr = image;
++ const Elf32_Ehdr *ehdr = image_start;
++
++ if ( image_size < sizeof(*ehdr) )
++ return 0;
+
+ return IS_ELF(*ehdr);
+ }
+
+-int elf_phdr_is_loadable(struct elf_binary *elf, const elf_phdr * phdr)
++bool elf_phdr_is_loadable(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
+ {
+ uint64_t p_type = elf_uval(elf, phdr, p_type);
+ uint64_t p_flags = elf_uval(elf, phdr, p_flags);
+diff --git a/xen/include/xen/libelf.h b/xen/include/xen/libelf.h
+index 584d8b3..41fc513 100644
+--- a/xen/include/xen/libelf.h
++++ b/xen/include/xen/libelf.h
+@@ -29,6 +29,11 @@
+ #error define architectural endianness
+ #endif
+
++#include <stdbool.h>
++
++typedef int elf_errorstatus; /* 0: ok; -ve (normally -1): error */
++typedef int elf_negerrnoval; /* 0: ok; -EFOO: error */
++
+ #undef ELFSIZE
+ #include "elfstructs.h"
+ #ifdef __XEN__
+@@ -42,12 +47,100 @@
+
+ struct elf_binary;
+ typedef void elf_log_callback(struct elf_binary*, void *caller_data,
+- int iserr, const char *fmt, va_list al);
++ bool iserr, const char *fmt, va_list al);
++
++#endif
++
++#define ELF_MAX_STRING_LENGTH 4096
++#define ELF_MAX_TOTAL_NOTE_COUNT 65536
+
++/* ------------------------------------------------------------------------ */
++
++/* Macros for accessing the input image and output area. */
++
++/*
++ * We abstract away the pointerness of these pointers, replacing
++ * various void*, char* and struct* with the following:
++ * elf_ptrval A pointer to a byte; one can do pointer arithmetic
++ * on this.
++ * HANDLE A pointer to a struct. There is one of these types
++ * for each pointer type - that is, for each "structname".
++ * In the arguments to the various HANDLE macros, structname
++ * must be a single identifier which is a typedef.
++ * It is not permitted to do arithmetic on these
++ * pointers. In the current code attempts to do so will
++ * compile, but in the next patch this will become a
++ * compile error.
++ */
++
++#ifdef __XEN__
++# ifdef __i386__
++typedef uint32_t elf_uintptr_t;
++# define ELF_PRPTRVAL PRIu32
++# else
++typedef uint64_t elf_uintptr_t;
++# define ELF_PRPTRVAL PRIu64
++# endif
++#else
++typedef uintptr_t elf_uintptr_t;
++# define ELF_PRPTRVAL PRIuPTR
+ #endif
+
++typedef elf_uintptr_t elf_ptrval;
++
++#define ELF_REALPTR2PTRVAL(realpointer) ((elf_ptrval)(realpointer))
++ /* Converts an actual C pointer into a PTRVAL */
++
++#define ELF_HANDLE_DECL(structname) structname##_handle
++ /* Provides a type declaration for a HANDLE. */
++
++#define ELF_DEFINE_HANDLE(structname) \
++ typedef union { \
++ elf_ptrval ptrval; \
++ const structname *typeonly; /* for sizeof, offsetof, &c only */ \
++ } structname##_handle;
++ /*
++ * This must be invoked for each HANDLE type to define
++ * the actual C type used for that kind of HANDLE.
++ */
++
++#define ELF_MAKE_HANDLE(structname, ptrval) ((structname##_handle){ ptrval })
++ /* Converts a PTRVAL to a HANDLE */
++
++#define ELF_IMAGE_BASE(elf) ((elf_ptrval)(elf)->image_base)
++ /* Returns the base of the image as a PTRVAL. */
++
++#define ELF_HANDLE_PTRVAL(handleval) ((handleval).ptrval)
++ /* Converts a HANDLE to a PTRVAL. */
++
++#define ELF_UNSAFE_PTR(ptrval) ((void*)(elf_uintptr_t)(ptrval))
++ /*
++ * Turns a PTRVAL into an actual C pointer. Before this is done
++ * the caller must have ensured that the PTRVAL does in fact point
++ * to a permissible location.
++ */
++
++/* PTRVALs can be INVALID (ie, NULL). */
++#define ELF_INVALID_PTRVAL ((elf_ptrval)0) /* returns NULL PTRVAL */
++#define ELF_INVALID_HANDLE(structname) /* returns NULL handle */ \
++ ELF_MAKE_HANDLE(structname, ELF_INVALID_PTRVAL)
++#define ELF_PTRVAL_VALID(ptrval) (!!(ptrval)) /* } */
++#define ELF_HANDLE_VALID(handleval) (!!(handleval).ptrval) /* } predicates */
++#define ELF_PTRVAL_INVALID(ptrval) (!ELF_PTRVAL_VALID((ptrval))) /* } */
++
++#define ELF_MAX_PTRVAL (~(elf_ptrval)0)
++ /* PTRVAL value guaranteed to compare > to any valid PTRVAL */
++
++/* For internal use by other macros here */
++#define ELF__HANDLE_FIELD_TYPE(handleval, elm) \
++ typeof((handleval).typeonly->elm)
++#define ELF__HANDLE_FIELD_OFFSET(handleval, elm) \
++ offsetof(typeof(*(handleval).typeonly),elm)
++
++
+ /* ------------------------------------------------------------------------ */
+
++
+ typedef union {
+ Elf32_Ehdr e32;
+ Elf64_Ehdr e64;
+@@ -83,20 +176,32 @@ typedef union {
+ Elf64_Note e64;
+ } elf_note;
+
++ELF_DEFINE_HANDLE(elf_ehdr)
++ELF_DEFINE_HANDLE(elf_shdr)
++ELF_DEFINE_HANDLE(elf_phdr)
++ELF_DEFINE_HANDLE(elf_sym)
++ELF_DEFINE_HANDLE(elf_note)
++
+ struct elf_binary {
+ /* elf binary */
+- const char *image;
++ const void *image_base;
+ size_t size;
+ char class;
+ char data;
+
+- const elf_ehdr *ehdr;
+- const char *sec_strtab;
+- const elf_shdr *sym_tab;
+- const char *sym_strtab;
++ ELF_HANDLE_DECL(elf_ehdr) ehdr;
++ elf_ptrval sec_strtab;
++ ELF_HANDLE_DECL(elf_shdr) sym_tab;
++ uint64_t sym_strtab;
+
+ /* loaded to */
+- char *dest;
++ /*
++ * dest_base and dest_size are trusted and must be correct;
++ * whenever dest_size is not 0, both of these must be valid
++ * so long as the struct elf_binary is in use.
++ */
++ char *dest_base;
++ size_t dest_size;
+ uint64_t pstart;
+ uint64_t pend;
+ uint64_t reloc_offset;
+@@ -104,12 +209,22 @@ struct elf_binary {
+ uint64_t bsd_symtab_pstart;
+ uint64_t bsd_symtab_pend;
+
++ /*
++ * caller's other acceptable destination
++ *
++ * Again, these are trusted and must be valid (or 0) so long
++ * as the struct elf_binary is in use.
++ */
++ void *caller_xdest_base;
++ uint64_t caller_xdest_size;
++
+ #ifndef __XEN__
+ /* misc */
+ elf_log_callback *log_callback;
+ void *log_caller_data;
+ #endif
+- int verbose;
++ bool verbose;
++ const char *broken;
+ };
+
+ /* ------------------------------------------------------------------------ */
+@@ -127,86 +242,143 @@ struct elf_binary {
+ #define elf_lsb(elf) (ELFDATA2LSB == (elf)->data)
+ #define elf_swap(elf) (NATIVE_ELFDATA != (elf)->data)
+
+-#define elf_uval(elf, str, elem) \
+- ((ELFCLASS64 == (elf)->class) \
+- ? elf_access_unsigned((elf), (str), \
+- offsetof(typeof(*(str)),e64.elem), \
+- sizeof((str)->e64.elem)) \
+- : elf_access_unsigned((elf), (str), \
+- offsetof(typeof(*(str)),e32.elem), \
+- sizeof((str)->e32.elem)))
+-
+-#define elf_sval(elf, str, elem) \
+- ((ELFCLASS64 == (elf)->class) \
+- ? elf_access_signed((elf), (str), \
+- offsetof(typeof(*(str)),e64.elem), \
+- sizeof((str)->e64.elem)) \
+- : elf_access_signed((elf), (str), \
+- offsetof(typeof(*(str)),e32.elem), \
+- sizeof((str)->e32.elem)))
+-
+-#define elf_size(elf, str) \
+- ((ELFCLASS64 == (elf)->class) \
+- ? sizeof((str)->e64) : sizeof((str)->e32))
++#define elf_uval_3264(elf, handle, elem) \
++ elf_access_unsigned((elf), (handle).ptrval, \
++ offsetof(typeof(*(handle).typeonly),elem), \
++ sizeof((handle).typeonly->elem))
++
++#define elf_uval(elf, handle, elem) \
++ ((ELFCLASS64 == (elf)->class) \
++ ? elf_uval_3264(elf, handle, e64.elem) \
++ : elf_uval_3264(elf, handle, e32.elem))
++ /*
++ * Reads an unsigned field in a header structure in the ELF.
++ * str is a HANDLE, and elem is the field name in it.
++ */
+
+-uint64_t elf_access_unsigned(struct elf_binary *elf, const void *ptr,
++
++#define elf_size(elf, handle_or_handletype) ({ \
++ typeof(handle_or_handletype) elf_size__dummy; \
++ ((ELFCLASS64 == (elf)->class) \
++ ? sizeof(elf_size__dummy.typeonly->e64) \
++ : sizeof(elf_size__dummy.typeonly->e32)); \
++})
++ /*
++ * Returns the size of the substructure for the appropriate 32/64-bitness.
++ * str should be a HANDLE.
++ */
++
++uint64_t elf_access_unsigned(struct elf_binary *elf, elf_ptrval ptr,
+ uint64_t offset, size_t size);
+-int64_t elf_access_signed(struct elf_binary *elf, const void *ptr,
+- uint64_t offset, size_t size);
++ /* Reads a field at arbitrary offset and alignemnt */
+
+ uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr);
+
++const char *elf_strval(struct elf_binary *elf, elf_ptrval start);
++ /* may return NULL if the string is out of range etc. */
++
++const char *elf_strfmt(struct elf_binary *elf, elf_ptrval start);
++ /* like elf_strval but returns "(invalid)" instead of NULL */
++
++void elf_memcpy_safe(struct elf_binary*, elf_ptrval dst, elf_ptrval src, size_t);
++void elf_memset_safe(struct elf_binary*, elf_ptrval dst, int c, size_t);
++ /*
++ * Versions of memcpy and memset which arrange never to write
++ * outside permitted areas.
++ */
++
++bool elf_access_ok(struct elf_binary * elf,
++ uint64_t ptrval, size_t size);
++
++#define elf_store_val(elf, type, ptr, val) \
++ ({ \
++ typeof(type) elf_store__val = (val); \
++ elf_ptrval elf_store__targ = ptr; \
++ if (elf_access_ok((elf), elf_store__targ, \
++ sizeof(elf_store__val))) { \
++ elf_memcpy_unchecked((void*)elf_store__targ, &elf_store__val, \
++ sizeof(elf_store__val)); \
++ } \
++ }) \
++ /* Stores a value at a particular PTRVAL. */
++
++#define elf_store_field(elf, hdr, elm, val) \
++ (elf_store_val((elf), ELF__HANDLE_FIELD_TYPE(hdr, elm), \
++ ELF_HANDLE_PTRVAL(hdr) + ELF__HANDLE_FIELD_OFFSET(hdr, elm), \
++ (val)))
++ /* Stores a 32/64-bit field. hdr is a HANDLE and elm is the field name. */
++
++
+ /* ------------------------------------------------------------------------ */
+ /* xc_libelf_tools.c */
+
+-int elf_shdr_count(struct elf_binary *elf);
+-int elf_phdr_count(struct elf_binary *elf);
++unsigned elf_shdr_count(struct elf_binary *elf);
++unsigned elf_phdr_count(struct elf_binary *elf);
++
++ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *name);
++ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_index(struct elf_binary *elf, unsigned index);
++ELF_HANDLE_DECL(elf_phdr) elf_phdr_by_index(struct elf_binary *elf, unsigned index);
+
+-const elf_shdr *elf_shdr_by_name(struct elf_binary *elf, const char *name);
+-const elf_shdr *elf_shdr_by_index(struct elf_binary *elf, int index);
+-const elf_phdr *elf_phdr_by_index(struct elf_binary *elf, int index);
++const char *elf_section_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr); /* might return NULL if inputs are invalid */
++elf_ptrval elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr);
++elf_ptrval elf_section_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr);
+
+-const char *elf_section_name(struct elf_binary *elf, const elf_shdr * shdr);
+-const void *elf_section_start(struct elf_binary *elf, const elf_shdr * shdr);
+-const void *elf_section_end(struct elf_binary *elf, const elf_shdr * shdr);
++elf_ptrval elf_segment_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr);
++elf_ptrval elf_segment_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr);
+
+-const void *elf_segment_start(struct elf_binary *elf, const elf_phdr * phdr);
+-const void *elf_segment_end(struct elf_binary *elf, const elf_phdr * phdr);
++ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *symbol);
++ELF_HANDLE_DECL(elf_sym) elf_sym_by_index(struct elf_binary *elf, unsigned index);
+
+-const elf_sym *elf_sym_by_name(struct elf_binary *elf, const char *symbol);
+-const elf_sym *elf_sym_by_index(struct elf_binary *elf, int index);
++const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note); /* may return NULL */
++elf_ptrval elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
++uint64_t elf_note_numeric(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
++
++/*
++ * If you use elf_note_next in a loop, you must put a nontrivial upper
++ * bound on the returned value as part of your loop condition. In
++ * some cases elf_note_next will substitute ELF_PTRVAL_MAX as return
++ * value to indicate that the iteration isn't going well (for example,
++ * the putative "next" value would be earlier in memory). In this
++ * case the caller's loop must terminate. Checking against the
++ * end of the notes segment with a strict inequality is sufficient.
++ */
++ELF_HANDLE_DECL(elf_note) elf_note_next(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
+
+-const char *elf_note_name(struct elf_binary *elf, const elf_note * note);
+-const void *elf_note_desc(struct elf_binary *elf, const elf_note * note);
+-uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note);
+-const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note);
++/* (Only) checks that the image has the right magic number. */
++bool elf_is_elfbinary(const void *image_start, size_t image_size);
+
+-int elf_is_elfbinary(const void *image);
+-int elf_phdr_is_loadable(struct elf_binary *elf, const elf_phdr * phdr);
++bool elf_phdr_is_loadable(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr);
+
+ /* ------------------------------------------------------------------------ */
+ /* xc_libelf_loader.c */
+
+-int elf_init(struct elf_binary *elf, const char *image, size_t size);
++elf_errorstatus elf_init(struct elf_binary *elf, const char *image, size_t size);
++ /*
++ * image and size must be correct. They will be recorded in
++ * *elf, and must remain valid while the elf is in use.
++ */
+ #ifdef __XEN__
+ void elf_set_verbose(struct elf_binary *elf);
+ #else
+ void elf_set_log(struct elf_binary *elf, elf_log_callback*,
+- void *log_caller_pointer, int verbose);
++ void *log_caller_pointer, bool verbose);
+ #endif
+
+ void elf_parse_binary(struct elf_binary *elf);
+ void elf_load_binary(struct elf_binary *elf);
+
+-void *elf_get_ptr(struct elf_binary *elf, unsigned long addr);
++elf_ptrval elf_get_ptr(struct elf_binary *elf, unsigned long addr);
+ uint64_t elf_lookup_addr(struct elf_binary *elf, const char *symbol);
+
+ void elf_parse_bsdsyms(struct elf_binary *elf, uint64_t pstart); /* private */
+
++void elf_mark_broken(struct elf_binary *elf, const char *msg);
++const char *elf_check_broken(const struct elf_binary *elf); /* NULL means OK */
++
+ /* ------------------------------------------------------------------------ */
+ /* xc_libelf_relocate.c */
+
+-int elf_reloc(struct elf_binary *elf);
++elf_errorstatus elf_reloc(struct elf_binary *elf);
+
+ /* ------------------------------------------------------------------------ */
+ /* xc_libelf_dominfo.c */
+@@ -230,9 +402,9 @@ struct xen_elfnote {
+
+ struct elf_dom_parms {
+ /* raw */
+- const char *guest_info;
+- const void *elf_note_start;
+- const void *elf_note_end;
++ elf_ptrval guest_info;
++ elf_ptrval elf_note_start;
++ elf_ptrval elf_note_end;
+ struct xen_elfnote elf_notes[XEN_ELFNOTE_MAX + 1];
+
+ /* parsed */
+@@ -240,8 +412,8 @@ struct elf_dom_parms {
+ char guest_ver[16];
+ char xen_ver[16];
+ char loader[16];
+- int pae;
+- int bsd_symtab;
++ int pae; /* some kind of enum apparently */
++ bool bsd_symtab;
+ uint64_t virt_base;
+ uint64_t virt_entry;
+ uint64_t virt_hypercall;
+@@ -271,10 +443,44 @@ int elf_xen_parse_features(const char *features,
+ uint32_t *required);
+ int elf_xen_parse_note(struct elf_binary *elf,
+ struct elf_dom_parms *parms,
+- const elf_note *note);
++ ELF_HANDLE_DECL(elf_note) note);
+ int elf_xen_parse_guest_info(struct elf_binary *elf,
+ struct elf_dom_parms *parms);
+ int elf_xen_parse(struct elf_binary *elf,
+ struct elf_dom_parms *parms);
+
++static inline void *elf_memcpy_unchecked(void *dest, const void *src, size_t n)
++ { return memcpy(dest, src, n); }
++static inline void *elf_memmove_unchecked(void *dest, const void *src, size_t n)
++ { return memmove(dest, src, n); }
++static inline void *elf_memset_unchecked(void *s, int c, size_t n)
++ { return memset(s, c, n); }
++ /*
++ * Unsafe versions of memcpy, memmove memset which take actual C
++ * pointers. These are just like the real functions.
++ * We provide these so that in libelf-private.h we can #define
++ * memcpy, memset and memmove to undefined MISTAKE things.
++ */
++
++
++/* Advances past amount bytes of the current destination area. */
++static inline void ELF_ADVANCE_DEST(struct elf_binary *elf, uint64_t amount)
++{
++ if ( elf->dest_base == NULL )
++ {
++ elf_mark_broken(elf, "advancing in null image");
++ }
++ else if ( elf->dest_size >= amount )
++ {
++ elf->dest_base += amount;
++ elf->dest_size -= amount;
++ }
++ else
++ {
++ elf->dest_size = 0;
++ elf_mark_broken(elf, "advancing past end (image very short?)");
++ }
++}
++
++
+ #endif /* __XEN_LIBELF_H__ */
diff --git a/main/xen/xsa57-4.1.patch b/main/xen/xsa57-4.1.patch
new file mode 100644
index 0000000000..b9df838b72
--- /dev/null
+++ b/main/xen/xsa57-4.1.patch
@@ -0,0 +1,363 @@
+libxl: Restrict permissions on PV console device xenstore nodes
+
+Matthew Daley has observed that the PV console protocol places sensitive host
+state into a guest writeable xenstore locations, this includes:
+
+ - The pty used to communicate between the console backend daemon and its
+ client, allowing the guest administrator to read and write arbitrary host
+ files.
+ - The output file, allowing the guest administrator to write arbitrary host
+ files or to target arbitrary qemu chardevs which include sockets, udp, ptr,
+ pipes etc (see -chardev in qemu(1) for a more complete list).
+ - The maximum buffer size, allowing the guest administrator to consume more
+ resources than the host administrator has configured.
+ - The backend to use (qemu vs xenconsoled), potentially allowing the guest
+ administrator to confuse host software.
+
+So we arrange to make the sensitive keys in the xenstore frontend directory
+read only for the guest. This is safe since the xenstore permissions model,
+unlike POSIX directory permissions, does not allow the guest to remove and
+recreate a node if it has write access to the containing directory.
+
+There are a few associated wrinkles:
+
+ - The primary PV console is "special". It's xenstore node is not under the
+ usual /devices/ subtree and it does not use the customary xenstore state
+ machine protocol. Unfortunately its directory is used for other things,
+ including the vnc-port node, which we do not want the guest to be able to
+ write to. Rather than trying to track down all the possible secondary uses
+ of this directory just make it r/o to the guest. All newly created
+ subdirectories inherit these permissions and so are now safe by default.
+
+ - The other serial consoles do use the customary xenstore state machine and
+ therefore need write access to at least the "protocol" and "state" nodes,
+ however they may also want to use arbitrary "feature-foo" nodes (although
+ I'm not aware of any) and therefore we cannot simply lock down the entire
+ frontend directory. Instead we add support to libxl__device_generic_add for
+ frontend keys which are explicitly read only and use that to lock down the
+ sensitive keys.
+
+ - Minios' console frontend wants to write the "type" node, which it has no
+ business doing since this is a host/toolstack level decision. This fails
+ now that the node has become read only to the PV guest. Since the toolstack
+ already writes this node just remove the attempt to set it.
+
+This is CVE-XXXX-XXX / XSA-57
+
+Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
+
+Conflicts (4.2 backport):
+ tools/libxl/libxl.c (no vtpm, free front_ro on error in
+ libxl__device_console_add)
+
+Conflicts (4.1 backport):
+ extras/mini-os/console/xenbus.c
+ tools/libxl/libxl.c
+ tools/libxl/libxl_device.c
+ tools/libxl/libxl_internal.h
+ tools/libxl/libxl_pci.c
+ tools/libxl/libxl_xshelp.c
+
+ - minios code was in xencons_ring.c
+ - many places need &gc not just gc
+ - libxl__xs_writev path is not const
+ - varios minor context fixups
+
+diff --git a/extras/mini-os/console/xencons_ring.c b/extras/mini-os/console/xencons_ring.c
+index 9ed3756..286c650 100644
+--- a/extras/mini-os/console/xencons_ring.c
++++ b/extras/mini-os/console/xencons_ring.c
+@@ -291,12 +291,6 @@ again:
+ goto abort_transaction;
+ }
+
+- err = xenbus_printf(xbt, nodename, "type", "%s", "ioemu");
+- if (err) {
+- message = "writing type";
+- goto abort_transaction;
+- }
+-
+ snprintf(path, sizeof(path), "%s/state", nodename);
+ err = xenbus_switch_state(xbt, path, XenbusStateConnected);
+ if (err) {
+diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
+index 3c2e1b2..54f440c 100644
+--- a/tools/libxl/libxl.c
++++ b/tools/libxl/libxl.c
+@@ -1036,8 +1036,9 @@ int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *dis
+ }
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+
+ rc = 0;
+
+@@ -1266,8 +1267,9 @@ int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
+ }
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+
+ /* FIXME: wait for plug */
+ rc = 0;
+@@ -1478,8 +1480,9 @@ int libxl_device_net2_add(libxl_ctx *ctx, uint32_t domid, libxl_device_net2 *net
+ flexarray_append(front, "1");
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+
+ /* FIXME: wait for plug */
+ rc = 0;
+@@ -1571,7 +1574,7 @@ int libxl_device_net2_del(libxl_ctx *ctx, libxl_device_net2 *net2, int wait)
+ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_console *console)
+ {
+ libxl__gc gc = LIBXL_INIT_GC(ctx);
+- flexarray_t *front;
++ flexarray_t *front, *ro_front;
+ flexarray_t *back;
+ libxl__device device;
+ int rc;
+@@ -1581,6 +1584,11 @@ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_consol
+ rc = ERROR_NOMEM;
+ goto out;
+ }
++ ro_front = flexarray_make(16, 1);
++ if (!ro_front) {
++ rc = ERROR_NOMEM;
++ goto out;
++ }
+ back = flexarray_make(16, 1);
+ if (!back) {
+ rc = ERROR_NOMEM;
+@@ -1607,25 +1615,27 @@ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_consol
+
+ flexarray_append(front, "backend-id");
+ flexarray_append(front, libxl__sprintf(&gc, "%d", console->backend_domid));
+- flexarray_append(front, "limit");
+- flexarray_append(front, libxl__sprintf(&gc, "%d", LIBXL_XENCONSOLE_LIMIT));
+- flexarray_append(front, "type");
++ flexarray_append(ro_front, "limit");
++ flexarray_append(ro_front, libxl__sprintf(&gc, "%d", LIBXL_XENCONSOLE_LIMIT));
++ flexarray_append(ro_front, "type");
+ if (console->consback == LIBXL_CONSBACK_XENCONSOLED)
+- flexarray_append(front, "xenconsoled");
++ flexarray_append(ro_front, "xenconsoled");
+ else
+- flexarray_append(front, "ioemu");
+- flexarray_append(front, "output");
+- flexarray_append(front, console->output);
++ flexarray_append(ro_front, "ioemu");
++ flexarray_append(ro_front, "output");
++ flexarray_append(ro_front, console->output);
++ flexarray_append(ro_front, "tty");
++ flexarray_append(ro_front, "");
+
+ if (device.devid == 0) {
+ if (console->build_state == NULL) {
+ rc = ERROR_INVAL;
+ goto out_free;
+ }
+- flexarray_append(front, "port");
+- flexarray_append(front, libxl__sprintf(&gc, "%"PRIu32, console->build_state->console_port));
+- flexarray_append(front, "ring-ref");
+- flexarray_append(front, libxl__sprintf(&gc, "%lu", console->build_state->console_mfn));
++ flexarray_append(ro_front, "port");
++ flexarray_append(ro_front, libxl__sprintf(&gc, "%"PRIu32, console->build_state->console_port));
++ flexarray_append(ro_front, "ring-ref");
++ flexarray_append(ro_front, libxl__sprintf(&gc, "%lu", console->build_state->console_mfn));
+ } else {
+ flexarray_append(front, "state");
+ flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
+@@ -1634,11 +1644,13 @@ int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_consol
+ }
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ libxl__xs_kvs_of_flexarray(&gc, ro_front, ro_front->count));
+ rc = 0;
+ out_free:
+ flexarray_free(back);
++ flexarray_free(ro_front);
+ flexarray_free(front);
+ out:
+ libxl__free_all(&gc);
+@@ -1693,8 +1705,9 @@ int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb)
+ flexarray_append(front, libxl__sprintf(&gc, "%d", 1));
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+ rc = 0;
+ out_free:
+ flexarray_free(back);
+@@ -1921,8 +1934,9 @@ int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb)
+ flexarray_append_pair(front, "state", libxl__sprintf(&gc, "%d", 1));
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(&gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(&gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(&gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(&gc, front, front->count),
++ NULL);
+ rc = 0;
+ out_free:
+ flexarray_free(front);
+diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
+index 7e8fcef..0628840 100644
+--- a/tools/libxl/libxl_device.c
++++ b/tools/libxl/libxl_device.c
+@@ -62,12 +62,13 @@ char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device)
+ }
+
+ int libxl__device_generic_add(libxl_ctx *ctx, libxl__device *device,
+- char **bents, char **fents)
++ char **bents, char **fents, char **ro_fents)
+ {
+ libxl__gc gc = LIBXL_INIT_GC(ctx);
+ char *frontend_path, *backend_path;
+ xs_transaction_t t;
+ struct xs_permissions frontend_perms[2];
++ struct xs_permissions ro_frontend_perms[2];
+ struct xs_permissions backend_perms[2];
+ int rc;
+
+@@ -84,21 +85,36 @@ int libxl__device_generic_add(libxl_ctx *ctx, libxl__device *device,
+ frontend_perms[1].id = device->backend_domid;
+ frontend_perms[1].perms = XS_PERM_READ;
+
+- backend_perms[0].id = device->backend_domid;
+- backend_perms[0].perms = XS_PERM_NONE;
+- backend_perms[1].id = device->domid;
+- backend_perms[1].perms = XS_PERM_READ;
++ ro_frontend_perms[0].id = backend_perms[0].id = device->backend_domid;
++ ro_frontend_perms[0].perms = backend_perms[0].perms = XS_PERM_NONE;
++ ro_frontend_perms[1].id = backend_perms[1].id = device->domid;
++ ro_frontend_perms[1].perms = backend_perms[1].perms = XS_PERM_READ;
+
+ retry_transaction:
+ t = xs_transaction_start(ctx->xsh);
+ /* FIXME: read frontend_path and check state before removing stuff */
+
+- if (fents) {
++ if (fents || ro_fents) {
+ xs_rm(ctx->xsh, t, frontend_path);
+ xs_mkdir(ctx->xsh, t, frontend_path);
+- xs_set_permissions(ctx->xsh, t, frontend_path, frontend_perms, ARRAY_SIZE(frontend_perms));
++ /* Console 0 is a special case. It doesn't use the regular PV
++ * state machine but also the frontend directory has
++ * historically contained other information, such as the
++ * vnc-port, which we don't want the guest fiddling with.
++ */
++ if (device->kind == DEVICE_CONSOLE && device->devid == 0)
++ xs_set_permissions(ctx->xsh, t, frontend_path,
++ ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
++ else
++ xs_set_permissions(ctx->xsh, t, frontend_path,
++ frontend_perms, ARRAY_SIZE(frontend_perms));
+ xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/backend", frontend_path), backend_path, strlen(backend_path));
+- libxl__xs_writev(&gc, t, frontend_path, fents);
++ if (fents)
++ libxl__xs_writev_perms(&gc, t, frontend_path, fents,
++ frontend_perms, ARRAY_SIZE(frontend_perms));
++ if (ro_fents)
++ libxl__xs_writev_perms(&gc, t, frontend_path, ro_fents,
++ ro_frontend_perms, ARRAY_SIZE(ro_frontend_perms));
+ }
+
+ if (bents) {
+diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
+index 9cf503f..5ddd27b 100644
+--- a/tools/libxl/libxl_internal.h
++++ b/tools/libxl/libxl_internal.h
+@@ -143,6 +143,11 @@ _hidden char **libxl__xs_kvs_of_flexarray(libxl__gc *gc, flexarray_t *array, int
+
+ _hidden int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
+ char *dir, char **kvs);
++/* as writev but also sets the permissions on each path */
++_hidden int libxl__xs_writev_perms(libxl__gc *gc, xs_transaction_t t,
++ char *dir, char *kvs[],
++ struct xs_permissions *perms,
++ unsigned int num_perms);
+ _hidden int libxl__xs_write(libxl__gc *gc, xs_transaction_t t,
+ char *path, char *fmt, ...) PRINTF_ATTRIBUTE(4, 5);
+ /* Each fn returns 0 on success.
+@@ -185,7 +190,7 @@ _hidden int libxl__device_physdisk_major_minor(const char *physpath, int *major,
+ _hidden int libxl__device_disk_dev_number(const char *virtpath);
+
+ _hidden int libxl__device_generic_add(libxl_ctx *ctx, libxl__device *device,
+- char **bents, char **fents);
++ char **bents, char **fents, char **ro_fents);
+ _hidden char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device);
+ _hidden char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device);
+ _hidden int libxl__device_del(libxl_ctx *ctx, libxl__device *dev, int wait);
+diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c
+index b1d05d9..9c76bce 100644
+--- a/tools/libxl/libxl_pci.c
++++ b/tools/libxl/libxl_pci.c
+@@ -274,8 +274,9 @@ static int libxl_create_pci_backend(libxl__gc *gc, uint32_t domid, libxl_device_
+ flexarray_append_pair(front, "state", libxl__sprintf(gc, "%d", 1));
+
+ libxl__device_generic_add(ctx, &device,
+- libxl__xs_kvs_of_flexarray(gc, back, back->count),
+- libxl__xs_kvs_of_flexarray(gc, front, front->count));
++ libxl__xs_kvs_of_flexarray(gc, back, back->count),
++ libxl__xs_kvs_of_flexarray(gc, front, front->count),
++ NULL);
+
+ out:
+ if (back)
+diff --git a/tools/libxl/libxl_xshelp.c b/tools/libxl/libxl_xshelp.c
+index 3dc9239..06b95e0 100644
+--- a/tools/libxl/libxl_xshelp.c
++++ b/tools/libxl/libxl_xshelp.c
+@@ -48,8 +48,10 @@ char **libxl__xs_kvs_of_flexarray(libxl__gc *gc, flexarray_t *array, int length)
+ return kvs;
+ }
+
+-int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
+- char *dir, char *kvs[])
++int libxl__xs_writev_perms(libxl__gc *gc, xs_transaction_t t,
++ char *dir, char *kvs[],
++ struct xs_permissions *perms,
++ unsigned int num_perms)
+ {
+ libxl_ctx *ctx = libxl__gc_owner(gc);
+ char *path;
+@@ -63,11 +65,19 @@ int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
+ if (path && kvs[i + 1]) {
+ int length = strlen(kvs[i + 1]);
+ xs_write(ctx->xsh, t, path, kvs[i + 1], length);
++ if (perms)
++ xs_set_permissions(ctx->xsh, t, path, perms, num_perms);
+ }
+ }
+ return 0;
+ }
+
++int libxl__xs_writev(libxl__gc *gc, xs_transaction_t t,
++ char *dir, char *kvs[])
++{
++ return libxl__xs_writev_perms(gc, t, dir, kvs, NULL, 0);
++}
++
+ int libxl__xs_write(libxl__gc *gc, xs_transaction_t t,
+ char *path, char *fmt, ...)
+ {