From mboxrd@z Thu Jan 1 00:00:00 1970 From: Konrad Rzeszutek Wilk Subject: [PATCH v2 10/13] xen_hello_world.xsplice: Test payload for patching 'xen_extra_version'. Date: Thu, 14 Jan 2016 16:47:08 -0500 Message-ID: <1452808031-706-11-git-send-email-konrad.wilk@oracle.com> References: <1452808031-706-1-git-send-email-konrad.wilk@oracle.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from mail6.bemta14.messagelabs.com ([193.109.254.103]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1aJpjv-0006UH-HU for xen-devel@lists.xenproject.org; Thu, 14 Jan 2016 21:47:31 +0000 In-Reply-To: <1452808031-706-1-git-send-email-konrad.wilk@oracle.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xenproject.org, ross.lagerwall@citrix.com, mpohlack@amazon.com, andrew.cooper3@citrix.com, stefano.stabellini@citrix.com, jbeulich@suse.com, ian.jackson@eu.citrix.com, ian.campbell@citrix.com, wei.liu2@citrix.com, sasha.levin@oracle.com Cc: Konrad Rzeszutek Wilk List-Id: xen-devel@lists.xenproject.org This change demonstrates how to generate an xSplice ELF payload. The idea here is that we want to patch in the hypervisor the 'xen_version_extra' function with an function that will return 'Hello World'. The 'xl info | grep extraversion' will reflect the new value after the patching. To generate this ELF payload file we need: - C code of the new code. - C code generating the .xsplice.func structure. - The address of the old code (xen_extra_version). We do it by using 'nm' but that is a bit of hack. The linker script file: - Discards .debug* and .comments* sections. - Changes the name of .data.local.xsplice_hello_world to .xsplice.func - Figures out the size of the new code. Also if you are curious on the input/output sections magic the linker does, add these to the GCC line: -Wl,-M -Wl,-t -Wl,-verbose which are: print linking map, provide trace and be verbose. The use-case is simple: $xen-xsplice load /usr/lib/xen/bin/xen_hello_world.xsplice $xen-xsplice list ID | status ----------------------------------------+------------ xen_hello_world APPLIED $xl info | grep extra xen_extra : Hello World $xen-xsplice revert xen_hello_world Performing revert: completed $xen-xsplice unload xen_hello_world Performing unload: completed $xl info | grep extra xen_extra : -unstable Note that it does not build under a 32-bit toolstack as there is no access to the hypervisor (xen-syms). We also force it to be built every time - as the hypervisor may have been rebuilt. Signed-off-by: Konrad Rzeszutek Wilk --- docs/misc/xsplice.markdown | 50 ++++++++++++++++++++++++++++++++++++++++++++ tools/misc/Makefile | 25 +++++++++++++++++++++- tools/misc/xen_hello_world.c | 15 +++++++++++++ tools/misc/xsplice.h | 12 +++++++++++ tools/misc/xsplice.lds | 11 ++++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 tools/misc/xen_hello_world.c create mode 100644 tools/misc/xsplice.h create mode 100644 tools/misc/xsplice.lds diff --git a/docs/misc/xsplice.markdown b/docs/misc/xsplice.markdown index beb452e..e2cdcff 100644 --- a/docs/misc/xsplice.markdown +++ b/docs/misc/xsplice.markdown @@ -312,11 +312,61 @@ size. When applying the patch the hypervisor iterates over each `xsplice_patch_func` structure and the core code inserts a trampoline at `old_addr` to `new_addr`. +The `new_addr` is altered when the ELF payload is loaded. When reverting a patch, the hypervisor iterates over each `xsplice_patch_func` and the core code copies the data from the undo buffer (private internal copy) to `old_addr`. +### Example + +A simple example of what a payload file can be: + +
+/* MUST be in sync with hypervisor. */  
+struct xsplice_patch_func {  
+    const char *name;  
+    unsigned long new_addr;  
+    const unsigned long old_addr;  
+    uint32_t new_size;  
+    const uint32_t old_size;  
+    uint8_t pad[32];  
+};  
+
+/* Our replacement function for xen_extra_version. */  
+const char *xen_hello_world(void)  
+{  
+    return "Hello World";  
+}  
+
+struct xsplice_patch_func xsplice_hello_world = {  
+    .name = "xen_extra_version",  
+    .new_addr = &xen_hello_world,  
+    .old_addr = 0xffff82d08013963c, /* Extracted from xen-syms. */  
+    .new_size = 13, /* To be be computed by scripts. */  
+    .old_size = 13, /* -----------""---------------  */  
+};  
+
+ +With the linker script as follow to change the `xsplice_hello_world` +do be `.xsplice.funcs` : + +
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")  
+OUTPUT_ARCH(i386:x86-64)  
+ENTRY(xsplice_hello_world)  
+SECTIONS  
+{  
+    /* The hypervisor expects ".xsplice.func", so change  
+     * the ".data.xsplice_hello_world" to it. */  
+
+    .xsplice.funcs : { *(*.xsplice_hello_world) }  
+    }  
+}  
+
+ +Code must be compiled with -fPIC. + ## Hypercalls We will employ the sub operations of the system management hypercall (sysctl). diff --git a/tools/misc/Makefile b/tools/misc/Makefile index c46873e..8385830 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -36,6 +36,10 @@ INSTALL_SBIN += $(INSTALL_SBIN-y) # Everything to be installed in a private bin/ INSTALL_PRIVBIN += xenpvnetboot +# We need the hypervisor - and only 64-bit builds have it. +ifeq ($(XEN_COMPILE_ARCH),x86_64) +INSTALL_PRIVBIN += xen_hello_world.xsplice +endif # Everything to be installed TARGETS_ALL := $(INSTALL_BIN) $(INSTALL_SBIN) $(INSTALL_PRIVBIN) @@ -49,7 +53,7 @@ TARGETS_COPY += xenpvnetboot # Everything which needs to be built TARGETS_BUILD := $(filter-out $(TARGETS_COPY),$(TARGETS_ALL)) -.PHONY: all build +.PHONY: all build xsplice all build: $(TARGETS_BUILD) .PHONY: install @@ -111,4 +115,23 @@ gtraceview: gtraceview.o xencov: xencov.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) +.PHONY: xsplice +xsplice: +ifeq ($(XEN_COMPILE_ARCH),x86_64) + # We MUST regenerate the file everytime we build - in case the hypervisor + # is rebuilt too. + $(RM) *.xplice + $(MAKE) xen_hello_world.xsplice +endif + +XEN_EXTRA_VERSION_ADDR=$(shell nm --defined $(XEN_ROOT)/xen/xen-syms | grep xen_extra_version | awk '{print "0x"$$1}') + +xen_hello_world.xsplice: xen_hello_world.c + $(CC) -DOLD_CODE=$(XEN_EXTRA_VERSION_ADDR) -I$(XEN_ROOT)/tools/include \ + -fPIC -Wl,--emit-relocs \ + -Wl,-r -Wl,--entry=xsplice_hello_world \ + -fdata-sections -ffunction-sections \ + -nostdlib -Txsplice.lds \ + -o $@ $< + @objdump -x --section=.xsplice.funcs $@ -include $(DEPS) diff --git a/tools/misc/xen_hello_world.c b/tools/misc/xen_hello_world.c new file mode 100644 index 0000000..8c24d8f --- /dev/null +++ b/tools/misc/xen_hello_world.c @@ -0,0 +1,15 @@ +#include "xsplice.h" + +/* Our replacement function for xen_extra_version. */ +const char *xen_hello_world(void) +{ + return "Hello World"; +} + +struct xsplice_patch_func xsplice_hello_world = { + .name = "xen_extra_version", + .new_addr = &xen_hello_world, + .old_addr = OLD_CODE, + .new_size = 13, /* TODO: Compute. */ + .old_size = 13, /* TODO: Compute. */ +}; diff --git a/tools/misc/xsplice.h b/tools/misc/xsplice.h new file mode 100644 index 0000000..6ce8bae --- /dev/null +++ b/tools/misc/xsplice.h @@ -0,0 +1,12 @@ +#include +#include + +/* MUST be in sync with hypervisor. */ +struct xsplice_patch_func { + const char *name; + unsigned long new_addr; + const unsigned long old_addr; + uint32_t new_size; + const uint32_t old_size; + uint8_t pad[32]; +}; diff --git a/tools/misc/xsplice.lds b/tools/misc/xsplice.lds new file mode 100644 index 0000000..f52eb8c --- /dev/null +++ b/tools/misc/xsplice.lds @@ -0,0 +1,11 @@ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(xsplice_hello_world) +SECTIONS +{ + /* The hypervisor expects ".xsplice.func", so change + * the ".data.xsplice_hello_world" to it. */ + + .xsplice.funcs : { *(*.xsplice_hello_world) } + +} -- 2.1.0