@@ -1,4 +1,4 @@
-# Xen Live Patching Design v1
+# Xen Live Patching Design v2
## Rationale
@@ -297,10 +297,14 @@ which describe the functions to be patched:
uint32_t old_size;
uint8_t version;
uint8_t opaque[31];
+ /* Added to livepatch payload version 2: */
+ uint8_t applied;
+ uint8_t _pad[7];
};
The size of the structure is 64 bytes on 64-bit hypervisors. It will be
52 on 32-bit hypervisors.
+The version 2 of the payload adds additional 8 bytes to the structure size.
* `name` is the symbol name of the old function. Only used if `old_addr` is
zero, otherwise will be used during dynamic linking (when hypervisor loads
@@ -324,9 +328,15 @@ The size of the structure is 64 bytes on 64-bit hypervisors. It will be
* If the value of `new_addr` is zero then `new_size` determines how many
instruction bytes to NOP (up to opaque size modulo smallest platform
instruction - 1 byte x86 and 4 bytes on ARM).
- * `version` is to be one.
+ * `version` indicates version of the generated payload.
* `opaque` **MUST** be zero.
+The version 2 of the payload adds the following fields to the structure:
+
+ * `applied` tracks function's applied/reverted state. It has a boolean type
+ either LIVEPATCH_FUNC_NOT_APPLIED or LIVEPATCH_FUNC_APPLIED.
+ * `_pad[7]` adds padding to align to 8 bytes.
+
The size of the `livepatch_func` array is determined from the ELF section
size.
@@ -378,6 +388,9 @@ A simple example of what a payload file can be:
uint32_t old_size;
uint8_t version;
uint8_t pad[31];
+ /* Added to livepatch payload version 2: */
+ uint8_t applied;
+ uint8_t _pad[7];
};
/* Our replacement function for xen_extra_version. */
@@ -22,9 +22,16 @@ void arch_livepatch_apply(struct livepatch_func *func)
ASSERT(vmap_of_xen_text);
+ /*
+ * If the apply action has been already executed
+ * on this function, do nothing...
+ */
+ if ( is_func_applied(func) )
+ return;
+
len = livepatch_insn_len(func);
if ( !len )
- return;
+ goto applied;
/* Save old ones. */
memcpy(func->opaque, func->old_addr, len);
@@ -73,6 +80,9 @@ void arch_livepatch_apply(struct livepatch_func *func)
if ( func->new_addr )
clean_and_invalidate_dcache_va_range(func->new_addr, func->new_size);
clean_and_invalidate_dcache_va_range(new_ptr, sizeof (*new_ptr) * len);
+
+applied:
+ func->applied = LIVEPATCH_FUNC_APPLIED;
}
/* arch_livepatch_revert shared with ARM 32/ARM 64. */
@@ -26,9 +26,16 @@ void arch_livepatch_apply(struct livepatch_func *func)
ASSERT(vmap_of_xen_text);
+ /*
+ * If the apply action has been already executed
+ * on this function, do nothing...
+ */
+ if ( is_func_applied(func) )
+ return;
+
len = livepatch_insn_len(func);
if ( !len )
- return;
+ goto applied;
/* Save old ones. */
memcpy(func->opaque, func->old_addr, len);
@@ -60,6 +67,9 @@ void arch_livepatch_apply(struct livepatch_func *func)
if ( func->new_addr )
clean_and_invalidate_dcache_va_range(func->new_addr, func->new_size);
clean_and_invalidate_dcache_va_range(new_ptr, sizeof (*new_ptr) * len);
+
+applied:
+ func->applied = LIVEPATCH_FUNC_APPLIED;
}
/* arch_livepatch_revert shared with ARM 32/ARM 64. */
@@ -73,17 +73,25 @@ int arch_livepatch_verify_func(const struct livepatch_func *func)
return 0;
}
-void arch_livepatch_revert(const struct livepatch_func *func)
+void arch_livepatch_revert(struct livepatch_func *func)
{
uint32_t *new_ptr;
unsigned int len;
+ /*
+ * If the apply action hasn't been executed
+ * on this function, do nothing...
+ */
+ if ( is_func_reverted(func) )
+ return;
+
new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text;
len = livepatch_insn_len(func);
memcpy(new_ptr, func->opaque, len);
clean_and_invalidate_dcache_va_range(new_ptr, len);
+ func->applied = LIVEPATCH_FUNC_NOT_APPLIED;
}
void arch_livepatch_post_action(void)
@@ -56,10 +56,17 @@ void noinline arch_livepatch_apply(struct livepatch_func *func)
uint8_t insn[sizeof(func->opaque)];
unsigned int len;
+ /*
+ * If the apply action has been already executed
+ * on this function, do nothing...
+ */
+ if ( is_func_applied(func) )
+ return;
+
old_ptr = func->old_addr;
len = livepatch_insn_len(func);
if ( !len )
- return;
+ goto applied;
memcpy(func->opaque, old_ptr, len);
if ( func->new_addr )
@@ -77,15 +84,26 @@ void noinline arch_livepatch_apply(struct livepatch_func *func)
add_nops(insn, len);
memcpy(old_ptr, insn, len);
+
+applied:
+ func->applied = LIVEPATCH_FUNC_APPLIED;
}
/*
* "noinline" to cause control flow change and thus invalidate I$ and
* cause refetch after modification.
*/
-void noinline arch_livepatch_revert(const struct livepatch_func *func)
+void noinline arch_livepatch_revert(struct livepatch_func *func)
{
+ /*
+ * If the apply action hasn't been executed
+ * on this function, do nothing...
+ */
+ if ( is_func_reverted(func) )
+ return;
+
memcpy(func->old_addr, func->opaque, livepatch_insn_len(func));
+ func->applied = LIVEPATCH_FUNC_NOT_APPLIED;
}
/*
@@ -1240,6 +1240,29 @@ static inline void revert_payload_tail(struct payload *data)
data->state = LIVEPATCH_STATE_CHECKED;
}
+/*
+ * Check if an action has applied the same state to all payload's functions consistently.
+ */
+static inline bool was_action_consistent(const struct payload *data, livepatch_func_state_t expected_state)
+{
+ int i;
+
+ for ( i = 0; i < data->nfuncs; i++ )
+ {
+ struct livepatch_func *f = &(data->funcs[i]);
+
+ if ( f->applied != expected_state )
+ {
+ printk(XENLOG_ERR LIVEPATCH "%s: Payload has a function: '%s' with inconsistent applied state.\n",
+ data->name, f->name ?: "noname");
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
/*
* This function is executed having all other CPUs with no deep stack (we may
* have cpu_idle on it) and IRQs disabled.
@@ -1266,6 +1289,9 @@ static void livepatch_do_action(void)
else
rc = apply_payload(data);
+ if ( !was_action_consistent(data, rc ? LIVEPATCH_FUNC_NOT_APPLIED : LIVEPATCH_FUNC_APPLIED) )
+ panic("livepatch: partially applied payload '%s'!\n", data->name);
+
if ( rc == 0 )
apply_payload_tail(data);
break;
@@ -1280,6 +1306,9 @@ static void livepatch_do_action(void)
else
rc = revert_payload(data);
+ if ( !was_action_consistent(data, rc ? LIVEPATCH_FUNC_APPLIED : LIVEPATCH_FUNC_NOT_APPLIED) )
+ panic("livepatch: partially reverted payload '%s'!\n", data->name);
+
if ( rc == 0 )
revert_payload_tail(data);
break;
@@ -1302,6 +1331,9 @@ static void livepatch_do_action(void)
other->rc = revert_payload(other);
+ if ( !was_action_consistent(other, rc ? LIVEPATCH_FUNC_APPLIED : LIVEPATCH_FUNC_NOT_APPLIED) )
+ panic("livepatch: partially reverted payload '%s'!\n", other->name);
+
if ( other->rc == 0 )
revert_payload_tail(other);
else
@@ -1322,6 +1354,9 @@ static void livepatch_do_action(void)
else
rc = apply_payload(data);
+ if ( !was_action_consistent(data, rc ? LIVEPATCH_FUNC_NOT_APPLIED : LIVEPATCH_FUNC_APPLIED) )
+ panic("livepatch: partially applied payload '%s'!\n", data->name);
+
if ( rc == 0 )
apply_payload_tail(data);
}
@@ -818,7 +818,7 @@ struct xen_sysctl_cpu_featureset {
* If zero exit with success.
*/
-#define LIVEPATCH_PAYLOAD_VERSION 1
+#define LIVEPATCH_PAYLOAD_VERSION 2
/*
* .livepatch.funcs structure layout defined in the `Payload format`
* section in the Live Patch design document.
@@ -826,6 +826,11 @@ struct xen_sysctl_cpu_featureset {
* We guard this with __XEN__ as toolstacks SHOULD not use it.
*/
#ifdef __XEN__
+typedef enum livepatch_func_state {
+ LIVEPATCH_FUNC_NOT_APPLIED,
+ LIVEPATCH_FUNC_APPLIED
+} livepatch_func_state_t;
+
struct livepatch_func {
const char *name; /* Name of function to be patched. */
void *new_addr;
@@ -834,6 +839,8 @@ struct livepatch_func {
uint32_t old_size;
uint8_t version; /* MUST be LIVEPATCH_PAYLOAD_VERSION. */
uint8_t opaque[31];
+ uint8_t applied;
+ uint8_t _pad[7];
};
typedef struct livepatch_func livepatch_func_t;
#endif
@@ -109,6 +109,31 @@ static inline int livepatch_verify_distance(const struct livepatch_func *func)
return 0;
}
+
+static inline bool_t is_func_applied(const struct livepatch_func *func)
+{
+ if ( func->applied == LIVEPATCH_FUNC_APPLIED )
+ {
+ printk(XENLOG_WARNING LIVEPATCH "%s: %s has been already applied before\n",
+ __func__, func->name);
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool_t is_func_reverted(const struct livepatch_func *func)
+{
+ if ( !func->old_addr || func->applied == LIVEPATCH_FUNC_NOT_APPLIED )
+ {
+ printk(XENLOG_WARNING LIVEPATCH "%s: %s has not been applied before\n",
+ __func__, func->name);
+ return true;
+ }
+
+ return false;
+}
+
/*
* These functions are called around the critical region patching live code,
* for an architecture to take make appropratie global state adjustments.
@@ -117,7 +142,7 @@ int arch_livepatch_quiesce(void);
void arch_livepatch_revive(void);
void arch_livepatch_apply(struct livepatch_func *func);
-void arch_livepatch_revert(const struct livepatch_func *func);
+void arch_livepatch_revert(struct livepatch_func *func);
void arch_livepatch_post_action(void);
void arch_livepatch_mask(void);
@@ -24,6 +24,9 @@ LIVEPATCH_PREPOST_HOOKS := xen_prepost_hooks.livepatch
LIVEPATCH_PREPOST_HOOKS_FAIL := xen_prepost_hooks_fail.livepatch
LIVEPATCH_ACTION_HOOKS := xen_action_hooks.livepatch
LIVEPATCH_ACTION_HOOKS_NOFUNC := xen_action_hooks_nofunc.livepatch
+LIVEPATCH_ACTION_HOOKS_MARKER:= xen_action_hooks_marker.livepatch
+LIVEPATCH_ACTION_HOOKS_NOAPPLY:= xen_action_hooks_noapply.livepatch
+LIVEPATCH_ACTION_HOOKS_NOREVERT:= xen_action_hooks_norevert.livepatch
LIVEPATCHES += $(LIVEPATCH)
LIVEPATCHES += $(LIVEPATCH_BYE)
@@ -34,6 +37,9 @@ LIVEPATCHES += $(LIVEPATCH_PREPOST_HOOKS)
LIVEPATCHES += $(LIVEPATCH_PREPOST_HOOKS_FAIL)
LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS)
LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_NOFUNC)
+LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_MARKER)
+LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_NOAPPLY)
+LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_NOREVERT)
LIVEPATCH_DEBUG_DIR ?= $(DEBUG_DIR)/xen-livepatch
@@ -158,7 +164,26 @@ $(LIVEPATCH_ACTION_HOOKS): xen_action_hooks.o xen_hello_world_func.o note.o xen_
$(LIVEPATCH_ACTION_HOOKS_NOFUNC): xen_action_hooks_nofunc.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_NOFUNC) $^
+xen_actions_hooks_marker.o: config.h
+
+.PHONY: $(LIVEPATCH_ACTION_HOOKS_MARKER)
+$(LIVEPATCH_ACTION_HOOKS_MARKER): xen_action_hooks_marker.o xen_hello_world_func.o note.o xen_note.o
+ $(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_MARKER) $^
+
+xen_actions_hooks_noapply.o: config.h
+
+.PHONY: $(LIVEPATCH_ACTION_HOOKS_NOAPPLY)
+$(LIVEPATCH_ACTION_HOOKS_NOAPPLY): xen_action_hooks_marker.o xen_hello_world_func.o note.o xen_note.o
+ $(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_NOAPPLY) $^
+
+xen_actions_hooks_norevert.o: config.h
+
+.PHONY: $(LIVEPATCH_ACTION_HOOKS_NOREVERT)
+$(LIVEPATCH_ACTION_HOOKS_NOREVERT): xen_action_hooks_marker.o xen_hello_world_func.o note.o xen_note.o
+ $(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_NOREVERT) $^
+
.PHONY: livepatch
livepatch: $(LIVEPATCH) $(LIVEPATCH_BYE) $(LIVEPATCH_REPLACE) $(LIVEPATCH_NOP) $(LIVEPATCH_NO_XEN_BUILDID) \
$(LIVEPATCH_PREPOST_HOOKS) $(LIVEPATCH_PREPOST_HOOKS_FAIL) $(LIVEPATCH_ACTION_HOOKS) \
- $(LIVEPATCH_ACTION_HOOKS_NOFUNC)
+ $(LIVEPATCH_ACTION_HOOKS_NOFUNC) $(LIVEPATCH_ACTION_HOOKS_MARKER) $(LIVEPATCH_ACTION_HOOKS_NOAPPLY) \
+ $(LIVEPATCH_ACTION_HOOKS_NOREVERT)
@@ -28,6 +28,7 @@ static int apply_hook(livepatch_payload_t *payload)
{
struct livepatch_func *func = &payload->funcs[i];
+ func->applied = LIVEPATCH_FUNC_APPLIED;
apply_cnt++;
printk(KERN_DEBUG "%s: applying: %s\n", __func__, func->name);
@@ -48,6 +49,7 @@ static int revert_hook(livepatch_payload_t *payload)
{
struct livepatch_func *func = &payload->funcs[i];
+ func->applied = LIVEPATCH_FUNC_NOT_APPLIED;
revert_cnt++;
printk(KERN_DEBUG "%s: reverting: %s\n", __func__, func->name);
new file mode 100644
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
+ *
+ */
+
+#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 const char hello_world_patch_this_fnc[] = "xen_extra_version";
+extern const char *xen_hello_world(void);
+
+static int pre_apply_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: pre applied: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return 0;
+}
+
+static void post_apply_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: post applied: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+}
+
+static int pre_revert_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: pre reverted: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return 0;
+}
+
+static void post_revert_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: post reverted: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+}
+
+LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
+LIVEPATCH_POSTAPPLY_HOOK(post_apply_hook);
+LIVEPATCH_PREREVERT_HOOK(pre_revert_hook);
+LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
+
+struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
+ .version = LIVEPATCH_PAYLOAD_VERSION,
+ .name = hello_world_patch_this_fnc,
+ .new_addr = xen_hello_world,
+ .old_addr = xen_extra_version,
+ .new_size = NEW_CODE_SZ,
+ .old_size = OLD_CODE_SZ,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
new file mode 100644
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
+ *
+ */
+
+#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 const char hello_world_patch_this_fnc[] = "xen_extra_version";
+extern const char *xen_hello_world(void);
+
+static unsigned int apply_cnt;
+
+static int pre_apply_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: pre applied: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return 0;
+}
+
+static int apply_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ apply_cnt++;
+ printk(KERN_DEBUG "%s: applying: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return -EINVAL; /* Mark action as inconsistent */
+}
+
+static void post_apply_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(apply_cnt != 1);
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: post applied: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+}
+
+static int pre_revert_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: pre reverted: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return 0;
+}
+
+static void post_revert_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: post reverted: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+}
+
+LIVEPATCH_APPLY_HOOK(apply_hook);
+
+LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
+LIVEPATCH_POSTAPPLY_HOOK(post_apply_hook);
+LIVEPATCH_PREREVERT_HOOK(pre_revert_hook);
+LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
+
+struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
+ .version = LIVEPATCH_PAYLOAD_VERSION,
+ .name = hello_world_patch_this_fnc,
+ .new_addr = xen_hello_world,
+ .old_addr = xen_extra_version,
+ .new_size = NEW_CODE_SZ,
+ .old_size = OLD_CODE_SZ,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
new file mode 100644
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
+ *
+ */
+
+#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 const char hello_world_patch_this_fnc[] = "xen_extra_version";
+extern const char *xen_hello_world(void);
+
+static unsigned int revert_cnt;
+
+static int pre_apply_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: pre applied: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return 0;
+}
+
+static void post_apply_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: post applied: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+}
+
+static int pre_revert_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
+ printk(KERN_DEBUG "%s: pre reverted: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return 0;
+}
+
+static int revert_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ revert_cnt++;
+ printk(KERN_DEBUG "%s: reverting: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+
+ return -EINVAL; /* Mark action as inconsistent */
+}
+
+static void post_revert_hook(livepatch_payload_t *payload)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
+
+ for (i = 0; i < payload->nfuncs; i++)
+ {
+ struct livepatch_func *func = &payload->funcs[i];
+
+ BUG_ON(revert_cnt != 1);
+ BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
+
+ /* Outside of quiesce zone: MAY TRIGGER HOST CRASH/UNDEFINED BEHAVIOR */
+ arch_livepatch_quiesce();
+ arch_livepatch_revert(payload);
+ arch_livepatch_revive();
+ BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
+
+ printk(KERN_DEBUG "%s: post reverted: %s\n", __func__, func->name);
+ }
+
+ printk(KERN_DEBUG "%s: Hook done.\n", __func__);
+}
+
+LIVEPATCH_APPLY_HOOK(revert_hook);
+
+LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
+LIVEPATCH_POSTAPPLY_HOOK(post_apply_hook);
+LIVEPATCH_PREREVERT_HOOK(pre_revert_hook);
+LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
+
+struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
+ .version = LIVEPATCH_PAYLOAD_VERSION,
+ .name = hello_world_patch_this_fnc,
+ .new_addr = xen_hello_world,
+ .old_addr = xen_extra_version,
+ .new_size = NEW_CODE_SZ,
+ .old_size = OLD_CODE_SZ,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */