[PATCH v3 3/5] x86/alternative: Walk all replacements during self tests
Andrew Cooper <[email protected]> Mon, 3 Aug 2026 08:20:04 +0100
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <[email protected]> |
When self tests are active, walk all alternative replacements with x86_decode_lite(). This checks that we can decode all instructions, and also lets us check that disp8's don't leave the replacement block as such a case will definitely malfunction. Signed-off-by: Andrew Cooper <[email protected]> Reviewed-by: Jan Beulich <[email protected]> --- CC: Jan Beulich <[email protected]> CC: Roger Pau Monné <[email protected]> CC: Teddy Astie <[email protected]> v2: * Rebase over API changes in patch 1 * Use +%lu and drop casts * Swap to CONFIG_SELF_TESTS --- xen/arch/x86/alternative.c | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c index 5ed0c2672589..fd03147bdd12 100644 --- a/xen/arch/x86/alternative.c +++ b/xen/arch/x86/alternative.c @@ -16,6 +16,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) @@ -586,6 +587,57 @@ static void __init _alternative_instructions(unsigned int what) 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(ALT_INSNS); } -- 2.39.5