diff --git a/docs/misc/livepatch.markdown b/docs/misc/livepatch.markdown index f22eeabe62..3dd6304cf7 100644 --- a/docs/misc/livepatch.markdown +++ b/docs/misc/livepatch.markdown @@ -351,6 +351,13 @@ When reverting a patch, the hypervisor iterates over each `livepatch_func` and the core code copies the data from the undo buffer (private internal copy) to `old_addr`. +It optionally may contain the address of functions to be called right before +being applied and after being reverted: + + * `.livepatch.hooks.load` - an array of function pointers. + * `.livepatch.hooks.unload` - an array of function pointers. + + ### Example of .livepatch.funcs A simple example of what a payload file can be: @@ -388,6 +395,22 @@ struct livepatch_func livepatch_hello_world = { Code must be compiled with -fPIC. +### .livepatch.hooks.load and .livepatch.hooks.unload + +This section contains an array of function pointers to be executed +before payload is being applied (.livepatch.funcs) or after reverting +the payload. This is useful to prepare data structures that need to +be modified patching. + +Each entry in this array is eight bytes. + +The type definition of the function are as follow: + +
+typedef void (*livepatch_loadcall_t)(void);  
+typedef void (*livepatch_unloadcall_t)(void);   
+
+ ### .livepatch.depends and .note.gnu.build-id To support dependencies checking and safe loading (to load the diff --git a/xen/arch/x86/test/xen_hello_world.c b/xen/arch/x86/test/xen_hello_world.c index d80963ef74..02f3f85dc0 100644 --- a/xen/arch/x86/test/xen_hello_world.c +++ b/xen/arch/x86/test/xen_hello_world.c @@ -4,14 +4,48 @@ */ #include "config.h" +#include #include #include #include +#include #include static const char hello_world_patch_this_fnc[] = "xen_extra_version"; extern const char *xen_hello_world(void); +static unsigned int cnt; + +static void apply_hook(void) +{ + printk(KERN_DEBUG "Hook executing.\n"); +} + +static void revert_hook(void) +{ + printk(KERN_DEBUG "Hook unloaded.\n"); +} + +static void hi_func(void) +{ + printk(KERN_DEBUG "%s: Hi! (called %u times)\n", __func__, ++cnt); +}; + +static void check_fnc(void) +{ + printk(KERN_DEBUG "%s: Hi func called %u times\n", __func__, cnt); + BUG_ON(cnt == 0 || cnt > 2); +} + +LIVEPATCH_LOAD_HOOK(apply_hook); +LIVEPATCH_UNLOAD_HOOK(revert_hook); + +/* Imbalance here. Two load and three unload. */ + +LIVEPATCH_LOAD_HOOK(hi_func); +LIVEPATCH_UNLOAD_HOOK(hi_func); + +LIVEPATCH_UNLOAD_HOOK(check_fnc); struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = { .version = LIVEPATCH_PAYLOAD_VERSION, diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index 293f106c49..0ca4804cbd 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -72,7 +73,11 @@ struct payload { unsigned int nsyms; /* Nr of entries in .strtab and symbols. */ struct livepatch_build_id id; /* ELFNOTE_DESC(.note.gnu.build-id) of the payload. */ struct livepatch_build_id dep; /* ELFNOTE_DESC(.livepatch.depends). */ - char name[XEN_LIVEPATCH_NAME_SIZE]; /* Name of it. */ + livepatch_loadcall_t *const *load_funcs; /* The array of funcs to call after */ + livepatch_unloadcall_t *const *unload_funcs;/* load and unload of the payload. */ + unsigned int n_load_funcs; /* Nr of the funcs to load and execute. */ + unsigned int n_unload_funcs; /* Nr of funcs to call durung unload. */ + char name[XEN_LIVEPATCH_NAME_SIZE]; /* Name of it. */ }; /* Defines an outstanding patching action. */ @@ -540,6 +545,25 @@ static int prepare_payload(struct payload *payload, return rc; } + sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.load"); + if ( sec ) + { + if ( sec->sec->sh_size % sizeof(*payload->load_funcs) ) + return -EINVAL; + + payload->load_funcs = sec->load_addr; + payload->n_load_funcs = sec->sec->sh_size / sizeof(*payload->load_funcs); + } + + sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.unload"); + if ( sec ) + { + if ( sec->sec->sh_size % sizeof(*payload->unload_funcs) ) + return -EINVAL; + + payload->unload_funcs = sec->load_addr; + payload->n_unload_funcs = sec->sec->sh_size / sizeof(*payload->unload_funcs); + } sec = livepatch_elf_sec_by_name(elf, ELF_BUILD_ID_NOTE); if ( sec ) { @@ -1030,6 +1054,18 @@ static int apply_payload(struct payload *data) return rc; } + /* + * Since we are running with IRQs disabled and the hooks may call common + * code - which expects certain spinlocks to run with IRQs enabled - we + * temporarily disable the spin locks IRQ state checks. + */ + spin_debug_disable(); + for ( i = 0; i < data->n_load_funcs; i++ ) + data->load_funcs[i](); + spin_debug_enable(); + + ASSERT(!local_irq_is_enabled()); + for ( i = 0; i < data->nfuncs; i++ ) arch_livepatch_apply(&data->funcs[i]); @@ -1062,6 +1098,18 @@ static int revert_payload(struct payload *data) for ( i = 0; i < data->nfuncs; i++ ) arch_livepatch_revert(&data->funcs[i]); + /* + * Since we are running with IRQs disabled and the hooks may call common + * code - which expects certain spinlocks to run with IRQs enabled - we + * temporarily disable the spin locks IRQ state checks. + */ + spin_debug_disable(); + for ( i = 0; i < data->n_unload_funcs; i++ ) + data->unload_funcs[i](); + spin_debug_enable(); + + ASSERT(!local_irq_is_enabled()); + arch_livepatch_revive(); /* diff --git a/xen/include/xen/livepatch_payload.h b/xen/include/xen/livepatch_payload.h new file mode 100644 index 0000000000..8f38cc2c60 --- /dev/null +++ b/xen/include/xen/livepatch_payload.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Citrix Systems R&D Ltd. + */ + +#ifndef __XEN_LIVEPATCH_PAYLOAD_H__ +#define __XEN_LIVEPATCH_PAYLOAD_H__ + +/* + * The following definitions are to be used in patches. They are taken + * from kpatch. + */ +typedef void livepatch_loadcall_t(void); +typedef void livepatch_unloadcall_t(void); + +/* + * LIVEPATCH_LOAD_HOOK macro + * + * Declares a function pointer to be allocated in a new + * .livepatch.hook.load section. This livepatch_load_data symbol is later + * stripped by create-diff-object so that it can be declared in multiple + * objects that are later linked together, avoiding global symbol + * collision. Since multiple hooks can be registered, the + * .livepatch.hook.load section is a table of functions that will be + * executed in series by the livepatch infrastructure at patch load time. + */ +#define LIVEPATCH_LOAD_HOOK(_fn) \ + livepatch_loadcall_t *__attribute__((weak)) \ + const livepatch_load_data_##_fn __section(".livepatch.hooks.load") = _fn; + +/* + * LIVEPATCH_UNLOAD_HOOK macro + * + * Same as LOAD hook with s/load/unload/ + */ +#define LIVEPATCH_UNLOAD_HOOK(_fn) \ + livepatch_unloadcall_t *__attribute__((weak)) \ + const livepatch_unload_data_##_fn __section(".livepatch.hooks.unload") = _fn; + +#endif /* __XEN_LIVEPATCH_PAYLOAD_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */