xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
To: xen-devel@lists.xenproject.org, konrad@kernel.org,
	sasha.levin@oracle.com, andrew.cooper3@citrix.com,
	ross.lagerwall@citrix.com, mpohlack@amazon.de
Cc: Keir Fraser <keir@xen.org>, Tim Deegan <tim@xen.org>,
	Ian Jackson <ian.jackson@eu.citrix.com>,
	Jan Beulich <jbeulich@suse.com>,
	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Subject: [PATCH v7 08/24] xsplice: Add helper elf routines
Date: Sun, 10 Apr 2016 17:14:40 -0400	[thread overview]
Message-ID: <1460322896-1115-9-git-send-email-konrad.wilk@oracle.com> (raw)
In-Reply-To: <1460322896-1115-1-git-send-email-konrad.wilk@oracle.com>

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

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@citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Reviewed-by: Andrew Cooper<andrew.cooper3@citrix.com>
---
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Keir Fraser <keir@xen.org>
Cc: Tim Deegan <tim@xen.org>

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
  - Add return_ macro back but make it depend on debug=y
  - Per Andrew review: add 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.
v4 - Fix memory leak in elf_get_sym
  - Add XSPLICE to printk/dprintk
v5: Sprinkle newlines.
v6: Squash the ELF header checks from 'xsplice: Implement payload loading' here,
    Do better job at checking string sections and the users of them (sh_size),
    Use XSPLICE as a string literal,
    Move some checks outside the loop,
    Make sure that SHT_STRTAB are really what they say
    Sprinkle consts.
v7:
    Check sh_entsize and sh_offset.
    Added Andrew's Reviewed-by and Ian's Acked-by
    Redo check on sh_entsize to not be !=
---
---
 xen/common/Makefile           |   1 +
 xen/common/xsplice_elf.c      | 360 ++++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/xsplice.h     |   3 +
 xen/include/xen/xsplice_elf.h |  51 ++++++
 4 files changed, 415 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 1e4bc70..afd84b6 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -59,6 +59,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..ffa5c95
--- /dev/null
+++ b/xen/common/xsplice_elf.c
@@ -0,0 +1,360 @@
+/*
+ * 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>
+
+const struct xsplice_elf_sec *xsplice_elf_sec_by_name(const struct xsplice_elf *elf,
+                                                      const char *name)
+{
+    unsigned int i;
+
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        if ( !strcmp(name, elf->sec[i].name) )
+            return &elf->sec[i];
+    }
+
+    return NULL;
+}
+
+static int elf_verify_strtab(const struct xsplice_elf_sec *sec)
+{
+    const Elf_Shdr *s;
+    const uint8_t *contents;
+
+    s = sec->sec;
+
+    if ( s->sh_type != SHT_STRTAB )
+        return -EINVAL;
+
+    if ( !s->sh_size )
+        return -EOPNOTSUPP;
+
+    contents = (const uint8_t *)sec->data;
+
+    if ( contents[0] || contents[s->sh_size - 1] )
+        return -EINVAL;
+
+    return 0;
+}
+
+static int elf_resolve_sections(struct xsplice_elf *elf, const void *data)
+{
+    struct xsplice_elf_sec *sec;
+    unsigned int i;
+    Elf_Off delta;
+    int rc;
+
+    /* xsplice_elf_load sanity checked e_shnum. */
+    sec = xmalloc_array(struct xsplice_elf_sec, elf->hdr->e_shnum);
+    if ( !sec )
+    {
+        printk(XENLOG_ERR XSPLICE"%s: Could not allocate memory for section table!\n",
+               elf->name);
+        return -ENOMEM;
+    }
+
+    elf->sec = sec;
+
+    delta = elf->hdr->e_shoff + elf->hdr->e_shnum * elf->hdr->e_shentsize;
+    if ( delta > elf->len )
+    {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: Section table is past end of payload!\n",
+                    elf->name);
+            return -EINVAL;
+    }
+
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        delta = elf->hdr->e_shoff + i * elf->hdr->e_shentsize;
+
+        sec[i].sec = (void *)data + delta;
+
+        delta = sec[i].sec->sh_offset;
+
+        /*
+         * N.B. elf_resolve_section_names, elf_get_sym skip this check as
+         * we do it here.
+         */
+        if ( delta && (delta + sec[i].sec->sh_size > elf->len) )
+        {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: Section [%u] data is past end of payload!\n",
+                    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, XSPLICE "%s: Unsupported multiple symbol tables!\n",
+                        elf->name);
+                return -EOPNOTSUPP;
+            }
+
+            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, XSPLICE
+                        "%s: Symbol table idx (%u) to strtab past end (%u)\n",
+                        elf->name, elf->symtab->sec->sh_link,
+                        elf->hdr->e_shnum);
+                return -EINVAL;
+            }
+        }
+    }
+
+    if ( !elf->symtab )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: No symbol table found!\n",
+                elf->name);
+        return -EINVAL;
+    }
+
+    if ( !elf->symtab->sec->sh_size ||
+         elf->symtab->sec->sh_entsize < sizeof(Elf_Sym) )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Symbol table header is corrupted!\n",
+                elf->name);
+        return -EINVAL;
+    }
+
+    /*
+     * There can be multiple SHT_STRTAB (.shstrtab, .strtab) so pick one
+     * associated with the symbol table.
+     */
+    elf->strtab = &sec[elf->symtab->sec->sh_link];
+
+    rc = elf_verify_strtab(elf->strtab);
+    if ( rc )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: String table section is corrupted\n",
+                elf->name);
+    }
+
+    return rc;
+}
+
+static int elf_resolve_section_names(struct xsplice_elf *elf, const void *data)
+{
+    const char *shstrtab;
+    unsigned int i;
+    Elf_Off offset, delta;
+    struct xsplice_elf_sec *sec;
+    int rc;
+
+    /*
+     * The elf->sec[0 -> e_shnum] structures have been verified by
+     * elf_resolve_sections. Find file offset for section string table
+     * (normally called .shstrtab)
+     */
+    sec = &elf->sec[elf->hdr->e_shstrndx];
+
+    rc = elf_verify_strtab(sec);
+    if ( rc )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Section string table is corrupted\n",
+                elf->name);
+        return rc;
+    }
+
+    /* Verified in elf_resolve_sections but just in case. */
+    offset = sec->sec->sh_offset;
+    ASSERT(offset < elf->len && (offset + sec->sec->sh_size <= elf->len));
+
+    shstrtab = data + offset;
+
+    for ( i = 1; i < elf->hdr->e_shnum; i++ )
+    {
+        delta = elf->sec[i].sec->sh_name;
+
+        if ( delta && delta >= sec->sec->sh_size )
+        {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: shstrtab [%u] data is past end of payload!\n",
+                    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)
+{
+    const 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;
+
+    /* Checked already in elf_resolve_sections, but just in case. */
+    ASSERT(offset == strtab_sec->sec->sh_offset);
+    ASSERT(offset < elf->len && (offset + strtab_sec->sec->sh_size <= elf->len));
+
+    /* 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 XSPLICE "%s: Could not allocate memory for symbols\n",
+               elf->name);
+        return -ENOMEM;
+    }
+
+    /* So we don't leak memory. */
+    elf->sym = sym;
+
+    for ( i = 1; i < nsym; i++ )
+    {
+        Elf_Sym *s = &((Elf_Sym *)symtab_sec->data)[i];
+
+        /* If st->name is STN_UNDEF zero, the check will always be true. */
+        delta = s->st_name;
+
+        if ( delta && (delta > strtab_sec->sec->sh_size) )
+        {
+            dprintk(XENLOG_DEBUG, XSPLICE "%s: Symbol [%u] data is past end of payload!\n",
+                    elf->name, i);
+            return -EINVAL;
+        }
+
+        sym[i].sym = s;
+        sym[i].name = data + (delta + offset);
+    }
+    elf->nsym = nsym;
+
+    return 0;
+}
+
+static int xsplice_header_check(const struct xsplice_elf *elf)
+{
+    const Elf_Ehdr *hdr = elf->hdr;
+
+    if ( sizeof(*elf->hdr) > elf->len )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Section header is bigger than payload!\n",
+                elf->name);
+        return -EINVAL;
+    }
+
+    if ( !IS_ELF(*hdr) )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Not an ELF payload!\n", elf->name);
+        return -EINVAL;
+    }
+
+    if ( hdr->e_ident[EI_CLASS] != ELFCLASS64 ||
+         hdr->e_ident[EI_DATA] != ELFDATA2LSB ||
+         hdr->e_ident[EI_OSABI] != ELFOSABI_SYSV ||
+         hdr->e_type != ET_REL ||
+         hdr->e_phnum != 0 )
+    {
+        dprintk(XENLOG_ERR, XSPLICE "%s: Invalid ELF payload!\n", elf->name);
+        return -EOPNOTSUPP;
+    }
+
+    if ( elf->hdr->e_shstrndx == SHN_UNDEF )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Section name idx is undefined!?\n",
+                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, XSPLICE "%s: Section name idx (%u) is past end of sections (%u)!\n",
+                elf->name, elf->hdr->e_shstrndx, elf->hdr->e_shnum);
+        return -EINVAL;
+    }
+
+    if ( elf->hdr->e_shnum > 64 )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Too many (%u) sections!\n",
+                elf->name, elf->hdr->e_shnum);
+        return -EINVAL;
+    }
+
+    if ( elf->hdr->e_shoff > elf->len )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Bogus e_shoff!\n", elf->name);
+        return -EINVAL;
+    }
+
+    if ( elf->hdr->e_shentsize < sizeof(Elf_Shdr) )
+    {
+        dprintk(XENLOG_DEBUG, XSPLICE "%s: Section header size is %u! Expected %zu!?\n",
+                elf->name, elf->hdr->e_shentsize, sizeof(Elf_Shdr));
+        return -EINVAL;
+    }
+    return 0;
+}
+
+int xsplice_elf_load(struct xsplice_elf *elf, const 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..89acb77
--- /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. */
+    size_t len;                          /* Length of the ELF file. */
+    const 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;
+    const struct xsplice_elf_sec *symtab;/* Pointer to .symtab section - aka to sec[x]. */
+    const struct xsplice_elf_sec *strtab;/* Pointer to .strtab section - aka to sec[y]. */
+};
+
+const 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, const 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@lists.xen.org
http://lists.xen.org/xen-devel

  parent reply	other threads:[~2016-04-10 21:15 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-10 21:14 [PATCH v7] xSplice v1 design and implementation Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 01/24] xsplice: Design document Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 02/24] xen/xsplice: Hypervisor implementation of XEN_XSPLICE_op Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 03/24] libxc: Implementation of XEN_XSPLICE_op in libxc Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 04/24] xen-xsplice: Tool to manipulate xsplice payloads Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 05/24] arm/x86: Use struct virtual_region to do bug, symbol, and (x86) exception tables lookup Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 06/24] arm/x86/vmap: Add vmalloc_xen, vfree_xen and vm_init_type Konrad Rzeszutek Wilk
