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

[Xen-devel] [PATCH v7 09/24] xsplice: Implement payload loading



From: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>

Add support for loading xsplice payloads. This is somewhat similar to
the Linux kernel module loader, implementing the following steps:
- Verify the elf file.
- Parse the elf file.
- Allocate a region of memory mapped within a free area of
  [xen_virt_end, XEN_VIRT_END].
- Copy allocated sections into the new region. Split them in three
  regions - .text, .data, and .rodata. MUST have at least .text.
- Resolve section symbols. All other symbols must be absolute addresses.
  (Note that patch titled "xsplice,symbols: Implement symbol name resolution
   on address" implements that)
- Perform relocations.
- Secure the the regions (.text,.data,.rodata) with proper permissions.

We capitalize on the vmalloc callback API (see patch titled:
"rm/x86/vmap: Add vmalloc_xen, vfree_xen and vm_init_type") to allocate
a region of memory within the [xen_virt_end, XEN_VIRT_END] for the code.

We also use the "x86/mm: Introduce modify_xen_mappings()"
to change the virtual address page-table permissions.

Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Reviewed-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Acked-by: Julien Grall <julien.grall@xxxxxxx>

---
Cc: Stefano Stabellini <stefano.stabellini@xxxxxxxxxx>
Cc: Julien Grall <julien.grall@xxxxxxx>
Cc: Keir Fraser <keir@xxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

v2: - Change the 'xsplice_patch_func' structure layout/size.
    - Add more error checking. Fix memory leak.
    - Move elf_resolve and elf_perform relocs in elf file.
    - Print the payload address and pages in keyhandler.
v3:
    - Make it build under ARM
    - Build it without using the return_ macro.
    - Add fixes from Ross.
    - Add the _return macro back - but only use it during debug builds.
    - Remove the macro, prefix arch_ on arch specific calls.
v4:
    - Move alloc_payload to arch specific file.
    - Use void* instead of uint8_t, use const
    - Add copyrights
    - Unroll the vmap code to add ASSERT. Change while to not incur
      potential long error loop
   - Use vmalloc/vfree cb APIs
   - Secure .text pages to be RX instead of RWX.
v5:
  - Fix allocation of virtual addresses only allowing one page to be allocated.
  - Create .text, .data, and .rodata regions with different permissions.
  - Make the find_space_t not a typedef to pointer to a function.
  - Allocate memory in here.
v6: Drop parentheses on typedefs.
  - s/an xSplice/a xSplice/
  - Rebase on "vmap: Add vmalloc_cb"
  - Rebase on "vmap: Add vmalloc_type and vm_init_type"
  - s/uint8_t/void/ on load_addr
  - Set xsplice_elf on stack without using memset.
v7:
  - Changed the check on delta = elf->hdr->e_shoff + elf->hdr->e_shnum * 
elf->hdr->e_shentsize;
    The sections can be right at the back of the file (different linker!), so 
the failing conditional
    for 'if (delta >= elf->len)' is incorrect and should have been '>'.
  - Changed dprintk(XENLOG_DEBUG to XENLOG_ERR, then back to DEBUG. Converted
    some of the printk to dprintk.
  - Rebase on " arm/x86/vmap: Add vmalloc_xen, vfree_xen and vm_init_type"
  - Changed some of the printk XENLOG_ERR to XENLOG_DEBUG
  - Check the idx in the relocation to make sure it is within bounds and
    implemented.
  - Use "x86/mm: Introduce modify_xen_mappings()"
  - Introduce PRIxElfAddr
  - Check for overflow in R_X86_64_PC32
  - Return -EOPNOTSUPP if we don't support types in ELF64_R_TYPE
---
---
 xen/arch/arm/Makefile         |   1 +
 xen/arch/arm/xsplice.c        |  54 ++++++++++
 xen/arch/x86/Makefile         |   1 +
 xen/arch/x86/xsplice.c        | 188 +++++++++++++++++++++++++++++++++++
 xen/common/xsplice.c          | 226 +++++++++++++++++++++++++++++++++++++++++-
 xen/common/xsplice_elf.c      | 124 ++++++++++++++++++++++-
 xen/include/xen/elfstructs.h  |   4 +
 xen/include/xen/xsplice.h     |  29 ++++++
 xen/include/xen/xsplice_elf.h |   9 +-
 9 files changed, 631 insertions(+), 5 deletions(-)
 create mode 100644 xen/arch/arm/xsplice.c
 create mode 100644 xen/arch/x86/xsplice.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 0328b50..eae5cb3 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -40,6 +40,7 @@ obj-y += device.o
 obj-y += decode.o
 obj-y += processor.o
 obj-y += smc.o
+obj-$(CONFIG_XSPLICE) += xsplice.o
 
 #obj-bin-y += ....o
 
diff --git a/xen/arch/arm/xsplice.c b/xen/arch/arm/xsplice.c
new file mode 100644
index 0000000..4465244
--- /dev/null
+++ b/xen/arch/arm/xsplice.c
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (C) 2016 Citrix Systems R&D Ltd.
+ */
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/xsplice_elf.h>
+#include <xen/xsplice.h>
+
+int arch_xsplice_verify_elf(const struct xsplice_elf *elf)
+{
+    return -ENOSYS;
+}
+
+int arch_xsplice_perform_rel(struct xsplice_elf *elf,
+                             const struct xsplice_elf_sec *base,
+                             const struct xsplice_elf_sec *rela)
+{
+    return -ENOSYS;
+}
+
+int arch_xsplice_perform_rela(struct xsplice_elf *elf,
+                              const struct xsplice_elf_sec *base,
+                              const struct xsplice_elf_sec *rela)
+{
+    return -ENOSYS;
+}
+
+void *arch_xsplice_alloc_payload(unsigned int pages)
+{
+    return NULL;
+}
+
+int arch_xsplice_secure(void *va, unsigned int pages, enum va_type type)
+{
+    return -ENOSYS;
+}
+
+void arch_xsplice_free_payload(void *va)
+{
+}
+
+void arch_xsplice_init(void)
+{
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 729065b..8a6a7d5 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -64,6 +64,7 @@ obj-y += vm_event.o
 obj-y += xstate.o
 
 obj-$(crash_debug) += gdbstub.o
+obj-$(CONFIG_XSPLICE) += xsplice.o
 
 x86_emulate.o: x86_emulate/x86_emulate.c x86_emulate/x86_emulate.h
 
diff --git a/xen/arch/x86/xsplice.c b/xen/arch/x86/xsplice.c
new file mode 100644
index 0000000..8ee6c5c
--- /dev/null
+++ b/xen/arch/x86/xsplice.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 Citrix Systems R&D Ltd.
+ */
+
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/pfn.h>
+#include <xen/vmap.h>
+#include <xen/xsplice_elf.h>
+#include <xen/xsplice.h>
+
+int arch_xsplice_verify_elf(const struct xsplice_elf *elf)
+{
+
+    const Elf_Ehdr *hdr = elf->hdr;
+
+    if ( hdr->e_machine != EM_X86_64 )
+    {
+        dprintk(XENLOG_ERR, XSPLICE "%s: Unsupported ELF Machine type!\n",
+                elf->name);
+        return -EOPNOTSUPP;
+    }
+
+    return 0;
+}
+
+int arch_xsplice_perform_rel(struct xsplice_elf *elf,
+                             const struct xsplice_elf_sec *base,
+                             const struct xsplice_elf_sec *rela)
+{
+    dprintk(XENLOG_ERR, XSPLICE "%s: SHT_REL relocation unsupported\n",
+            elf->name);
+    return -EOPNOTSUPP;
+}
+
+int arch_xsplice_perform_rela(struct xsplice_elf *elf,
+                              const struct xsplice_elf_sec *base,
+                              const struct xsplice_elf_sec *rela)
+{
+    const Elf_RelA *r;
+    unsigned int symndx, i;
+    uint64_t val;
+    uint8_t *dest;
+
+    if ( !rela->sec->sh_entsize || !rela->sec->sh_size ||
+         rela->sec->sh_entsize != sizeof(Elf_RelA) )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Section relative header is 
corrupted!\n",
+                elf->name);
+        return -EINVAL;
+    }
+
+    for ( i = 0; i < (rela->sec->sh_size / rela->sec->sh_entsize); i++ )
+    {
+        r = rela->data + i * rela->sec->sh_entsize;
+        if ( (unsigned long)r > (unsigned long)(elf->hdr + elf->len) )
+        {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: Relative entry %u in %s is past 
end!\n",
+                    elf->name, i, rela->name);
+            return -EINVAL;
+        }
+
+        symndx = ELF64_R_SYM(r->r_info);
+        if ( symndx > elf->nsym )
+        {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: Relative symbol wants symbol@%u 
which is past end!\n",
+                    elf->name, symndx);
+            return -EINVAL;
+        }
+
+        dest = base->load_addr + r->r_offset;
+        val = r->r_addend + elf->sym[symndx].sym->st_value;
+
+        switch ( ELF64_R_TYPE(r->r_info) )
+        {
+        case R_X86_64_NONE:
+            break;
+
+        case R_X86_64_64:
+            *(uint64_t *)dest = val;
+            break;
+
+        case R_X86_64_PLT32:
+            /*
+             * Xen uses -fpic which normally uses PLT relocations
+             * except that it sets visibility to hidden which means
+             * that they are not used.  However, when gcc cannot
+             * inline memcpy it emits memcpy with default visibility
+             * which then creates a PLT relocation.  It can just be
+             * treated the same as R_X86_64_PC32.
+             */
+            /* Fall through */
+        case R_X86_64_PC32:
+            val -= (uint64_t)dest;
+            *(uint32_t *)dest = val;
+            if ( (s64)val != *(s32 *)dest )
+            {
+                printk(XENLOG_DEBUG XSPLICE "%s: Overflow in relocation %u in 
%s for %s!\n",
+                       elf->name, i, rela->name, base->name);
+                return -EOVERFLOW;
+            }
+            break;
+
+        default:
+            printk(XENLOG_DEBUG XSPLICE "%s: Unhandled relocation %lu\n",
+                   elf->name, ELF64_R_TYPE(r->r_info));
+            return -EOPNOTSUPP;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * The function prepares a xSplice payload by allocating space which
+ * then can be used for loading the allocated sections, resolving symbols,
+ * performing relocations, etc.
+ */
+void *arch_xsplice_alloc_payload(unsigned int pages)
+{
+    unsigned int i;
+    void *p;
+
+    ASSERT(pages);
+
+    p = vmalloc_xen(pages * PAGE_SIZE);
+    WARN_ON(!p);
+    if ( p )
+    {
+        /* By default they are PAGE_HYPERVISOR aka PAGE_HYPERVISOR_RWX.*/
+        for ( i = 0; i < pages; i++ )
+            clear_page(p + (i * PAGE_SIZE) );
+    }
+    return p;
+}
+
+/*
+ * Once the resolving symbols, performing relocations, etc is complete
+ * we secure the memory by putting in the proper page table attributes
+ * for the desired type.
+ */
+int arch_xsplice_secure(void *va, unsigned int pages, enum va_type type)
+{
+    unsigned long start = (unsigned long)va;
+    int flag;
+
+    ASSERT(va);
+    ASSERT(pages);
+
+    if ( type == XSPLICE_VA_RX ) /* PAGE_HYPERVISOR_RX */
+        flag = _PAGE_PRESENT;
+    else if ( type == XSPLICE_VA_RW ) /* PAGE_HYPERVISOR_RW */
+        flag = _PAGE_RW | _PAGE_NX | _PAGE_PRESENT;
+    else /* PAGE_HYPERVISOR_RO */
+        flag = _PAGE_NX | _PAGE_PRESENT;
+
+    /* The ones we are allowed to modify are: _PAGE_NX|_PAGE_RW|_PAGE_PRESENT 
*/
+    modify_xen_mappings(start, start + pages * PAGE_SIZE, flag);
+
+    return 0;
+}
+
+void arch_xsplice_free_payload(void *va)
+{
+    vfree_xen(va);
+}
+
+void arch_xsplice_init(void)
+{
+    void *start, *end;
+
+    start = (void *)xen_virt_end;
+    end = (void *)(XEN_VIRT_END - NR_CPUS * PAGE_SIZE);
+
+    BUG_ON(end <= start);
+
+    vm_init_type(VMAP_XEN, start, end);
+}
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/xsplice.c b/xen/common/xsplice.c
index 120fd5c..cbee264 100644
--- a/xen/common/xsplice.c
+++ b/xen/common/xsplice.c
@@ -13,6 +13,7 @@
 #include <xen/smp.h>
 #include <xen/spinlock.h>
 #include <xen/vmap.h>
+#include <xen/xsplice_elf.h>
 #include <xen/xsplice.h>
 
 #include <asm/event.h>
@@ -28,6 +29,13 @@ struct payload {
     uint32_t state;                      /* One of the XSPLICE_STATE_*. */
     int32_t rc;                          /* 0 or -XEN_EXX. */
     struct list_head list;               /* Linked to 'payload_list'. */
+    void *text_addr;                     /* Virtual address of .text. */
+    size_t text_size;                    /* .. and its size. */
+    void *rw_addr;                       /* Virtual address of .data. */
+    size_t rw_size;                      /* .. and its size (if any). */
+    void *ro_addr;                       /* Virtual address of .rodata. */
+    size_t ro_size;                      /* .. and its size (if any). */
+    size_t pages;                        /* Total pages for [text,rw,ro]_addr 
*/
     char name[XEN_XSPLICE_NAME_SIZE];    /* Name of it. */
 };
 
@@ -85,19 +93,215 @@ static struct payload *find_payload(const char *name)
     return found;
 }
 
+/*
+ * Functions related to XEN_SYSCTL_XSPLICE_UPLOAD (see xsplice_upload), and
+ * freeing payload (XEN_SYSCTL_XSPLICE_ACTION:XSPLICE_ACTION_UNLOAD).
+ */
+
+static void free_payload_data(struct payload *payload)
+{
+    /* Set to zero until "move_payload". */
+    if ( !payload->text_addr )
+        return;
+
+    arch_xsplice_free_payload(payload->text_addr);
+
+    payload->text_addr = NULL;
+    payload->ro_addr = NULL;
+    payload->rw_addr = NULL;
+    payload->pages = 0;
+}
+
+/*
+* calc_section computes the size (taking into account section alignment).
+*
+* It also modifies sh_entsize with the offset of from the start of
+* virtual address space. This is used in move_payload to figure out the
+* destination location.
+*/
+static void calc_section(struct xsplice_elf_sec *sec, size_t *size)
+{
+    Elf_Shdr *s = sec->sec;
+    size_t align_size;
+
+    align_size = ROUNDUP(*size, s->sh_addralign);
+    s->sh_entsize = align_size;
+
+    *size = s->sh_size + align_size;
+}
+
+static int move_payload(struct payload *payload, struct xsplice_elf *elf)
+{
+    uint8_t *buf;
+    unsigned int i;
+    size_t size = 0;
+
+    /* Compute text regions. */
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        if ( (elf->sec[i].sec->sh_flags & (SHF_ALLOC|SHF_EXECINSTR)) ==
+             (SHF_ALLOC|SHF_EXECINSTR) )
+            calc_section(&elf->sec[i], &payload->text_size);
+    }
+
+    /* Compute rw data. */
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) &&
+             !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
+             (elf->sec[i].sec->sh_flags & SHF_WRITE) )
+            calc_section(&elf->sec[i], &payload->rw_size);
+    }
+
+    /* Compute ro data. */
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) &&
+             !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
+             !(elf->sec[i].sec->sh_flags & SHF_WRITE) )
+            calc_section(&elf->sec[i], &payload->ro_size);
+    }
+
+    /* Do not accept wx. */
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        if ( !(elf->sec[i].sec->sh_flags & SHF_ALLOC) &&
+             (elf->sec[i].sec->sh_flags & SHF_EXECINSTR) &&
+             (elf->sec[i].sec->sh_flags & SHF_WRITE) )
+        {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: No WX sections!\n", elf->name);
+            return -EINVAL;
+        }
+    }
+
+    /*
+     * Total of all three regions - RX, RW, and RO. We have to have
+     * keep them in seperate pages so we PAGE_ALIGN the RX and RW to have
+     * them on seperate pages. The last one will by default fall on its
+     * own page.
+     */
+    size = PAGE_ALIGN(payload->text_size) + PAGE_ALIGN(payload->rw_size) +
+                      payload->ro_size;
+
+    size = PFN_UP(size);
+    buf = arch_xsplice_alloc_payload(size);
+    if ( !buf )
+    {
+        printk(XENLOG_ERR XSPLICE "%s: Could not allocate memory for 
payload!\n",
+               elf->name);
+        return -ENOMEM;
+    }
+    payload->pages = size;
+    payload->text_addr = buf;
+    payload->rw_addr = payload->text_addr + PAGE_ALIGN(payload->text_size);
+    payload->ro_addr = payload->rw_addr + PAGE_ALIGN(payload->rw_size);
+
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        if ( elf->sec[i].sec->sh_flags & SHF_ALLOC )
+        {
+            if ( (elf->sec[i].sec->sh_flags & SHF_EXECINSTR) )
+                 buf = payload->text_addr;
+            else if ( (elf->sec[i].sec->sh_flags & SHF_WRITE) )
+                buf = payload->rw_addr;
+             else
+                buf = payload->ro_addr;
+
+            elf->sec[i].load_addr = buf + elf->sec[i].sec->sh_entsize;
+
+            /* Don't copy NOBITS - such as BSS. */
+            if ( elf->sec[i].sec->sh_type != SHT_NOBITS )
+            {
+                memcpy(elf->sec[i].load_addr, elf->sec[i].data,
+                       elf->sec[i].sec->sh_size);
+                dprintk(XENLOG_DEBUG, XSPLICE "%s: Loaded %s at 0x%p\n",
+                        elf->name, elf->sec[i].name, elf->sec[i].load_addr);
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int secure_payload(struct payload *payload, struct xsplice_elf *elf)
+{
+    int rc;
+    unsigned int text_pages, rw_pages, ro_pages;
+
+    text_pages = PFN_UP(payload->text_size);
+    ASSERT(text_pages);
+
+    rc = arch_xsplice_secure(payload->text_addr, text_pages, XSPLICE_VA_RX);
+    if ( rc )
+        return rc;
+
+    rw_pages = PFN_UP(payload->rw_size);
+    if ( rw_pages )
+    {
+        rc = arch_xsplice_secure(payload->rw_addr, rw_pages, XSPLICE_VA_RW);
+        if ( rc )
+            return rc;
+    }
+
+    ro_pages = PFN_UP(payload->ro_size);
+    if ( ro_pages )
+    {
+        rc = arch_xsplice_secure(payload->ro_addr, ro_pages, XSPLICE_VA_RO);
+    }
+
+    ASSERT(ro_pages + rw_pages + text_pages == payload->pages);
+
+    return rc;
+}
+
 static void free_payload(struct payload *data)
 {
     ASSERT(spin_is_locked(&payload_lock));
     list_del(&data->list);
     payload_cnt--;
     payload_version++;
+    free_payload_data(data);
     xfree(data);
 }
 
+static int load_payload_data(struct payload *payload, void *raw, size_t len)
+{
+    struct xsplice_elf elf = { .name = payload->name, .len = len };
+    int rc = 0;
+
+    rc = xsplice_elf_load(&elf, raw);
+    if ( rc )
+        goto out;
+
+    rc = move_payload(payload, &elf);
+    if ( rc )
+        goto out;
+
+    rc = xsplice_elf_resolve_symbols(&elf);
+    if ( rc )
+        goto out;
+
+    rc = xsplice_elf_perform_relocs(&elf);
+    if ( rc )
+        goto out;
+
+    rc = secure_payload(payload, &elf);
+
+ out:
+    if ( rc )
+        free_payload_data(payload);
+
+    /* Free our temporary data structure. */
+    xsplice_elf_free(&elf);
+
+    return rc;
+}
+
 static int xsplice_upload(xen_sysctl_xsplice_upload_t *upload)
 {
     struct payload *data = NULL, *found;
     char n[XEN_XSPLICE_NAME_SIZE];
+    void *raw_data = NULL;
     int rc;
 
     rc = verify_payload(upload, n);
@@ -125,9 +329,20 @@ static int xsplice_upload(xen_sysctl_xsplice_upload_t 
*upload)
         goto out;
     }
 
-    rc = 0;
+    rc = -ENOMEM;
+    raw_data = vmalloc(upload->size);
+    if ( !raw_data )
+        goto out;
+
+    rc = -EFAULT;
+    if ( __copy_from_guest(raw_data, upload->payload, upload->size) )
+        goto out;
 
     memcpy(data->name, n, strlen(n));
+    rc = load_payload_data(data, raw_data, upload->size);
+    if ( rc )
+        goto out;
+
     data->state = XSPLICE_STATE_CHECKED;
     INIT_LIST_HEAD(&data->list);
 
@@ -138,6 +353,8 @@ static int xsplice_upload(xen_sysctl_xsplice_upload_t 
*upload)
  out:
     spin_unlock(&payload_lock);
 
+    vfree(raw_data);
+
     if ( rc )
         xfree(data);
 
@@ -379,8 +596,9 @@ static void xsplice_printall(unsigned char key)
     }
 
     list_for_each_entry ( data, &payload_list, list )
-        printk(" name=%s state=%s(%d)\n", data->name,
-               state2str(data->state), data->state);
+        printk(" name=%s state=%s(%d) %p (.data=%p, .rodata=%p) using %zu 
pages.\n",
+               data->name, state2str(data->state), data->state, 
data->text_addr,
+               data->rw_addr, data->ro_addr, data->pages);
 
     spin_unlock(&payload_lock);
 }
