[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH 2/3] libelf: Use flags to check pv or pvh in elf_xen_parse
Certain checks are only applicable to PV vs. PVH, so split them and run only the appropriate checks for each. This fixes loading a PVH kernel that has a PHYS32_ENTRY but not an ENTRY ELF note. Such a kernel would fail the virt_entry check which is not applicable for PVH. This re-instatates loader and xen version checks for the PV case that were omited for kernels passing the PHYS32_ENTRY check. Signed-off-by: Jason Andryuk <jandryuk@xxxxxxxxx> --- tools/fuzz/libelf/libelf-fuzzer.c | 2 +- tools/libs/guest/xg_dom_elfloader.c | 11 +++- tools/libs/guest/xg_dom_hvmloader.c | 2 +- xen/arch/x86/hvm/dom0_build.c | 2 +- xen/arch/x86/pv/dom0_build.c | 2 +- xen/common/libelf/libelf-dominfo.c | 91 +++++++++++++++++++++++------ xen/include/xen/libelf.h | 7 ++- 7 files changed, 93 insertions(+), 24 deletions(-) diff --git a/tools/fuzz/libelf/libelf-fuzzer.c b/tools/fuzz/libelf/libelf-fuzzer.c index 1ba8571711..f488510618 100644 --- a/tools/fuzz/libelf/libelf-fuzzer.c +++ b/tools/fuzz/libelf/libelf-fuzzer.c @@ -17,7 +17,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) return -1; elf_parse_binary(elf); - elf_xen_parse(elf, &parms); + elf_xen_parse(elf, &parms, ELF_XEN_CHECK_PV | ELF_XEN_CHECK_PVH); return 0; } diff --git a/tools/libs/guest/xg_dom_elfloader.c b/tools/libs/guest/xg_dom_elfloader.c index 06e713fe11..c3280b1603 100644 --- a/tools/libs/guest/xg_dom_elfloader.c +++ b/tools/libs/guest/xg_dom_elfloader.c @@ -120,6 +120,7 @@ static elf_negerrnoval check_elf_kernel(struct xc_dom_image *dom, bool verbose) static elf_negerrnoval xc_dom_probe_elf_kernel(struct xc_dom_image *dom) { struct elf_binary elf; + unsigned int flags; int rc; rc = check_elf_kernel(dom, 0); @@ -135,7 +136,9 @@ static elf_negerrnoval xc_dom_probe_elf_kernel(struct xc_dom_image *dom) * or else we might be trying to load a plain ELF. */ elf_parse_binary(&elf); - rc = elf_xen_parse(&elf, dom->parms); + flags = dom->container_type == XC_DOM_PV_CONTAINER ? ELF_XEN_CHECK_PV : + ELF_XEN_CHECK_PVH; + rc = elf_xen_parse(&elf, dom->parms, flags); if ( rc != 0 ) return rc; @@ -146,6 +149,7 @@ static elf_negerrnoval xc_dom_parse_elf_kernel(struct xc_dom_image *dom) { struct elf_binary *elf; elf_negerrnoval rc; + unsigned int flags; rc = check_elf_kernel(dom, 1); if ( rc != 0 ) @@ -166,7 +170,10 @@ static elf_negerrnoval xc_dom_parse_elf_kernel(struct xc_dom_image *dom) /* parse binary and get xen meta info */ elf_parse_binary(elf); - if ( elf_xen_parse(elf, dom->parms) != 0 ) + flags = dom->container_type == XC_DOM_PV_CONTAINER ? ELF_XEN_CHECK_PV : + ELF_XEN_CHECK_PVH; + rc = elf_xen_parse(elf, dom->parms, flags); + if ( rc != 0 ) { rc = -EINVAL; goto out; diff --git a/tools/libs/guest/xg_dom_hvmloader.c b/tools/libs/guest/xg_dom_hvmloader.c index ec6ebad7fd..bf28690415 100644 --- a/tools/libs/guest/xg_dom_hvmloader.c +++ b/tools/libs/guest/xg_dom_hvmloader.c @@ -73,7 +73,7 @@ static elf_negerrnoval xc_dom_probe_hvm_kernel(struct xc_dom_image *dom) * else we might be trying to load a PV kernel. */ elf_parse_binary(&elf); - rc = elf_xen_parse(&elf, dom->parms); + rc = elf_xen_parse(&elf, dom->parms, ELF_XEN_CHECK_PV | ELF_XEN_CHECK_PVH); if ( rc == 0 ) return -EINVAL; diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index 5b9192ecc6..552448ce5d 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -561,7 +561,7 @@ static int __init pvh_load_kernel(struct domain *d, const module_t *image, elf_set_verbose(&elf); #endif elf_parse_binary(&elf); - if ( (rc = elf_xen_parse(&elf, &parms)) != 0 ) + if ( (rc = elf_xen_parse(&elf, &parms, ELF_XEN_CHECK_PVH)) != 0 ) { printk("Unable to parse kernel for ELFNOTES\n"); return rc; diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c index e0801a9e6d..8bc77b0366 100644 --- a/xen/arch/x86/pv/dom0_build.c +++ b/xen/arch/x86/pv/dom0_build.c @@ -353,7 +353,7 @@ int __init dom0_construct_pv(struct domain *d, elf_set_verbose(&elf); elf_parse_binary(&elf); - if ( (rc = elf_xen_parse(&elf, &parms)) != 0 ) + if ( (rc = elf_xen_parse(&elf, &parms, ELF_XEN_CHECK_PV)) != 0 ) goto out; /* compatibility check */ diff --git a/xen/common/libelf/libelf-dominfo.c b/xen/common/libelf/libelf-dominfo.c index b1f36866eb..13eb39ec52 100644 --- a/xen/common/libelf/libelf-dominfo.c +++ b/xen/common/libelf/libelf-dominfo.c @@ -359,7 +359,21 @@ elf_errorstatus elf_xen_parse_guest_info(struct elf_binary *elf, /* ------------------------------------------------------------------------ */ /* sanity checks */ -static elf_errorstatus elf_xen_note_check(struct elf_binary *elf, +static elf_errorstatus elf_xen_note_check_pvh(struct elf_binary *elf, + struct elf_dom_parms *parms) +{ + /* PVH only requires one ELF note to be set */ + if (parms->phys_entry != UNSET_ADDR32 ) + { + elf_msg(elf, "ELF: Found PVH image\n"); + return 0; + } else { + elf_err(elf, "ELF: Missing PVH PHYS32_ENTRY\n"); + return -1; + } +} + +static elf_errorstatus elf_xen_note_check_pv(struct elf_binary *elf, struct elf_dom_parms *parms) { if ( (ELF_PTRVAL_INVALID(parms->elf_note_start)) && @@ -381,13 +395,6 @@ static elf_errorstatus elf_xen_note_check(struct elf_binary *elf, return 0; } - /* PVH only requires one ELF note to be set */ - if ( parms->phys_entry != UNSET_ADDR32 ) - { - elf_msg(elf, "ELF: Found PVH image\n"); - return 0; - } - /* Check the contents of the Xen notes or guest string. */ if ( ((strlen(parms->loader) == 0) || strncmp(parms->loader, "generic", 7)) && @@ -413,7 +420,36 @@ static elf_errorstatus elf_xen_note_check(struct elf_binary *elf, return 0; } -static elf_errorstatus elf_xen_addr_calc_check(struct elf_binary *elf, +static elf_errorstatus elf_xen_addr_calc_check_pvh(struct elf_binary *elf, + struct elf_dom_parms *parms) +{ + parms->phys_kstart = elf->pstart; + parms->phys_kend = elf->pend; + + if ( parms->bsd_symtab ) + { + elf_parse_bsdsyms(elf, elf->pend); + if ( elf->bsd_symtab_pend ) + parms->phys_kend = elf->bsd_symtab_pend; + } + + elf_msg(elf, "ELF: addresses:\n"); + elf_msg(elf, " phys_kstart = 0x%" PRIx64 "\n", parms->phys_kstart); + elf_msg(elf, " phys_kend = 0x%" PRIx64 "\n", parms->phys_kend); + elf_msg(elf, " phys_entry = 0x%" PRIx32 "\n", parms->phys_entry); + + if ( parms->phys_kstart > parms->phys_kend || + parms->phys_entry < parms->phys_kstart || + parms->phys_entry > parms->phys_kend ) + { + elf_err(elf, "ERROR: ELF start or entries are out of bounds\n"); + return -1; + } + + return 0; +} + +static elf_errorstatus elf_xen_addr_calc_check_pv(struct elf_binary *elf, struct elf_dom_parms *parms) { uint64_t virt_offset; @@ -453,8 +489,6 @@ static elf_errorstatus elf_xen_addr_calc_check(struct elf_binary *elf, } virt_offset = parms->virt_base - parms->elf_paddr_offset; - parms->phys_kstart = elf->pstart; - parms->phys_kend = elf->pend; parms->virt_kstart = elf->pstart + virt_offset; parms->virt_kend = elf->pend + virt_offset; @@ -466,7 +500,6 @@ static elf_errorstatus elf_xen_addr_calc_check(struct elf_binary *elf, elf_parse_bsdsyms(elf, elf->pend); if ( elf->bsd_symtab_pend ) parms->virt_kend = elf->bsd_symtab_pend + virt_offset; - parms->phys_kend = elf->bsd_symtab_pend; } elf_msg(elf, "ELF: addresses:\n"); @@ -500,9 +533,8 @@ static elf_errorstatus elf_xen_addr_calc_check(struct elf_binary *elf, /* ------------------------------------------------------------------------ */ /* glue it all together ... */ - -elf_errorstatus elf_xen_parse(struct elf_binary *elf, - struct elf_dom_parms *parms) +static elf_errorstatus elf_xen_parse_common(struct elf_binary *elf, + struct elf_dom_parms *parms) { ELF_HANDLE_DECL(elf_shdr) shdr; ELF_HANDLE_DECL(elf_phdr) phdr; @@ -597,10 +629,35 @@ elf_errorstatus elf_xen_parse(struct elf_binary *elf, } } - if ( elf_xen_note_check(elf, parms) != 0 ) + return 0; +} + +elf_errorstatus elf_xen_parse(struct elf_binary *elf, + struct elf_dom_parms *parms, + unsigned int flags) +{ + if ( !flags ) { + elf_err(elf, "Must specify ELF_XEN_CHECK_{PV,PVH} flags to check"); return -1; - if ( elf_xen_addr_calc_check(elf, parms) != 0 ) + } + + if ( elf_xen_parse_common(elf, parms) != 0 ) return -1; + + if ( flags & ELF_XEN_CHECK_PV ) { + if ( elf_xen_note_check_pv(elf, parms) != 0 ) + return -1; + if ( elf_xen_addr_calc_check_pv(elf, parms) != 0 ) + return -1; + } + + if ( flags & ELF_XEN_CHECK_PVH ) { + if ( elf_xen_note_check_pvh(elf, parms) != 0 ) + return -1; + if ( elf_xen_addr_calc_check_pvh(elf, parms) != 0 ) + return -1; + } + return 0; } diff --git a/xen/include/xen/libelf.h b/xen/include/xen/libelf.h index 8d80d0812a..858f42cf07 100644 --- a/xen/include/xen/libelf.h +++ b/xen/include/xen/libelf.h @@ -455,8 +455,13 @@ int elf_xen_parse_note(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note); int elf_xen_parse_guest_info(struct elf_binary *elf, struct elf_dom_parms *parms); + +#define ELF_XEN_CHECK_PV (1 << 0) +#define ELF_XEN_CHECK_PVH (1 << 1) + int elf_xen_parse(struct elf_binary *elf, - struct elf_dom_parms *parms); + struct elf_dom_parms *parms, + unsigned int flags); static inline void *elf_memcpy_unchecked(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } -- 2.31.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |