All of lore.kernel.org
 help / color / mirror / Atom feed
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
To: konrad@kernel.org, xen-devel@lists.xenproject.org,
	sasha.levin@oracle.com, andrew.cooper3@citrix.com,
	ross.lagerwall@citrix.com, mpohlack@amazon.de
Cc: Julien Grall <julien.grall@arm.com>,
	Stefano Stabellini <sstabellini@kernel.org>,
	Keir Fraser <keir@xen.org>, Jan Beulich <jbeulich@suse.com>,
	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Subject: [PATCH v8 09/25] xsplice: Implement payload loading
Date: Wed, 13 Apr 2016 17:09:40 -0400	[thread overview]
Message-ID: <1460581796-30071-10-git-send-email-konrad.wilk@oracle.com> (raw)
In-Reply-To: <1460581796-30071-1-git-send-email-konrad.wilk@oracle.com>

From: Ross Lagerwall <ross.lagerwall@citrix.com>

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@citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Julien Grall <julien.grall@arm.com>

---
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Julien Grall <julien.grall@arm.com>
Cc: Keir Fraser <keir@xen.org>
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>

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
v8:
  - Change dprintk and printk XENLOG_DEBUG to XENLOG_ERR
  - Convert four of the printks in dprintk.
---
---
 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..3000ecb
--- /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_ERR, 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_ERR, 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_ERR, 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 )
+            {
+                dprintk(XENLOG_ERR, XSPLICE "%s: Overflow in relocation %u in %s for %s!\n",
+                        elf->name, i, rela->name, base->name);
+                return -EOVERFLOW;
+            }
+            break;
+
+        default:
+            dprintk(XENLOG_ERR, 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 04151e9..809b067 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>
@@ -29,6 +30,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. */
 };
 
@@ -86,19 +94,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_ERR, 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 )
+    {
+        dprintk(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);
@@ -126,9 +330,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);
 
@@ -139,6 +354,8 @@ static int xsplice_upload(xen_sysctl_xsplice_upload_t *upload)
  out:
     spin_unlock(&payload_lock);
 
+    vfree(raw_data);
+
     if ( rc )
         xfree(data);
 
@@ -380,8 +597,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);
 }
@@ -389,6 +607,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 0d96b78..f59f011 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:
+            dprintk(XENLOG_ERR, XSPLICE "%s: Unexpected common symbol: %s\n",
+                    elf->name, elf->sym[i].name);
+            rc = -EINVAL;
+            break;
+
+        case SHN_UNDEF:
+            dprintk(XENLOG_ERR, 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_ERR, 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 )
+                dprintk(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_ERR, 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_ERR, 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@lists.xen.org
http://lists.xen.org/xen-devel

  parent reply	other threads:[~2016-04-13 21:11 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-13 21:09 [PATCH v8] xSplice v1 design and implementation Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 01/25] xsplice: Design document Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 02/25] xen/xsplice: Hypervisor implementation of XEN_XSPLICE_op Konrad Rzeszutek Wilk
2016-04-20 13:18   ` Ross Lagerwall
2016-04-22 18:06     ` Konrad Rzeszutek Wilk
2016-04-25  9:03       ` Jan Beulich
2016-04-25  9:13         ` Ross Lagerwall
2016-04-13 21:09 ` [PATCH v8 03/25] libxc: Implementation of XEN_XSPLICE_op in libxc Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 04/25] xen-xsplice: Tool to manipulate xsplice payloads Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 05/25] arm/x86: Use struct virtual_region to do bug, symbol, and (x86) exception tables lookup Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 06/25] arm/x86/vmap: Add vmalloc_xen, vfree_xen and vm_init_type Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 07/25] x86/mm: Introduce modify_xen_mappings() Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 08/25] xsplice: Add helper elf routines Konrad Rzeszutek Wilk
2016-04-13 21:09 ` Konrad Rzeszutek Wilk [this message]
2016-04-13 21:09 ` [PATCH v8 10/25] xsplice: Implement support for applying/reverting/replacing patches Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 11/25] x86/xen_hello_world.xsplice: Test payload for patching 'xen_extra_version' Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 12/25] xsplice, symbols: Implement symbol name resolution on address Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 13/25] xsplice, symbols: Implement fast symbol names -> virtual addresses lookup Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 14/25] x86, xsplice: Print payload's symbol name and payload name in backtraces Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 15/25] xsplice: Add support for bug frames Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 16/25] xsplice: Add support for exception tables Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 17/25] xsplice: Add support for alternatives Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 18/25] build_id: Provide ld-embedded build-ids Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 19/25] HYPERCALL_version_op: Add VERSION_build_id to retrieve build-id Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 20/25] libxl: info: Display build_id of the hypervisor using XEN_VERSION_build_id Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 21/25] xsplice: Print build_id in keyhandler and on bootup Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 22/25] xsplice: Stacking build-id dependency checking Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 23/25] xsplice/xen_replace_world: Test-case for XSPLICE_ACTION_REPLACE Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 24/25] xsplice: Prevent duplicate payloads from being loaded Konrad Rzeszutek Wilk
2016-04-13 21:09 ` [PATCH v8 25/25] MAINTAINERS/xsplice: Add myself and Ross as the maintainers Konrad Rzeszutek Wilk
2016-04-13 21:57 ` [PATCH v8] xSplice v1 design and implementation Konrad Rzeszutek Wilk
2016-04-13 22:01   ` Konrad Rzeszutek Wilk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1460581796-30071-10-git-send-email-konrad.wilk@oracle.com \
    --to=konrad.wilk@oracle.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=julien.grall@arm.com \
    --cc=keir@xen.org \
    --cc=konrad@kernel.org \
    --cc=mpohlack@amazon.de \
    --cc=ross.lagerwall@citrix.com \
    --cc=sasha.levin@oracle.com \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.