|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: Assert in x86_emulate_wrapper triggerable by HVM domain
On 15.04.2025 23:52, Manuel Andreas wrote:
> Dear all,
>
> my fuzzing infrastructure discovered that an assert in
> x86_emulate_wrapper is able to be triggered by an HVM domain executing a
> specially crafted repeating movs instruction.
That's
/* All cases returning X86EMUL_EXCEPTION should have fault semantics. */
if ( rc == X86EMUL_EXCEPTION )
ASSERT(ctxt->regs->r(ip) == orig_ip);
?
> Specifically, if the emulation of the rep movs instruction triggers an
> exception (e.g. by accessing invalid memory after some amount of
> iterations), the emulation will be halted at that point.
> However, the instruction manual requires that _some_ register state
> (namely the updated value of rcx) shall be commited, whereas the
> instruction pointer needs to be rolled back to point to the address of
> the instruction itself. The assert checks for the latter. Problematic is
> the fact that for these type of repeating instructions, Xen seems to
> eventually just commit all register state when it encounters an exception:
>
> 557 #define put_rep_prefix(reps_completed)
> ({ \
> 558 if ( rep_prefix()
> ) \
> 559 { \
> 560 __put_rep_prefix(&_regs, ctxt->regs, ad_bytes,
> reps_completed); \
> 561 if ( unlikely(rc == X86EMUL_EXCEPTION)
> ) \
> 562 goto
> complete_insn; \
> 563 } \
> 564 })
I fear I'm not following, considering __put_rep_prefix() has
/* Reduce counter appropriately, and repeat instruction if non-zero. */
ecx -= reps_completed;
if ( ecx != 0 )
int_regs->r(ip) = ext_regs->r(ip);
> 8356 complete_insn: /* Commit shadow register state. */
> 8357 put_fpu(fpu_type, false, state, ctxt, ops);
> 8358 fpu_type = X86EMUL_FPU_none;
> 8359
> 8360 /* Zero the upper 32 bits of %rip if not in 64-bit mode. */
> 8361 if ( !mode_64bit() )
> 8362 _regs.r(ip) = (uint32_t)_regs.r(ip);
> 8363
> 8364 /* Should a singlestep #DB be raised? */
> 8365 if ( rc == X86EMUL_OKAY && singlestep && !ctxt->retire.mov_ss )
> 8366 {
> 8367 ctxt->retire.singlestep = true;
> 8368 ctxt->retire.sti = false;
> 8369 }
> 8370
> 8371 if ( rc != X86EMUL_DONE )
> 8372 *ctxt->regs = _regs; // <- Incorrect RIP is commited
>
> I've attached an XTF test that should trigger the aforementioned assert
> on the latest release commit: 3ad5d648cda5add395f49fc3704b2552aae734f7
I'll give this a try, perhaps it'll shed more light on the situation. I'd
be surprised though that the fuzzer we have in tree wouldn't have found
this (so far).
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |