@@ -61,6 +61,14 @@ void noinline arch_livepatch_apply(struct livepatch_func *func)
if ( !len )
return;
+ /* If the apply action has been already executed on this function, do nothing... */
+ if ( func->applied == LIVEPATCH_FUNC_APPLIED )
+ {
+ printk(XENLOG_WARNING LIVEPATCH "%s: %s has been already applied before\n",
+ __func__, func->name);
+ return;
+ }
+
memcpy(func->opaque, old_ptr, len);
if ( func->new_addr )
{
@@ -77,15 +85,25 @@ void noinline arch_livepatch_apply(struct livepatch_func *func)
add_nops(insn, len);
memcpy(old_ptr, insn, len);
+ 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 ( !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;
+ }
+
memcpy(func->old_addr, func->opaque, livepatch_insn_len(func));
+ func->applied = LIVEPATCH_FUNC_NOT_APPLIED;
}
/*
@@ -1242,6 +1242,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.
@@ -1268,6 +1291,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;
@@ -1282,6 +1308,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;
@@ -1304,6 +1333,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
@@ -1324,6 +1356,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 = 0,
+ LIVEPATCH_FUNC_APPLIED = 1
+} livepatch_func_state_t;
+
struct livepatch_func {
const char *name; /* Name of function to be patched. */
void *new_addr;
@@ -834,6 +839,10 @@ struct livepatch_func {
uint32_t old_size;
uint8_t version; /* MUST be LIVEPATCH_PAYLOAD_VERSION. */
uint8_t opaque[31];
+#if defined CONFIG_X86
+ uint8_t applied;
+ uint8_t _pad[7];
+#endif
};
typedef struct livepatch_func livepatch_func_t;
#endif
@@ -117,7 +117,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);