@@ -15,6 +15,7 @@
#include <asm/traps.h>
#include <asm/nmi.h>
#include <asm/nops.h>
+#include <asm/x86_emulate.h>
#include <xen/livepatch.h>
#define MAX_PATCH_LEN (255-1)
@@ -490,6 +491,57 @@ static void __init _alternative_instructions(bool force)
void __init alternative_instructions(void)
{
arch_init_ideal_nops();
+
+ /*
+ * Walk all replacement instructions with x86_decode_lite(). This checks
+ * both that we can decode all instructions within the replacement, and
+ * that any near branch with a disp8 stays within the alternative itself.
+ */
+ if ( IS_ENABLED(CONFIG_SELF_TESTS) )
+ {
+ struct alt_instr *a;
+
+ for ( a = __alt_instructions;
+ a < __alt_instructions_end; ++a )
+ {
+ void *repl = ALT_REPL_PTR(a);
+ void *ip = repl, *end = ip + a->repl_len;
+
+ if ( !a->repl_len )
+ continue;
+
+ for ( x86_decode_lite_t res; ip < end; ip += res.len )
+ {
+ const int8_t *d8;
+ const void *target;
+
+ res = x86_decode_lite(ip, end);
+
+ if ( res.len == 0 )
+ {
+ printk("Alt for %ps [%*ph]\n",
+ ALT_ORIG_PTR(a), a->repl_len, repl);
+ panic(" Unable to decode instruction at +%lu in alternative\n",
+ ip - repl);
+ }
+
+ if ( res.rel_sz != 1 )
+ continue;
+
+ d8 = res.rel;
+ target = ip + res.len + *d8;
+
+ if ( target < repl || target > end )
+ {
+ printk("Alt for %ps [%*ph]\n",
+ ALT_ORIG_PTR(a), a->repl_len, repl);
+ panic(" 'JMP/Jcc disp8' at +%lu leaves alternative block\n",
+ ip - repl);
+ }
+ }
+ }
+ }
+
_alternative_instructions(false);
}