2016-04-11  9:39   ` Andrew Cooper
2016-04-11 13:29     ` Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 07/24] x86/mm: Introduce modify_xen_mappings() Konrad Rzeszutek Wilk
2016-04-11 12:51   ` George Dunlap
2016-04-11 13:00     ` Andrew Cooper
2016-04-11 14:04     ` [PATCH v7.1 " Andrew Cooper
2016-04-11 15:21       ` George Dunlap
2016-04-11 17:18       ` Jan Beulich
2016-04-11 17:33         ` Andrew Cooper
2016-04-11 17:46         ` [PATCH v7.2 " Andrew Cooper
2016-04-11 17:54           ` Jan Beulich
2016-04-12  9:08             ` Andrew Cooper
2016-04-10 21:14 ` Konrad Rzeszutek Wilk [this message]
2016-04-10 21:14 ` [PATCH v7 09/24] xsplice: Implement payload loading Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 10/24] xsplice: Implement support for applying/reverting/replacing patches Konrad Rzeszutek Wilk
2016-04-11 10:14   ` Andrew Cooper
2016-04-11 13:29     ` Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 11/24] x86/xen_hello_world.xsplice: Test payload for patching 'xen_extra_version' Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 12/24] xsplice, symbols: Implement symbol name resolution on address Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 13/24] x86, xsplice: Print payload's symbol name and payload name in backtraces Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 14/24] xsplice: Add support for bug frames Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 15/24] xsplice: Add support for exception tables Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 16/24] xsplice: Add support for alternatives Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 17/24] build_id: Provide ld-embedded build-ids Konrad Rzeszutek Wilk
2016-04-11 12:17   ` Andrew Cooper
2016-04-11 13:31     ` Konrad Rzeszutek Wilk
2016-04-11 13:35       ` Andrew Cooper
2016-04-10 21:14 ` [PATCH v7 18/24] HYPERCALL_version_op: Add VERSION_build_id to retrieve build-id Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 19/24] libxl: info: Display build_id of the hypervisor using XEN_VERSION_build_id Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 20/24] xsplice: Print build_id in keyhandler and on bootup Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 21/24] xsplice: Stacking build-id dependency checking Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 22/24] xsplice/xen_replace_world: Test-case for XSPLICE_ACTION_REPLACE Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 23/24] xsplice: Prevent duplicate payloads from being loaded Konrad Rzeszutek Wilk
2016-04-10 21:14 ` [PATCH v7 24/24] MAINTAINERS/xsplice: Add myself and Ross as the maintainers Konrad Rzeszutek Wilk
2016-04-11 14:32 ` [PATCH v7] xSplice v1 design and implementation Konrad Rzeszutek Wilk
2016-04-11 15:43   ` Konrad Rzeszutek Wilk
2016-04-12  8:10     ` Ross Lagerwall
2016-04-12 20:59   ` Konrad Rzeszutek Wilk
2016-04-12 20:59     ` [PATCH v7 25/24] symbols/xsplice: Implement fast symbol names -> virtual addresses lookup Konrad Rzeszutek Wilk
2016-04-13  2:03       ` Konrad Rzeszutek Wilk
2016-04-13  2:17         ` 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=1460322896-1115-9-git-send-email-konrad.wilk@oracle.com \
    --to=konrad.wilk@oracle.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=keir@xen.org \
    --cc=konrad@kernel.org \
    --cc=mpohlack@amazon.de \
    --cc=ross.lagerwall@citrix.com \
    --cc=sasha.levin@oracle.com \
    --cc=tim@xen.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).