[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v4 15/34] xsplice: Add helper elf routines



From: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>

Add Elf routines and data structures in preparation for loading an
xSplice payload.

We make an assumption that the max number of sections an ELF payload
can have is 64. We can in future make this be dependent on the
names of the sections and verifying against a list, but for right now
this suffices.

Also we a whole lot of checks to make sure that the ELF payload
file is not corrupted nor that the offsets point past the file.

For most of the checks we print an message if the hypervisor is built
with debug enabled.

Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
---
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Keir Fraser <keir@xxxxxxx>
Cc: Tim Deegan <tim@xxxxxxx>

v2: - With the #define ELFSIZE in the ARM file we can use the common
     #defines instead of using #ifdef CONFIG_ARM_32. Moved to another
    patch.
    - Add checks for ELF file.
    - Add name to be printed.
    - Add len for easier ELF checks.
    - Expand on the checks. Add macro.
v3: Remove the return_ macro
v4: Add return_ macro back but make it depend on debug=y
v5: Per Andrew review: ddd local variable. Fix memory leak in
    elf_resolve_sections, Remove macro and use dprintk. Fix alignment.
    Use void* instead of uint8_t to handle raw payload.
v6: Fix memory leak in elf_get_sym
v7: Add XSPLICE to printk/dprintk
---
 xen/common/Makefile           |   1 +
 xen/common/xsplice_elf.c      | 287 ++++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/xsplice.h     |   3 +
 xen/include/xen/xsplice_elf.h |  51 ++++++++
 4 files changed, 342 insertions(+)
 create mode 100644 xen/common/xsplice_elf.c
 create mode 100644 xen/include/xen/xsplice_elf.h

diff --git a/xen/common/Makefile b/xen/common/Makefile
index 0c8ba2c..9b7fac7 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -61,6 +61,7 @@ obj-y += wait.o
 obj-$(CONFIG_XENOPROF) += xenoprof.o
 obj-y += xmalloc_tlsf.o
 obj-$(CONFIG_XSPLICE) += xsplice.o
+obj-$(CONFIG_XSPLICE) += xsplice_elf.o
 
 obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma unlzo 
unlz4 earlycpio,$(n).init.o)
 