@@ -388,6 +606,8 @@ static void xsplice_printall(unsigned char key)
 static int __init xsplice_init(void)
 {
     register_keyhandler('x', xsplice_printall, "print xsplicing info", 1);
+
+    arch_xsplice_init();
     return 0;
 }
 __initcall(xsplice_init);
diff --git a/xen/common/xsplice_elf.c b/xen/common/xsplice_elf.c
index ffa5c95..7262fc2 100644
--- a/xen/common/xsplice_elf.c
+++ b/xen/common/xsplice_elf.c
@@ -101,7 +101,7 @@ static int elf_resolve_sections(struct xsplice_elf *elf, 
const void *data)
             }
 
             elf->symtab = &sec[i];
-
+            elf->symtab_idx = i;
             /*
              * elf->symtab->sec->sh_link would point to the right section
              * but we hadn't finished parsing all the sections.
@@ -249,9 +249,127 @@ static int elf_get_sym(struct xsplice_elf *elf, const 
void *data)
     return 0;
 }
 
+int xsplice_elf_resolve_symbols(struct xsplice_elf *elf)
+{
+    unsigned int i;
+    int rc = 0;
+
+    /*
+     * The first entry of an ELF symbol table is the "undefined symbol index".
+     * aka reserved so we skip it.
+     */
+    ASSERT(elf->sym);
+
+    for ( i = 1; i < elf->nsym; i++ )
+    {
+        uint16_t idx = elf->sym[i].sym->st_shndx;
+
+        rc = 0;
+        switch ( idx )
+        {
+        case SHN_COMMON:
+            printk(XENLOG_DEBUG XSPLICE "%s: Unexpected common symbol: %s\n",
+                   elf->name, elf->sym[i].name);
+            rc = -EINVAL;
+            break;
+
+        case SHN_UNDEF:
+            printk(XENLOG_DEBUG XSPLICE "%s: Unknown symbol: %s\n",
+                   elf->name, elf->sym[i].name);
+            rc = -ENOENT;
+            break;
+
+        case SHN_ABS:
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: Absolute symbol: %s => 
%#"PRIxElfAddr"\n",
+                    elf->name, elf->sym[i].name, elf->sym[i].sym->st_value);
+            break;
+
+        default:
+            /* SHN_COMMON and SHN_ABS are above. */
+            if ( idx > SHN_LORESERVE )
+                rc = -EOPNOTSUPP;
+            /* SHN_UNDEF (0) above. */
+            else if ( idx > elf->hdr->e_shnum && idx < SHN_LORESERVE )
+                rc = -EINVAL;
+
+            if ( rc )
+            {
+                dprintk(XENLOG_DEBUG, XSPLICE "%s: Unknown type=%#"PRIx16"\n",
+                        elf->name, idx);
+                break;
+            }
+
+            if ( !(elf->sec[idx].sec->sh_flags & SHF_ALLOC) )
+                break;
+
+            elf->sym[i].sym->st_value += (unsigned 
long)elf->sec[idx].load_addr;
+            if ( elf->sym[i].name )
+                printk(XENLOG_DEBUG XSPLICE "%s: Symbol resolved: %s => 
%#"PRIxElfAddr"(%s)\n",
+                       elf->name, elf->sym[i].name,
+                       elf->sym[i].sym->st_value, elf->sec[idx].name);
+        }
+
+        if ( rc )
+            break;
+    }
+
+    return rc;
+}
+
+int xsplice_elf_perform_relocs(struct xsplice_elf *elf)
+{
+    struct xsplice_elf_sec *rela, *base;
+    unsigned int i;
+    int rc = 0;
+
+    /*
+     * The first entry of an ELF symbol table is the "undefined symbol index".
+     * aka reserved so we skip it.
+     */
+    ASSERT(elf->sym);
+
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        rela = &elf->sec[i];
+
+        if ( (rela->sec->sh_type != SHT_RELA) &&
+             (rela->sec->sh_type != SHT_REL) )
+            continue;
+
+         /* Is it a valid relocation section? */
+         if ( rela->sec->sh_info >= elf->hdr->e_shnum )
+            continue;
+
+         base = &elf->sec[rela->sec->sh_info];
+
+         /* Don't relocate non-allocated sections. */
+         if ( !(base->sec->sh_flags & SHF_ALLOC) )
+            continue;
+
+        if ( rela->sec->sh_link != elf->symtab_idx )
+        {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: Relative link of %s is 
incorrect (%d, expected=%d)\n",
+                    elf->name, rela->name, rela->sec->sh_link, 
elf->symtab_idx);
+            rc = -EINVAL;
+            break;
+        }
+
+        if ( rela->sec->sh_type == SHT_RELA )
+            rc = arch_xsplice_perform_rela(elf, base, rela);
+        else /* SHT_REL */
+            rc = arch_xsplice_perform_rel(elf, base, rela);
+
+        if ( rc )
+            break;
+    }
+
+    return rc;
+}
+
 static int xsplice_header_check(const struct xsplice_elf *elf)
 {
     const Elf_Ehdr *hdr = elf->hdr;
+    int rc;
 
     if ( sizeof(*elf->hdr) > elf->len )
     {
@@ -276,6 +394,10 @@ static int xsplice_header_check(const struct xsplice_elf 
*elf)
         return -EOPNOTSUPP;
     }
 
+    rc = arch_xsplice_verify_elf(elf);
+    if ( rc )
+        return rc;
+
     if ( elf->hdr->e_shstrndx == SHN_UNDEF )
     {
         dprintk(XENLOG_DEBUG, XSPLICE "%s: Section name idx is undefined!?\n",
diff --git a/xen/include/xen/elfstructs.h b/xen/include/xen/elfstructs.h
index 85f35ed..be55985 100644
--- a/xen/include/xen/elfstructs.h
+++ b/xen/include/xen/elfstructs.h
@@ -472,6 +472,8 @@ typedef struct {
 #endif
 
 #if defined(ELFSIZE) && (ELFSIZE == 32)
+#define PRIxElfAddr    "08x"
+
 #define Elf_Ehdr       Elf32_Ehdr
 #define Elf_Phdr       Elf32_Phdr
 #define Elf_Shdr       Elf32_Shdr
@@ -497,6 +499,8 @@ typedef struct {
 
 #define AuxInfo                Aux32Info
 #elif defined(ELFSIZE) && (ELFSIZE == 64)
+#define PRIxElfAddr    "lx"
+
 #define Elf_Ehdr       Elf64_Ehdr
 #define Elf_Phdr       Elf64_Phdr
 #define Elf_Shdr       Elf64_Shdr
diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h
index cd805a8..83e4f31 100644
--- a/xen/include/xen/xsplice.h
+++ b/xen/include/xen/xsplice.h
@@ -6,6 +6,9 @@
 #ifndef __XEN_XSPLICE_H__
 #define __XEN_XSPLICE_H__
 
+struct xsplice_elf;
+struct xsplice_elf_sec;
+struct xsplice_elf_sym;
 struct xen_sysctl_xsplice_op;
 
 #ifdef CONFIG_XSPLICE
@@ -15,6 +18,32 @@ struct xen_sysctl_xsplice_op;
 
 int xsplice_op(struct xen_sysctl_xsplice_op *);
 
+/* Arch hooks. */
+int arch_xsplice_verify_elf(const struct xsplice_elf *elf);
+int arch_xsplice_perform_rel(struct xsplice_elf *elf,
+                             const struct xsplice_elf_sec *base,
+                             const struct xsplice_elf_sec *rela);
+int arch_xsplice_perform_rela(struct xsplice_elf *elf,
+                              const struct xsplice_elf_sec *base,
+                              const struct xsplice_elf_sec *rela);
+enum va_type {
+    XSPLICE_VA_RX, /* .text */
+    XSPLICE_VA_RW, /* .data */
+    XSPLICE_VA_RO, /* .rodata */
+};
+
+#include <xen/mm.h>
+void *arch_xsplice_alloc_payload(unsigned int pages);
+
+/*
+ * Function to secure the allocate pages (from arch_xsplice_alloc_payload)
+ * with the right page permissions.
+ */
+int arch_xsplice_secure(void *va, unsigned int pages, enum va_type types);
+
+void arch_xsplice_free_payload(void *va);
+
+void arch_xsplice_init(void);
 #else
 
 #include <xen/errno.h> /* For -ENOSYS */
diff --git a/xen/include/xen/xsplice_elf.h b/xen/include/xen/xsplice_elf.h
index 89acb77..6892f59 100644
--- a/xen/include/xen/xsplice_elf.h
+++ b/xen/include/xen/xsplice_elf.h
@@ -15,6 +15,8 @@ struct xsplice_elf_sec {
                                             elf_resolve_section_names. */
     const void *data;                    /* Pointer to the section (done by
                                             elf_resolve_sections). */
+    void *load_addr;                     /* A pointer to the allocated 
destination.
+                                            Done by load_payload_data. */
 };
 
 struct xsplice_elf_sym {
@@ -29,8 +31,10 @@ struct xsplice_elf {
     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;
-    const struct xsplice_elf_sec *symtab;/* Pointer to .symtab section - aka 
to sec[x]. */
+    const struct xsplice_elf_sec *symtab;/* Pointer to .symtab section - aka to
+                                            sec[symtab_idx]. */
     const struct xsplice_elf_sec *strtab;/* Pointer to .strtab section - aka 
to sec[y]. */
+    unsigned int symtab_idx;
 };
 
 const struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf 
*elf,
@@ -38,6 +42,9 @@ const struct xsplice_elf_sec *xsplice_elf_sec_by_name(const 
struct xsplice_elf *
 int xsplice_elf_load(struct xsplice_elf *elf, const void *data);
 void xsplice_elf_free(struct xsplice_elf *elf);
 
+int xsplice_elf_resolve_symbols(struct xsplice_elf *elf);
+int xsplice_elf_perform_relocs(struct xsplice_elf *elf);
+
 #endif /* __XEN_XSPLICE_ELF_H__ */
 
 /*
-- 
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®.