@@ -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;
}
@@ -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;
@@ -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;
@@ -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;
@@ -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 */
@@ -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;
}
@@ -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); }
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@gmail.com> --- 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(-)