@@ -342,6 +342,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:
@@ -379,6 +386,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:
+
+<pre>
+typedef void (*livepatch_loadcall_t)(void);
+typedef void (*livepatch_unloadcall_t)(void);
+</pre>
+
### .livepatch.depends and .note.gnu.build-id
To support dependencies checking and safe loading (to load the
@@ -4,14 +4,49 @@
*/
#include "config.h"
+#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
+#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static 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);
+};
+
+/* If we are sorted we _MUST_ be the last .livepatch.hook section. */
+static void z_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(z_check_fnc);
struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
.version = LIVEPATCH_PAYLOAD_VERSION,
@@ -23,6 +23,7 @@
#include <xen/wait.h>
#include <xen/livepatch_elf.h>
#include <xen/livepatch.h>
+#include <xen/livepatch_payload.h>
#include <asm/event.h>
@@ -72,7 +73,11 @@ struct payload {
struct livepatch_build_id dep; /* ELFNOTE_DESC(.livepatch.depends). */
void *bss; /* .bss of the payload. */
size_t bss_size; /* and its size. */
- char name[XEN_LIVEPATCH_NAME_SIZE]; /* Name of it. */
+ livepatch_loadcall_t **load_funcs; /* The array of funcs to call after */
+ livepatch_unloadcall_t **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. */
@@ -581,6 +586,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 )
{
@@ -1065,6 +1089,18 @@ static int apply_payload(struct payload *data)
arch_livepatch_quiesce();
+ /*
+ * Since we are running with IRQs disabled and the hooks may call common
+ * code - which expects the spinlocks to run with IRQs enabled - we temporarly
+ * 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_jmp(&data->funcs[i]);
@@ -1091,6 +1127,18 @@ static int revert_payload(struct payload *data)
for ( i = 0; i < data->nfuncs; i++ )
arch_livepatch_revert_jmp(&data->funcs[i]);
+ /*
+ * Since we are running with IRQs disabled and the hooks may call common
+ * code - which expects the spinlocks to run with IRQs enabled - we temporarly
+ * 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();
/*
new file mode 100644
@@ -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:
+ */