[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Assert in x86_emulate_wrapper triggerable by HVM domain


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Manuel Andreas <manuel.andreas@xxxxxx>
  • Date: Tue, 15 Apr 2025 23:52:10 +0200
  • Authentication-results: postout.lrz.de (amavis); dkim=pass (2048-bit key) reason="pass (just generated, assumed good)" header.d=tum.de
  • Autocrypt: addr=manuel.andreas@xxxxxx; keydata= xjMEY9Zx/RYJKwYBBAHaRw8BAQdALWzRzW9a74DX4l6i8VzXGvv72Vz0qfvj9s7bjBD905nN Jk1hbnVlbCBBbmRyZWFzIDxtYW51ZWwuYW5kcmVhc0B0dW0uZGU+wokEExYIADEWIQQuSfNX 11QV6exAUmOqZGwY4LuingUCY9Zx/QIbAwQLCQgHBRUICQoLBRYCAwEAAAoJEKpkbBjgu6Ke McQBAPyP530S365I50I5rM2XjH5Hr9YcUQATD5dusZJMDgejAP9T/wUurwQSuRfm1rK8cNcf w4wP3+PLvL+J+kuVku93CM44BGPWcf0SCisGAQQBl1UBBQEBB0AmCAf31tLBD5tvtdZ0XX1B yGLUAxhgmFskGyPhY8wOKQMBCAfCeAQYFggAIBYhBC5J81fXVBXp7EBSY6pkbBjgu6KeBQJj 1nH9AhsMAAoJEKpkbBjgu6Kej6YA/RvJdXMjsD5csifolLw53KX0/ElM22SvaGym1+KiiVND AQDy+y+bCXI+J713/AwLBsDxTEXmP7Cp49ZqbAu83NnpBQ==
  • Delivery-date: Wed, 16 Apr 2025 00:08:47 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

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.

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  })

  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

Best,
Manuel

Attachment: poc-x86emul-assert-orig-ip.tar.gz
Description: application/gzip


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.