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

Re: [Xen-devel] [PATCH v1 07/11] xsplice: Implement payload loading



On Thu, Nov 05, 2015 at 11:15:34AM +0000, Ross Lagerwall wrote:
> On 11/04/2015 10:21 PM, Konrad Rzeszutek Wilk wrote:
> snip
> >>
> >>+
> >>+/*
> >>+ * The following functions prepare an xSplice module to be executed by
> >>+ * allocating space, loading the allocated sections, resolving symbols,
> >>+ * performing relocations, etc.
> >>+ */
> >>+#ifdef CONFIG_X86
> >>+static void *alloc_module(size_t size)
> >
> >s/module/payload/
> 
> My intention was that all the code which implements the "module loader"
> functionality (and is sort of independent from xSplice) uses the term
> "module" whereas the payload implies the loaded module + the other
> xSplice-specific bits. Your thoughts?

Aaah. I had module == payload in mind. 

> 
> >>+{
> >>+    mfn_t *mfn, *mfn_ptr;
> >>+    size_t pages, i;
> >>+    struct page_info *pg;
> >>+    unsigned long hole_start, hole_end, cur;
> >>+    struct payload *data, *data2;
> >>+
> >>+    ASSERT(size);
> >>+
> >>+    pages = PFN_UP(size);
> >>+    mfn = xmalloc_array(mfn_t, pages);
> >>+    if ( mfn == NULL )
> >>+        return NULL;
> >>+
> >>+    for ( i = 0; i < pages; i++ )
> >>+    {
> >>+        pg = alloc_domheap_page(NULL, 0);
> >>+        if ( pg == NULL )
> >>+            goto error;
> >>+        mfn[i] = _mfn(page_to_mfn(pg));
> >>+    }
> >
> >This looks like 'vmalloc'. Why not use that?
> >(That explanation should be part of the commit description probably)
> 
> vmalloc allocates pages and then maps them to an arbitrary virtual address
> with PAGE_HYPERVISOR. I needed to use a specific virtual address with
> PAGE_HYPERVISOR_RWX.

/me nods. 
> 
> >
> >>+
> >>+    hole_start = (unsigned long)module_virt_start;
> >>+    hole_end = hole_start + pages * PAGE_SIZE;
> >>+    spin_lock(&payload_list_lock);
> >>+    list_for_each_entry ( data, &payload_list, list )
> >>+    {
> >>+        list_for_each_entry ( data2, &payload_list, list )
> >>+        {
> >>+            unsigned long start, end;
> >>+
> >>+            start = (unsigned long)data2->module_address;
> >>+            end = start + data2->module_pages * PAGE_SIZE;
> >>+            if ( hole_end > start && hole_start < end )
> >>+            {
> >>+                hole_start = end;
> >>+                hole_end = hole_start + pages * PAGE_SIZE;
> >>+                break;
> >>+            }
> >>+        }
> >>+        if ( &data2->list == &payload_list )
> >>+            break;
> >>+    }
> >>+    spin_unlock(&payload_list_lock);
> >
> >This could be made in a nice function. 'find_hole' perhaps?
> >
> >>+
> >>+    if ( hole_end >= module_virt_end )
> >>+        goto error;
> >>+
> >>+    for ( cur = hole_start, mfn_ptr = mfn; pages--; ++mfn_ptr, cur += 
> >>PAGE_SIZE )
> >>+    {
> >>+        if ( map_pages_to_xen(cur, mfn_x(*mfn_ptr), 1, 
> >>PAGE_HYPERVISOR_RWX) )
> >>+        {
> >>+            if ( cur != hole_start )
> >>+                destroy_xen_mappings(hole_start, cur);
> >
> >I think 'destroy_xen_mappings' is OK handling hole_start == cur.
> >
> >>+            goto error;
> >>+        }
> >>+    }
> >>+    xfree(mfn);
> >>+    return (void *)hole_start;
> >>+
> >>+ error:
> >>+    while ( i-- )
> >>+        free_domheap_page(mfn_to_page(mfn_x(mfn[i])));
> >>+    xfree(mfn);
> >>+    return NULL;
> >>+}
> >>+#else
> >>+static void *alloc_module(size_t size)
> >
> >s/module/payload/
> >>+{
> >>+    return NULL;
> >>+}
> >>+#endif
> >>+
> >>+static void free_module(struct payload *payload)
> >>+{
> >>+    int i;
> >
> >unsigned int;
> >
> >>+    struct page_info *pg;
> >>+    PAGE_LIST_HEAD(pg_list);
> >>+    void *va = payload->module_address;
> >>+    unsigned long addr = (unsigned long)va;
> >>+
> >>+    if ( !payload->module_address )
> >>+        return;
> >
> >How about 'if ( !addr )
> >             return;
> >?
> >
> >>+
> >>+    payload->module_address = NULL;
> >>+
> >>+    for ( i = 0; i < payload->module_pages; i++ )
> >>+        page_list_add(vmap_to_page(va + i * PAGE_SIZE), &pg_list);
> >>+
> >>+    destroy_xen_mappings(addr, addr + payload->module_pages * PAGE_SIZE);
> >>+
> >>+    while ( (pg = page_list_remove_head(&pg_list)) != NULL )
> >>+        free_domheap_page(pg);
> >>+
> >>+    payload->module_pages = 0;
> >>+}
> >>+
> >>+static void alloc_section(struct xsplice_elf_sec *sec, size_t *core_size)
> >
> >s/alloc/compute/?
> >
> >>+{
> >>+    size_t align_size = ROUNDUP(*core_size, sec->sec->sh_addralign);
> >>+    sec->sec->sh_entsize = align_size;
> >>+    *core_size = sec->sec->sh_size + align_size;
> >>+}
> >>+
> >>+static int move_module(struct payload *payload, struct xsplice_elf *elf)
> >>+{
> >>+    uint8_t *buf;
> >>+    int i;
> >
> >unsigned int i;
> >
> >>+    size_t core_size = 0;
> >>+
> >>+    /* Allocate text regions */
> >
> >s/Allocate/Compute/
> >
> >>+    for ( i = 0; i < elf->hdr->e_shnum; i++ )
> >>+    {
> >>+        if ( (elf->sec[i].sec->sh_flags & (SHF_ALLOC|SHF_EXECINSTR)) ==
> >>+             (SHF_ALLOC|SHF_EXECINSTR) )
> >>+            alloc_section(&elf->sec[i], &core_size);
> >>+    }
> >>+
> >>+    /* Allocate rw data */
> >>+    for ( i = 0; 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) )
> >>+            alloc_section(&elf->sec[i], &core_size);
> >>+    }
> >>+
> >>+    /* Allocate ro data */
> >>+    for ( i = 0; 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) )
> >>+            alloc_section(&elf->sec[i], &core_size);
> >>+    }
> >>+
> >>+    buf = alloc_module(core_size);
> >>+    if ( !buf ) {
> >>+        printk(XENLOG_ERR "Could not allocate memory for module\n");
> >
> >(%s: Could not allocate %u memory for payload!\n", elf->name, core_size);
> >
> >>+        return -ENOMEM;
> >>+    }
> >>+    memset(buf, 0, core_size);
> >
> >Perhaps for fun it ought to be 'ud2' ?
> 
> There's no point. It either gets memcpy'd over or needs to be set to zero
> for BSS.

Or 0xcc. Was thinking it may be good have it poison so
that we would trip over bugs more easily. Maybe for debug builds?

> 
> >
> >>+
> >>+    for ( i = 0; i < elf->hdr->e_shnum; i++ )
> >>+    {
> >>+        if ( elf->sec[i].sec->sh_flags & SHF_ALLOC )
> >>+        {
> >>+            elf->sec[i].load_addr = buf + elf->sec[i].sec->sh_entsize;
> >>+            memcpy(elf->sec[i].load_addr, elf->sec[i].data,
> >>+                   elf->sec[i].sec->sh_size);
> >>+            printk(XENLOG_DEBUG "Loaded %s at 0x%p\n",
> >
> >Add %s: at the start ..
> >>+                   elf->sec[i].name, elf->sec[i].load_addr);
> >
> >which would be elf->name.
> >
> >>+        }
> >>+    }
> >>+
> >>+    payload->module_address = buf;
> >>+    payload->module_pages = PFN_UP(core_size);
> >
> >Instead of module could we name it payload?
> 
> See comment above.
> 
> >
> >>+
> >>+    return 0;
> >>+}
> >>+
> >>+static int resolve_symbols(struct xsplice_elf *elf)
> >
> >s/resolve/check/
> 
> No, this is resolving section symbols.
> 
> >
> >>+{
> >>+    int i;
> >
> >unsigned int;
> >
> >>+
> >>+    for ( i = 1; i < elf->nsym; i++ )
> >
> >Why 1? Please explain as comment.
> 
> The first entry of an ELF symbol table is the "undefined symbol index". This
> code is expected to be read alongside the ELF specification :-)
> 
> >
> >
> >>+    {
> >>+        switch ( elf->sym[i].sym->st_shndx )
> >>+        {
> >>+            case SHN_COMMON:
> >>+                printk(XENLOG_ERR "Unexpected common symbol: %s\n",
> >>+                       elf->sym[i].name);
> >
> >Please also include elf->name in the error.
> >
> >>+                return -EINVAL;
> >>+                break;
> >>+            case SHN_UNDEF:
> >>+                printk(XENLOG_ERR "Unknown symbol: %s\n", 
> >>elf->sym[i].name);
> >
> >Ditto.
> >>+                return -ENOENT;
> >>+                break;
> >>+            case SHN_ABS:
> >>+                printk(XENLOG_DEBUG "Absolute symbol: %s => 0x%p\n",
> >>+                       elf->sym[i].name, (void 
> >>*)elf->sym[i].sym->st_value);
> >>+                break;
> >>+            default:
> >>+                if ( elf->sec[elf->sym[i].sym->st_shndx].sec->sh_flags & 
> >>SHF_ALLOC )
> >>+                {
> >>+                    elf->sym[i].sym->st_value +=
> >>+                        (unsigned 
> >>long)elf->sec[elf->sym[i].sym->st_shndx].load_addr;
> >>+                    printk(XENLOG_DEBUG "Symbol resolved: %s => 0x%p\n",
> >
> >Ditto;
> >>+                           elf->sym[i].name, (void 
> >>*)elf->sym[i].sym->st_value);
> >>+                }
> >>+        }
> >>+    }
> >>+
> >>+    return 0;
> >>+}
> >>+
> >>+static int perform_relocs(struct xsplice_elf *elf)
> >>+{
> >>+    struct xsplice_elf_sec *rela, *base;
> >>+    int i, rc;
> >>+
> >
> >unsigned int i;
> >
> >>+    for ( i = 0; i < elf->hdr->e_shnum; i++ )
> >>+    {
> >>+        rela = &elf->sec[i];
> >>+
> >>+        /* Is it a valid relocation section? */
> >>+        if ( rela->sec->sh_info >= elf->hdr->e_shnum )
> >>+            continue;
> >
> >Um, don't we want to mark it as invalid or such?
> >Or overwrite it so we won't use it?
> 
> The code doesn't use it. I don't understand the concern.

The comment. Perhaps change it to
/* Ignore invalid relocation sections.  */
> 
> >
> >>+
> >>+        base = &elf->sec[rela->sec->sh_info];
> >>+
> >>+        /* Don't relocate non-allocated sections */
> >>+        if ( !(base->sec->sh_flags & SHF_ALLOC) )
> >>+            continue;
> >
> >>+
> >>+        if ( elf->sec[i].sec->sh_type == SHT_RELA )
> >>+            rc = xsplice_perform_rela(elf, base, rela);
> >>+        else if ( elf->sec[i].sec->sh_type == SHT_REL )
> >>+            rc = xsplice_perform_rel(elf, base, rela);
> >>+
> >>+        if ( rc )
> >>+            return rc;
> >>+    }
> >>+
> >>+    return 0;
> >>+}
> >>+
> >>+static int load_module(struct payload *payload, uint8_t *raw, ssize_t len)
> >>+{
> >>+    struct xsplice_elf elf;
> >
> >Wait a minute? We ditch it after this?
> >
> >>+    int rc = 0;
> >>+
> >>+    rc = xsplice_verify_elf(raw, len);
> >>+    if ( rc )
> >>+        return rc;
> >>+
> >>+    rc = xsplice_elf_load(&elf, raw, len);
> >>+    if ( rc )
> >>+        return rc;
> >>+
> >>+    rc = move_module(payload, &elf);
> >>+    if ( rc )
> >>+        goto err_elf;
> >>+
> >>+    rc = resolve_symbols(&elf);
> >>+    if ( rc )
> >>+        goto err_module;
> >>+
> >>+    rc = perform_relocs(&elf);
> >>+    if ( rc )
> >>+        goto err_module;
> >>+
> >
> >Shouldn't you call xsplice_elf_free(&elf) here? Or
> >hook up the elf to the 'struct payload'?
> >
> >
> >If not, who is going to clean up elf->sec and elf->sym when the
> >payload is unloaded?
> 
> Yes, I forgot to free it here.
> 
> >>+    return 0;
> >>+
> >>+ err_module:
> >>+    free_module(payload);
> >>+ err_elf:
> >>+    xsplice_elf_free(&elf);
> >>+
> >>+    return rc;
> >>+}
> >>+
> >>  static int __init xsplice_init(void)
> >>  {
> >>      register_keyhandler('x', xsplice_printall, "print xsplicing info", 1);
> >>diff --git a/xen/include/asm-x86/x86_64/page.h 
> >>b/xen/include/asm-x86/x86_64/page.h
> >>index 19ab4d0..e6f08e9 100644
> >>--- a/xen/include/asm-x86/x86_64/page.h
> >>+++ b/xen/include/asm-x86/x86_64/page.h
> >>@@ -38,6 +38,8 @@
> >>  #include <xen/pdx.h>
> >>
> >>  extern unsigned long xen_virt_end;
> >>+extern unsigned long module_virt_start;
> >>+extern unsigned long module_virt_end;
> >>
> >>  #define spage_to_pdx(spg) (((spg) - 
> >> spage_table)<<(SUPERPAGE_SHIFT-PAGE_SHIFT))
> >>  #define pdx_to_spage(pdx) (spage_table + 
> >> ((pdx)>>(SUPERPAGE_SHIFT-PAGE_SHIFT)))
> >>diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h
> >>index 41e28da..a3946a3 100644
> >>--- a/xen/include/xen/xsplice.h
> >>+++ b/xen/include/xen/xsplice.h
> >>@@ -1,9 +1,31 @@
> >>  #ifndef __XEN_XSPLICE_H__
> >>  #define __XEN_XSPLICE_H__
> >>
> >>+struct xsplice_elf;
> >>+struct xsplice_elf_sec;
> >>+struct xsplice_elf_sym;
> >>+
> >>+struct xsplice_patch_func {
> >>+    unsigned long new_addr;
> >>+    unsigned long new_size;
> >>+    unsigned long old_addr;
> >>+    unsigned long old_size;
> >>+    char *name;
> >>+    unsigned char undo[8];
> >>+};
> >
> >We don't use them in this patch. They could be moved to another patch.
> 
> OK.
> 
> -- 
> Ross Lagerwall

_______________________________________________
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®.