diff --git a/xen/common/xsplice_elf.c b/xen/common/xsplice_elf.c
new file mode 100644
index 0000000..ae87361
--- /dev/null
+++ b/xen/common/xsplice_elf.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2016 Citrix Systems R&D Ltd.
+ */
+
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/xsplice_elf.h>
+#include <xen/xsplice.h>
+
+struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf *elf,
+                                                const char *name)
+{
+    unsigned int i;
+
+    for ( i = 0; i < elf->hdr->e_shnum; i++ )
+    {
+        if ( !strcmp(name, elf->sec[i].name) )
+            return &elf->sec[i];
+    }
+
+    return NULL;
+}
+
+static int elf_resolve_sections(struct xsplice_elf *elf, const void *data)
+{
+    struct xsplice_elf_sec *sec;
+    unsigned int i;
+
+    /* xsplice_elf_load sanity checked e_shnum checked. */
+    sec = xmalloc_array(struct xsplice_elf_sec, elf->hdr->e_shnum);
+    if ( !sec )
+    {
+        printk(XENLOG_ERR "%s%s: Could not allocate memory for section 
table!\n",
+               XSPLICE, elf->name);
+        return -ENOMEM;
+    }
+
+    elf->sec = sec;
+
+    /* N.B. We also will ingest SHN_UNDEF sections. */
+    for ( i = 0; i < elf->hdr->e_shnum; i++ )
+    {
+        ssize_t delta = elf->hdr->e_shoff + i * elf->hdr->e_shentsize;
+
+        if ( delta + sizeof(Elf_Shdr) > elf->len )
+        {
+            dprintk(XENLOG_DEBUG, "%s%s: Section header [%d] is past end of 
payload!\n",
+                    XSPLICE, elf->name, i);
+            return -EINVAL;
+        }
+        sec[i].sec = (Elf_Shdr *)(data + delta);
+        delta = sec[i].sec->sh_offset;
+
+        if ( delta > elf->len )
+        {
+            dprintk(XENLOG_DEBUG, "%s%s: Section [%d] data is past end of 
payload!\n",
+                    XSPLICE, elf->name, i);
+            return -EINVAL;
+        }
+        sec[i].data = data + delta;
+
+        /* Name is populated in xsplice_elf_sections_name. */
+        sec[i].name = NULL;
+
+        if ( sec[i].sec->sh_type == SHT_SYMTAB )
+        {
+            if ( elf->symtab )
+            {
+                dprintk(XENLOG_DEBUG, "%s%s: Multiple symbol tables!\n",
+                        XSPLICE, elf->name);
+                return -EINVAL;
+            }
+            elf->symtab = &sec[i];
+
+            /*
+             * elf->symtab->sec->sh_link would point to the right section
+             * but we hadn't finished parsing all the sections.
+             */
+            if ( elf->symtab->sec->sh_link > elf->hdr->e_shnum )
+            {
+                dprintk(XENLOG_DEBUG, "%s%s: Symbol table idx (%d) to strtab 
past end (%d)\n",
+                        XSPLICE, elf->name, elf->symtab->sec->sh_link,
+                        elf->hdr->e_shnum);
+                return -EINVAL;
+            }
+        }
+    }
+
+    if ( !elf->symtab )
+    {
+        dprintk(XENLOG_DEBUG, "%s%s: No symbol table found!\n",
+                XSPLICE, elf->name);
+        return -EINVAL;
+    }
+
+    /* There can be multiple SHT_STRTAB so pick the right one. */
+    elf->strtab = &sec[elf->symtab->sec->sh_link];
+
+    if ( !elf->symtab->sec->sh_size || !elf->symtab->sec->sh_entsize ||
+         elf->symtab->sec->sh_entsize != sizeof(Elf_Sym) )
+    {
+        dprintk(XENLOG_DEBUG, "%s%s: Symbol table header is corrupted!\n",
+                XSPLICE, elf->name);
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int elf_resolve_section_names(struct xsplice_elf *elf, const void *data)
+{
+    const char *shstrtab;
+    unsigned int i;
+    unsigned int offset, delta;
+
+    /*
+     * The elf->sec[0 -> e_shnum] structures have been verified by
+     * elf_resolve_sections. Find file offset for section string table.
+     */
+    offset =  elf->sec[elf->hdr->e_shstrndx].sec->sh_offset;
+
+    if ( offset > elf->len )
+    {
+        dprintk(XENLOG_DEBUG, "%s%s: shstrtab section offset (%u) past end of 
payload!\n",
+                XSPLICE, elf->name, elf->hdr->e_shstrndx);
+        return -EINVAL;
+    }
+    shstrtab = (data + offset);
+
+    /* We could ignore the first as it is reserved.. */
+    for ( i = 0; i < elf->hdr->e_shnum; i++ )
+    {
+        delta = elf->sec[i].sec->sh_name;
+
+        if ( offset + delta > elf->len )
+        {
+            dprintk(XENLOG_DEBUG, "%s%s: shstrtab [%d] data is past end of 
payload!\n",
+                    XSPLICE, elf->name, i);
+            return -EINVAL;
+        }
+        elf->sec[i].name = shstrtab + delta;
+    }
+    return 0;
+}
+
+static int elf_get_sym(struct xsplice_elf *elf, const void *data)
+{
+    struct xsplice_elf_sec *symtab_sec, *strtab_sec;
+    struct xsplice_elf_sym *sym;
+    unsigned int i, delta, offset, nsym;
+
+    symtab_sec = elf->symtab;
+
+    strtab_sec = elf->strtab;
+
+    /* Pointers arithmetic to get file offset. */
+    offset = strtab_sec->data - data;
+
+    ASSERT( offset == strtab_sec->sec->sh_offset );
+
+    /* symtab_sec->data was computed in elf_resolve_sections. */
+    ASSERT((symtab_sec->sec->sh_offset + data) == symtab_sec->data );
+
+    /* No need to check values as elf_resolve_sections did it. */
+    nsym = symtab_sec->sec->sh_size / symtab_sec->sec->sh_entsize;
+
+    sym = xmalloc_array(struct xsplice_elf_sym, nsym);
+    if ( !sym )
+    {
+        printk(XENLOG_ERR "%s%s: Could not allocate memory for symbols\n",
+               XSPLICE, elf->name);
+        return -ENOMEM;
+    }
+
+    /* So we don't leak memory. */
+    elf->sym = sym;
+    for ( i = 0; i < nsym; i++ )
+    {
+        Elf_Sym *s;
+
+        if ( i * sizeof(Elf_Sym) > elf->len )
+        {
+            dprintk(XENLOG_DEBUG, "%s%s: Symbol header [%d] is past end of 
payload!\n",
+                    XSPLICE, elf->name, i);
+            return -EINVAL;
+        }
+        s = &((Elf_Sym *)symtab_sec->data)[i];
+
+        /* If st->name is STN_UNDEF is zero, the check will always be true. */
+        delta = s->st_name;
+
+        /* Offset has been computed earlier. */
+        if ( offset + delta > elf->len )
+        {
+            dprintk(XENLOG_DEBUG, "%s%s: Symbol [%u] data is past end of 
payload!\n",
+                    XSPLICE, elf->name, i);
+            return -EINVAL;
+        }
+        sym[i].sym = s;
+        if ( s->st_name == STN_UNDEF )
+            sym[i].name = NULL;
+        else
+            sym[i].name = data + ( delta + offset );
+    }
+    elf->nsym = nsym;
+
+    return 0;
+}
+
+static int xsplice_header_check(const struct xsplice_elf *elf)
+{
+    if ( sizeof(*elf->hdr) >= elf->len )
+    {
+        dprintk(XENLOG_DEBUG, "%s%s: Section header is bigger than payload!\n",
+                XSPLICE, elf->name);
+        return -EINVAL;
+    }
+
+    if ( elf->hdr->e_shstrndx == SHN_UNDEF )
+    {
+        dprintk(XENLOG_DEBUG, "%s%s: Section name idx is undefined!?\n",
+                XSPLICE, elf->name);
+        return -EINVAL;
+    }
+
+    /* Check that section name index is within the sections. */
+    if ( elf->hdr->e_shstrndx > elf->hdr->e_shnum )
+    {
+        dprintk(XENLOG_DEBUG, "%s%s: Section name idx (%d) is past end of  
sections (%d)!\n",
+                XSPLICE, elf->name, elf->hdr->e_shstrndx, elf->hdr->e_shnum);
+        return -EINVAL;
+    }
+
+    if ( elf->hdr->e_shnum > 64 )
+    {
+        dprintk(XENLOG_DEBUG, "%s%s: Too many (%d) sections!\n",
+                XSPLICE, elf->name, elf->hdr->e_shnum);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+int xsplice_elf_load(struct xsplice_elf *elf, void *data)
+{
+    int rc;
+
+    elf->hdr = data;
+
+    rc = xsplice_header_check(elf);
+    if ( rc )
+        return rc;
+
+    rc = elf_resolve_sections(elf, data);
+    if ( rc )
+        return rc;
+
+    rc = elf_resolve_section_names(elf, data);
+    if ( rc )
+        return rc;
+
+    rc = elf_get_sym(elf, data);
+    if ( rc )
+        return rc;
+
+    return 0;
+}
+
+void xsplice_elf_free(struct xsplice_elf *elf)
+{
+    xfree(elf->sec);
+    elf->sec = NULL;
+    xfree(elf->sym);
+    elf->sym = NULL;
+    elf->nsym = 0;
+    elf->name = NULL;
+    elf->len = 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h
index b9f08cd..cd805a8 100644
--- a/xen/include/xen/xsplice.h
+++ b/xen/include/xen/xsplice.h
@@ -10,6 +10,9 @@ struct xen_sysctl_xsplice_op;
 
 #ifdef CONFIG_XSPLICE
 
+/* Convenience define for printk. */
+#define XSPLICE "xsplice: "
+
 int xsplice_op(struct xen_sysctl_xsplice_op *);
 
 #else
diff --git a/xen/include/xen/xsplice_elf.h b/xen/include/xen/xsplice_elf.h
new file mode 100644
index 0000000..e2dea18
--- /dev/null
+++ b/xen/include/xen/xsplice_elf.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Citrix Systems R&D Ltd.
+ */
+
+#ifndef __XEN_XSPLICE_ELF_H__
+#define __XEN_XSPLICE_ELF_H__
+
+#include <xen/types.h>
+#include <xen/elfstructs.h>
+
+/* The following describes an Elf file as consumed by xSplice. */
+struct xsplice_elf_sec {
+    Elf_Shdr *sec;                 /* Hooked up in elf_resolve_sections. */
+    const char *name;              /* Human readable name hooked in
+                                      elf_resolve_section_names. */
+    const void *data;              /* Pointer to the section (done by
+                                      elf_resolve_sections). */
+};
+
+struct xsplice_elf_sym {
+    Elf_Sym *sym;
+    const char *name;
+};
+
+struct xsplice_elf {
+    const char *name;              /* Pointer to payload->name. */
+    ssize_t len;                   /* Length of the ELF file. */
+    Elf_Ehdr *hdr;                 /* ELF file. */
+    struct xsplice_elf_sec *sec;   /* Array of sections, allocated by us. */
+    struct xsplice_elf_sym *sym;   /* Array of symbols , allocated by us. */
+    unsigned int nsym;
+    struct xsplice_elf_sec *symtab;/* Pointer to .symtab section - aka to 
sec[x]. */
+    struct xsplice_elf_sec *strtab;/* Pointer to .strtab section - aka to 
sec[y]. */
+};
+
+struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf *elf,
+                                                const char *name);
+int xsplice_elf_load(struct xsplice_elf *elf, void *data);
+void xsplice_elf_free(struct xsplice_elf *elf);
+
+#endif /* __XEN_XSPLICE_ELF_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.5.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.