From f78e9dea47b7c130cb417d9826c984d8664f01ec Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Fri, 21 Jun 2013 13:31:08 +0000 Subject: main/xen: security fix (CVE-2013-2194,CVE-2013-2195,CVE-2013-2196) fixes #2115 --- main/xen/APKBUILD | 6 +- main/xen/xsa55.patch | 3431 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3436 insertions(+), 1 deletion(-) create mode 100644 main/xen/xsa55.patch diff --git a/main/xen/APKBUILD b/main/xen/APKBUILD index ce15c7091..af9ce2219 100644 --- a/main/xen/APKBUILD +++ b/main/xen/APKBUILD @@ -3,7 +3,7 @@ # Maintainer: William Pitcock pkgname=xen pkgver=4.2.2 -pkgrel=3 +pkgrel=4 pkgdesc="Xen hypervisor" url="http://www.xen.org/" arch="x86 x86_64" @@ -28,6 +28,7 @@ source="http://bits.xensource.com/oss-xen/release/$pkgver/$pkgname-$pkgver.tar.g xsa52-4.2-unstable.patch xsa53-4.2.patch xsa54.patch + xsa55.patch xsa56.patch fix-pod2man-choking.patch @@ -156,6 +157,7 @@ b3e3a57d189a4f86c9766eaf3b5207f4 xsa48-4.2.patch 83a9cdd035bcd18bf035434a1ba08c38 xsa52-4.2-unstable.patch 03a1a4ebc470ee7e638e04db2701a4f7 xsa53-4.2.patch a8393d1ec6b886ea72ffe624a04ee10a xsa54.patch +42cd104f2a33d67938a63a6372cff573 xsa55.patch e70b9128ffc2175cea314a533a7d8457 xsa56.patch c1d1a415415b0192e5dae9032962bf61 fix-pod2man-choking.patch 95d8af17bf844d41a015ff32aae51ba1 xenstored.initd @@ -181,6 +183,7 @@ dc23077028584e71a08dd0dc9e81552c76744a5ce9d39df5958a95ae9cf3107b xsa48-4.2.patc 5b8582185bf90386729e81db1f7780c69a891b074a87d9a619a90d6f639bea13 xsa52-4.2-unstable.patch 785f7612bd229f7501f4e98e4760f307d90c64305ee14707d262b77f05fa683d xsa53-4.2.patch 5d94946b3c9cba52aae2bffd4b0ebb11d09181650b5322a3c85170674a05f6b7 xsa54.patch +ac3ebaf3ec37e28ba08e23d63626d7aaccf0a3f282dd0af9c24cc4df3fd8fae0 xsa55.patch a691c5f5332a42c0d38ddb4dc037eb902f01ba31033b64c47d02909a8de0257d xsa56.patch b4e7d43364a06b2cb04527db3e9567524bc489fef475709fd8493ebf1e62406d fix-pod2man-choking.patch 81d335946c81311c86e2f2112b773a568a5a530c0db9802b2fe559e71bb8b381 xenstored.initd @@ -206,6 +209,7 @@ bda9105793f2327e1317991762120d0668af0e964076b18c9fdbfd509984b2e88d85df95702c46b2 b64a965fab8534958e453c493211ed3a6555aafb90d18f6d56a45b41d3086a0029aee85b6b6eb93b0d861d5fdc0ef10fc32e9b4f83593b37c43922d838085dd8 xsa52-4.2-unstable.patch 9b08924e563e79d2b308c1521da520c0579b334b61ac99a5593eabdb96dbda2da898b542cc47bda6d663c68343216d9d29c04853b6d1b6ecdde964b0cbb3f7ab xsa53-4.2.patch c9010be637d4f96ef03c880e1ef28228f762c5980108380a105bd190b631a882c8dff81e9421246d88d597e72f69ad1a8c672be6ddd06936acfcacd4575a2650 xsa54.patch +b4f43095163146a29ae258575bb03bd45f5a315d3cca7434a0b88c18eb1b6e1cf17ef13b4ac428a08797271a3dbc756d3f705a990991c8d2fc96f0f272c3665a xsa55.patch 26a1c2cc92ddd4c1ab6712b0e41a0135d0e76a7fe3a14b651fb0235e352e5a24077414371acccb93058b7ce4d882b667386811170ba74570c53165837bcd983d xsa56.patch ffb1113fcec0853b690c177655c7d1136388efdebf0d7f625b80481b98eadd3e9ef461442ced53e11acf0e347800a2b0a41e18b05065b5d04bffdd8a4e127cec fix-pod2man-choking.patch 792b062e8a16a2efd3cb4662d379d1500527f2a7ca9228d7831c2bd34f3b9141df949153ea05463a7758c3e3dd9a4182492ad5505fa38e298ecf8c99db77b4ee xenstored.initd diff --git a/main/xen/xsa55.patch b/main/xen/xsa55.patch new file mode 100644 index 000000000..35fe7afd0 --- /dev/null +++ b/main/xen/xsa55.patch @@ -0,0 +1,3431 @@ +diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile +index 876c148..1a5249c 100644 +--- a/tools/libxc/Makefile ++++ b/tools/libxc/Makefile +@@ -52,8 +52,13 @@ endif + 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_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c +index 0882ce6..da435ce 100644 +--- a/tools/libxc/xc_cpuid_x86.c ++++ b/tools/libxc/xc_cpuid_x86.c +@@ -589,6 +589,8 @@ static int xc_cpuid_do_domctl( + static char *alloc_str(void) + { + char *s = malloc(33); ++ if ( s == NULL ) ++ return s; + memset(s, 0, 33); + return s; + } +@@ -600,6 +602,8 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs) + for ( i = 0; i < 4; i++ ) + { + strs[i] = alloc_str(); ++ if ( strs[i] == NULL ) ++ continue; + for ( j = 0; j < 32; j++ ) + strs[i][j] = !!((regs[i] & (1U << (31 - j)))) ? '1' : '0'; + } +@@ -680,7 +684,7 @@ int xc_cpuid_check( + const char **config, + char **config_transformed) + { +- int i, j; ++ int i, j, rc; + unsigned int regs[4]; + + memset(config_transformed, 0, 4 * sizeof(*config_transformed)); +@@ -692,6 +696,11 @@ int xc_cpuid_check( + if ( config[i] == NULL ) + continue; + config_transformed[i] = alloc_str(); ++ if ( config_transformed[i] == NULL ) ++ { ++ rc = -ENOMEM; ++ goto fail_rc; ++ } + for ( j = 0; j < 32; j++ ) + { + unsigned char val = !!((regs[i] & (1U << (31 - j)))); +@@ -708,12 +717,14 @@ int xc_cpuid_check( + return 0; + + fail: ++ rc = -EPERM; ++ fail_rc: + for ( i = 0; i < 4; i++ ) + { + free(config_transformed[i]); + config_transformed[i] = NULL; + } +- return -EPERM; ++ return rc; + } + + /* +@@ -758,6 +769,11 @@ int xc_cpuid_set( + } + + config_transformed[i] = alloc_str(); ++ if ( config_transformed[i] == NULL ) ++ { ++ rc = -ENOMEM; ++ goto fail; ++ } + + for ( j = 0; j < 32; j++ ) + { +diff --git a/tools/libxc/xc_dom.h b/tools/libxc/xc_dom.h +index 6a72aa9..d801f66 100644 +--- a/tools/libxc/xc_dom.h ++++ b/tools/libxc/xc_dom.h +@@ -140,9 +140,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; + }; +@@ -275,27 +276,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) +@@ -307,6 +331,8 @@ static inline xen_pfn_t xc_dom_p2m_host(struct xc_dom_image *dom, xen_pfn_t pfn) + { + if (dom->shadow_enabled) + return pfn; ++ if (pfn >= dom->total_pages) ++ return INVALID_MFN; + return dom->p2m_host[pfn]; + } + +@@ -315,6 +341,8 @@ static inline xen_pfn_t xc_dom_p2m_guest(struct xc_dom_image *dom, + { + if (xc_dom_feature_translated(dom)) + return pfn; ++ if (pfn >= dom->total_pages) ++ return INVALID_MFN; + return dom->p2m_host[pfn]; + } + +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..e79e38d 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); + } +@@ -478,7 +509,8 @@ int xc_dom_alloc_segment(struct xc_dom_image *dom, + seg->vstart = start; + seg->pfn = (seg->vstart - dom->parms.virt_base) / page_size; + +- if ( pages > dom->total_pages || /* double test avoids overflow probs */ ++ if ( pages > dom->total_pages || /* multiple test avoids overflow probs */ ++ seg->pfn > dom->total_pages || + pages > dom->total_pages - seg->pfn) + { + xc_dom_panic(dom->xch, XC_OUT_OF_MEMORY, +@@ -855,6 +887,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 2e69559..be58276 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_Word*)(&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,23 +342,27 @@ 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; ++ } + + if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) ) + { + xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not" + " support unprivileged (DomU) operation", __FUNCTION__); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out; + } + + /* find kernel segment */ +@@ -304,15 +376,30 @@ 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; +- int rc; ++ elf_errorstatus rc; ++ xen_pfn_t pages; ++ ++ 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->dest = xc_dom_seg_to_ptr(dom, &dom->kernel_seg); + rc = elf_load_binary(elf); + if ( rc < 0 ) + { +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 b4c0b10..f9ed6b2 100644 +--- a/tools/libxc/xc_domain_restore.c ++++ b/tools/libxc/xc_domain_restore.c +@@ -1180,6 +1180,11 @@ static int apply_batch(xc_interface *xch, uint32_t dom, struct restore_ctx *ctx, + + /* Map relevant mfns */ + pfn_err = calloc(j, sizeof(*pfn_err)); ++ if ( pfn_err == NULL ) ++ { ++ PERROR("allocation for pfn_err failed"); ++ return -1; ++ } + region_base = xc_map_foreign_bulk( + xch, dom, PROT_WRITE, region_mfn, pfn_err, j); + +@@ -1556,6 +1561,12 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, + mfn = ctx->p2m[pfn]; + buf = xc_map_foreign_range(xch, dom, PAGE_SIZE, + PROT_READ | PROT_WRITE, mfn); ++ if ( buf == NULL ) ++ { ++ ERROR("xc_map_foreign_range for generation id" ++ " buffer failed"); ++ goto out; ++ } + + generationid = *(unsigned long long *)(buf + offset); + *(unsigned long long *)(buf + offset) = generationid + 1; +@@ -1713,6 +1724,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]; +@@ -1739,6 +1755,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]; +@@ -1909,6 +1930,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<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; + +- elf->dest += elf->pstart & (PAGE_SIZE - 1); ++ ELF_ADVANCE_DEST(elf, elf->pstart & (PAGE_SIZE - 1)); + + /* Load the initial elf image. */ + rc = elf_load_binary(elf); + if ( rc < 0 ) + PERROR("Failed to load elf binary\n"); + +- 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); +@@ -401,11 +403,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 787e742..98e041c 100644 +--- a/tools/libxc/xc_linux_osdep.c ++++ b/tools/libxc/xc_linux_osdep.c +@@ -378,6 +378,8 @@ static void *linux_privcmd_map_foreign_range(xc_interface *xch, xc_osdep_handle + + num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT; + arr = calloc(num, sizeof(xen_pfn_t)); ++ if ( arr == NULL ) ++ return NULL; + + for ( i = 0; i < num; i++ ) + arr[i] = mfn + i; +@@ -402,6 +404,8 @@ static void *linux_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handle + num_per_entry = chunksize >> XC_PAGE_SHIFT; + num = num_per_entry * nentries; + arr = calloc(num, sizeof(xen_pfn_t)); ++ if ( arr == NULL ) ++ return NULL; + + for ( i = 0; i < nentries; i++ ) + for ( j = 0; j < num_per_entry; j++ ) +diff --git a/tools/libxc/xc_offline_page.c b/tools/libxc/xc_offline_page.c +index 089a361..36b9812 100644 +--- a/tools/libxc/xc_offline_page.c ++++ b/tools/libxc/xc_offline_page.c +@@ -714,6 +714,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 3e03a91..848ceed 100644 +--- a/tools/libxc/xc_private.c ++++ b/tools/libxc/xc_private.c +@@ -771,6 +771,8 @@ const char *xc_strerror(xc_interface *xch, int errcode) + errbuf = pthread_getspecific(errbuf_pkey); + if (errbuf == NULL) { + errbuf = malloc(XS_BUFSIZE); ++ if ( errbuf == NULL ) ++ return "(failed to allocate errbuf)"; + pthread_setspecific(errbuf_pkey, errbuf); + } + +diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h +index b7741ca..8952048 100644 +--- a/tools/libxc/xenctrl.h ++++ b/tools/libxc/xenctrl.h +@@ -1778,7 +1778,7 @@ int xc_cpuid_set(xc_interface *xch, + int xc_cpuid_apply_policy(xc_interface *xch, + domid_t domid); + void xc_cpuid_to_str(const unsigned int *regs, +- char **strs); ++ char **strs); /* some strs[] may be NULL if ENOMEM */ + int xc_mca_op(xc_interface *xch, struct xen_mc *mc); + #endif + +diff --git a/tools/xcutils/readnotes.c b/tools/xcutils/readnotes.c +index c926186..5fa445e 100644 +--- a/tools/xcutils/readnotes.c ++++ b/tools/xcutils/readnotes.c +@@ -61,51 +61,56 @@ struct setup_header { + } __attribute__((packed)); + + 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++; +@@ -156,7 +161,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; + } + } +@@ -166,12 +171,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; + + struct setup_header *hdr; + uint64_t payload_offset, payload_length; +@@ -257,7 +263,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; +@@ -269,8 +275,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 ) +@@ -278,13 +284,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"); + +@@ -292,8 +298,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/arm/kernel.c b/xen/arch/arm/kernel.c +index 2d56130..dec0519 100644 +--- a/xen/arch/arm/kernel.c ++++ b/xen/arch/arm/kernel.c +@@ -146,6 +146,8 @@ static int kernel_try_elf_prepare(struct kernel_info *info) + { + int rc; + ++ memset(&info->elf.elf, 0, sizeof(info->elf.elf)); ++ + info->kernel_order = get_order_from_bytes(KERNEL_FLASH_SIZE); + info->kernel_img = alloc_xenheap_pages(info->kernel_order, 0); + if ( info->kernel_img == NULL ) +@@ -160,7 +162,7 @@ static int kernel_try_elf_prepare(struct kernel_info *info) + #endif + elf_parse_binary(&info->elf.elf); + if ( (rc = elf_xen_parse(&info->elf.elf, &info->elf.parms)) != 0 ) +- return rc; ++ goto err; + + /* + * TODO: can the ELF header be used to find the physical address +@@ -169,7 +171,18 @@ static int kernel_try_elf_prepare(struct kernel_info *info) + info->entry = info->elf.parms.virt_entry; + info->load = kernel_elf_load; + ++ if ( elf_check_broken(&info->elf.elf) ) ++ printk("Xen: warning: ELF kernel broken: %s\n", ++ elf_check_broken(&info->elf.elf)); ++ + return 0; ++ ++err: ++ if ( elf_check_broken(&info->elf.elf) ) ++ printk("Xen: ELF kernel broken: %s\n", ++ elf_check_broken(&info->elf.elf)); ++ ++ return rc; + } + + int kernel_prepare(struct kernel_info *info) +diff --git a/xen/arch/x86/bzimage.c b/xen/arch/x86/bzimage.c +index 5adc223..3600dca 100644 +--- a/xen/arch/x86/bzimage.c ++++ b/xen/arch/x86/bzimage.c +@@ -220,7 +220,7 @@ unsigned long __init bzimage_headroom(char *image_start, + image_length = hdr->payload_length; + } + +- if ( elf_is_elfbinary(image_start) ) ++ if ( elf_is_elfbinary(image_start, image_length) ) + return 0; + + orig_image_len = image_length; +@@ -251,7 +251,7 @@ int __init bzimage_parse(char *image_base, char **image_start, unsigned long *im + *image_len = hdr->payload_length; + } + +- if ( elf_is_elfbinary(*image_start) ) ++ if ( elf_is_elfbinary(*image_start, *image_len) ) + return 0; + + BUG_ON(!(image_base < *image_start)); +diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c +index 469d363..0dbec96 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,14 +413,16 @@ int __init construct_dom0( + if ( !compatible ) + { + printk("Mismatch between Xen and DOM0 kernel\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out; + } + + if ( parms.elf_notes[XEN_ELFNOTE_SUPPORTED_FEATURES].type != XEN_ENT_NONE && + !test_bit(XENFEAT_dom0, parms.f_supported) ) + { + printk("Kernel does not support Dom0 operation\n"); +- return -EINVAL; ++ rc = -EINVAL; ++ goto out; + } + + #if defined(__x86_64__) +@@ -734,7 +736,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) ) +@@ -908,12 +911,13 @@ 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; + rc = elf_load_binary(&elf); + if ( rc < 0 ) + { + printk("Failed to load the kernel binary\n"); +- return rc; ++ goto out; + } + bootstrap_map(NULL); + +@@ -924,7 +928,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); +@@ -1271,9 +1276,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 18dc8e2..5bf8f76 100644 +--- a/xen/common/libelf/Makefile ++++ b/xen/common/libelf/Makefile +@@ -2,6 +2,8 @@ obj-bin-y := libelf.o + + SECTIONS := text data $(SPECIAL_DATA_SECTIONS) + ++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 523837f..412ea70 100644 +--- a/xen/common/libelf/libelf-dominfo.c ++++ b/xen/common/libelf/libelf-dominfo.c +@@ -29,22 +29,22 @@ static const char *const elf_xen_feature_names[] = { + [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb", + [XENFEAT_dom0] = "dom0" + }; +-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 ) +@@ -94,14 +94,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}, +@@ -125,7 +125,7 @@ int elf_xen_parse_note(struct elf_binary *elf, + const char *str = NULL; + uint64_t val = 0; + unsigned int i; +- 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) ) +@@ -137,7 +137,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; +@@ -213,23 +216,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; +@@ -238,48 +255,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); + +@@ -325,12 +343,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: " +@@ -368,7 +387,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) && +@@ -454,15 +473,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; +@@ -475,6 +495,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; + +@@ -485,13 +508,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; + } + + /* +@@ -504,21 +528,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; + } + + } +@@ -528,20 +556,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 ab58b8b..e2e75af 100644 +--- a/xen/common/libelf/libelf-loader.c ++++ b/xen/common/libelf/libelf-loader.c +@@ -16,27 +16,33 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#ifdef __XEN__ ++#include ++#endif ++ + #include "libelf-private.h" + + /* ------------------------------------------------------------------------ */ + +-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 +67,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 +75,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 +95,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,36 +110,39 @@ 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; + elf->verbose = verbose; + } + +-static int elf_load_image(void *dst, const void *src, uint64_t filesz, uint64_t memsz) ++static elf_errorstatus elf_load_image(struct elf_binary *elf, ++ elf_ptrval dst, elf_ptrval src, ++ uint64_t filesz, uint64_t memsz) + { +- memcpy(dst, src, filesz); +- memset(dst + filesz, 0, memsz - filesz); ++ elf_memcpy_safe(elf, dst, src, filesz); ++ elf_memset_safe(elf, dst + filesz, 0, memsz - filesz); + return 0; + } + #else +-#include + + void elf_set_verbose(struct elf_binary *elf) + { + elf->verbose = 1; + } + +-static int elf_load_image(void *dst, const void *src, uint64_t filesz, uint64_t memsz) ++static elf_errorstatus elf_load_image(struct elf_binary *elf, elf_ptrval dst, elf_ptrval src, uint64_t filesz, uint64_t memsz) + { +- int rc; ++ elf_errorstatus rc; + if ( filesz > ULONG_MAX || memsz > ULONG_MAX ) + return -1; +- rc = raw_copy_to_guest(dst, src, filesz); ++ /* We trust the dom0 kernel image completely, so we don't care ++ * about overruns etc. here. */ ++ rc = raw_copy_to_guest(ELF_UNSAFE_PTR(dst), ELF_UNSAFE_PTR(src), filesz); + if ( rc != 0 ) + return -1; +- rc = raw_clear_guest(dst + filesz, memsz - filesz); ++ rc = raw_clear_guest(ELF_UNSAFE_PTR(dst + filesz), memsz - filesz); + if ( rc != 0 ) + return -1; + return 0; +@@ -141,10 +153,10 @@ static int elf_load_image(void *dst, const void *src, uint64_t filesz, uint64_t + 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); +@@ -161,7 +173,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)); + } +@@ -172,11 +187,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; +@@ -184,18 +201,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); +@@ -204,37 +221,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); + } +- shdr = (elf_shdr *)((long)shdr + +- (long)elf_uval(elf, elf->ehdr, e_shentsize)); ++ 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; ++ } ++ 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; +@@ -243,6 +273,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); +@@ -260,16 +293,25 @@ void elf_parse_binary(struct elf_binary *elf) + __FUNCTION__, elf->pstart, elf->pend); + } + +-int elf_load_binary(struct elf_binary *elf) ++elf_errorstatus 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); +@@ -277,9 +319,23 @@ int 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); +- if ( elf_load_image(dest, elf->image + offset, filesz, memsz) != 0 ) ++ ++ /* ++ * 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)); ++ if ( elf_load_image(elf, dest, ELF_IMAGE_BASE(elf) + offset, filesz, memsz) != 0 ) + return -1; + } + +@@ -287,18 +343,18 @@ int elf_load_binary(struct elf_binary *elf) + return 0; + } + +-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 cb97908..e202249 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 void *elf_section_start(struct elf_binary *elf, const elf_shdr * shdr) ++const char *elf_strval(struct elf_binary *elf, elf_ptrval start) + { +- return elf->image + elf_uval(elf, shdr, sh_offset); ++ 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 void *elf_section_end(struct elf_binary *elf, const elf_shdr * shdr) ++const char *elf_strfmt(struct elf_binary *elf, elf_ptrval start) + { +- return elf->image ++ const char *str = elf_strval(elf, start); ++ ++ if ( str == NULL ) ++ return "(invalid)"; ++ return str; ++} ++ ++elf_ptrval elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr) ++{ ++ return ELF_IMAGE_BASE(elf) + elf_uval(elf, shdr, sh_offset); ++} ++ ++elf_ptrval elf_section_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr) ++{ ++ 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) + { +@@ -228,11 +319,11 @@ uint64_t elf_note_numeric(struct elf_binary *elf, const elf_note * note) + } + } + +-uint64_t elf_note_numeric_array(struct elf_binary *elf, const elf_note *note, ++uint64_t elf_note_numeric_array(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note, + unsigned int unitsz, unsigned int idx) + { +- 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); + + if ( descsz % unitsz || idx >= descsz / unitsz ) + return 0; +@@ -248,24 +339,34 @@ uint64_t elf_note_numeric_array(struct elf_binary *elf, const elf_note *note, + } + } + +-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 e8f6508..174f8da 100644 +--- a/xen/include/xen/libelf.h ++++ b/xen/include/xen/libelf.h +@@ -29,6 +29,11 @@ + #error define architectural endianness + #endif + ++#include ++ ++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,98 @@ + + 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. ++ */ ++ ++typedef 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. */ + ++#ifdef __XEN__ ++# define ELF_PRPTRVAL "lu" ++ /* ++ * PRIuPTR is misdefined in xen/include/xen/inttypes.h, on 32-bit, ++ * to "u", when in fact uintptr_t is an unsigned long. ++ */ ++#else ++# define ELF_PRPTRVAL PRIuPTR + #endif ++ /* printf format a la PRId... for a PTRVAL */ ++ ++#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_ptrval)(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 +174,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 +207,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,88 +240,145 @@ 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); + +-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); ++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 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); ++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 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_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 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); ++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 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); +-uint64_t elf_note_numeric_array(struct elf_binary *, const elf_note *, ++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); ++uint64_t elf_note_numeric_array(struct elf_binary *, ELF_HANDLE_DECL(elf_note), + unsigned int unitsz, unsigned int idx); +-const elf_note *elf_note_next(struct elf_binary *elf, const elf_note * note); + +-int elf_is_elfbinary(const void *image); +-int elf_phdr_is_loadable(struct elf_binary *elf, const elf_phdr * phdr); ++/* ++ * 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); ++ ++/* (Only) checks that the image has the right magic number. */ ++bool elf_is_elfbinary(const void *image_start, size_t image_size); ++ ++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); +-int elf_load_binary(struct elf_binary *elf); ++elf_errorstatus 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 */ +@@ -232,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 */ +@@ -242,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; +@@ -273,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__ */ -- cgit v1.2.3