diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c
index 090a48977b..8aef2fd12e 100644
--- a/xen/common/livepatch.c
+++ b/xen/common/livepatch.c
@@ -560,6 +560,58 @@ static int check_patching_sections(const struct livepatch_elf *elf)
     return 0;
 }
 
+static inline int livepatch_verify_expectation_fn(const struct livepatch_func *func)
+{
+    const livepatch_expectation_t *exp = &func->expect;
+
+    /* Ignore disabled expectations. */
+    if ( !exp->enabled )
+        return 0;
+
+    /* There is nothing to expect */
+    if ( !func->old_addr )
+        return -EFAULT;
+
+    if ( exp->len > sizeof(exp->data))
+        return -EOVERFLOW;
+
+    /* Incorrect expectation */
+    if ( func->old_size < exp->len )
+        return -ERANGE;
+
+    if ( memcmp(func->old_addr, exp->data, exp->len) )
+    {
+        printk(XENLOG_ERR LIVEPATCH "%s: expectation failed: expected:%*phN, actual:%*phN\n",
+               func->name, exp->len, exp->data, exp->len, func->old_addr);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static inline int livepatch_check_expectations(const struct payload *payload)
+{
+    int i, rc;
+
+    printk(XENLOG_INFO LIVEPATCH "%s: Verifying enabled expectations for all functions\n",
+           payload->name);
+
+    for ( i = 0; i < payload->nfuncs; i++ )
+    {
+        const struct livepatch_func *func = &(payload->funcs[i]);
+
+        rc = livepatch_verify_expectation_fn(func);
+        if ( rc )
+        {
+            printk(XENLOG_ERR LIVEPATCH "%s: expectations of %s failed (rc=%d), aborting!\n",
+                   payload->name, func->name ?: "unknown", rc);
+            return rc;
+        }
+    }
+
+    return 0;
+}
+
 /*
  * Lookup specified section and when exists assign its address to a specified hook.
  * Perform section pointer and size validation: single hook sections must contain a
@@ -1347,6 +1399,20 @@ static void livepatch_do_action(void)
 
         if ( rc == 0 )
         {
+            /*
+             * Make sure all expectation requirements are met.
+             * Beware all the payloads are reverted at this point.
+             * If expectations are not met the system is left in a
+             * completely UNPATCHED state!
+             */
+            rc = livepatch_check_expectations(data);
+            if ( rc )
+            {
+                printk(XENLOG_ERR LIVEPATCH "%s: SYSTEM MIGHT BE INSECURE: "
+                       "Replace action has been aborted after reverting ALL payloads!\n", data->name);
+                break;
+            }
+
             if ( is_hook_enabled(data->hooks.apply.action) )
             {
                 printk(XENLOG_INFO LIVEPATCH "%s: Calling apply action hook function\n", data->name);
@@ -1800,6 +1866,11 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action)
                     break;
             }
 
+            /* Make sure all expectation requirements are met. */
+            rc = livepatch_check_expectations(data);
+            if ( rc )
+                break;
+
             if ( is_hook_enabled(data->hooks.apply.pre) )
             {
                 printk(XENLOG_INFO LIVEPATCH "%s: Calling pre-apply hook function\n", data->name);
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index b55ad6d050..e18322350d 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -818,7 +818,7 @@ struct xen_sysctl_cpu_featureset {
  *     If zero exit with success.
  */
 
-#define LIVEPATCH_PAYLOAD_VERSION 2
+#define LIVEPATCH_PAYLOAD_VERSION 3
 /*
  * .livepatch.funcs structure layout defined in the `Payload format`
  * section in the Live Patch design document.
@@ -826,6 +826,18 @@ struct xen_sysctl_cpu_featureset {
  * We guard this with __XEN__ as toolstacks SHOULD not use it.
  */
 #ifdef __XEN__
+#define LIVEPATCH_OPAQUE_SIZE 31
+
+struct livepatch_expectation {
+    uint8_t enabled : 1;
+    uint8_t len : 5;        /* Length of data up to LIVEPATCH_OPAQUE_SIZE
+                               (5 bits is enough for now) */
+    uint8_t data[LIVEPATCH_OPAQUE_SIZE]; /* Same size as opaque[] buffer of
+                                            struct livepatch_func. This is the
+                                            max number of bytes to be patched */
+};
+typedef struct livepatch_expectation livepatch_expectation_t;
+
 typedef enum livepatch_func_state {
     LIVEPATCH_FUNC_NOT_APPLIED = 0,
     LIVEPATCH_FUNC_APPLIED = 1
@@ -838,11 +850,12 @@ struct livepatch_func {
     uint32_t new_size;
     uint32_t old_size;
     uint8_t version;        /* MUST be LIVEPATCH_PAYLOAD_VERSION. */
-    uint8_t opaque[31];
+    uint8_t opaque[LIVEPATCH_OPAQUE_SIZE];
 #if defined CONFIG_X86
     uint8_t applied;
     uint8_t _pad[7];
 #endif
+    livepatch_expectation_t expect;
 };
 typedef struct livepatch_func livepatch_func_t;
 #endif
