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 <konrad.w...@oracle.com> --- 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: + +<pre> +/* 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, /* -----------""--------------- */ +}; +</pre> + +With the linker script as follow to change the `xsplice_hello_world` +do be `.xsplice.funcs` : + +<pre> +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) } + } +} +</pre> + +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 <stdint.h> +#include <sys/types.h> + +/* 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 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel