<div dir="ltr"><div><div><div><div><div><div><div><div>Hi,<br><br></div>I've made a fix for this bug <a href="https://www.virtualbox.org/ticket/10947" target="_blank">https://www.virtualbox.org/ticket/10947</a>.
Mentioned ticket isn't very descriptive so I will try to explain this
issue a little bit more in detail. First of all this problem occurs only
when VT-x is enabled. Basically some instructions don't generate
expected single step exception after they are executed with the trap
flag being set. The behaviour is observed that such instructions are
executed under the control of the guest system but single step exception
is generated after the next instruction. This is a well known bug
amongst malware researchers and malware authors who can easily take
advantage of this fact in order to detect virtualized environment.<br>
<br></div>It turns out that the problem lies in the way VirtualBox
handles some VM exits initiated by the execution of certain
instructions. Several instructions can never be executed in VMX non-root
operation and those need to be emulated and skipped within VM exit
handlers by adjusting RIP. Unfortunately the code lacks necessary check
for the trap flag being set, so it doesn't inject expected exception
into the guest.<br>
<br></div><div>Here's the fix:<br></div><span style="font-family:courier new,monospace">*** src\VBox\VMM\VMMR0\HMVMXR0_original.cpp 2013-11-01 18:58:26.000000000 +0100<br>--- </span><span style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">src\VBox\VMM\VMMR0\</span>HMVMXR0_fixed.cpp 2013-11-08 20:24:30.578125000 +0100<br>
***************<br>*** 8166,8181 ****<br>--- 8166,8190 ----<br> DECLINLINE(int) hmR0VmxAdvanceGuestRip(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)<br> {<br> int rc = hmR0VmxReadExitInstrLenVmcs(pVCpu, pVmxTransient);<br>
rc |= hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);<br> AssertRCReturn(rc, rc);<br> <br> pMixedCtx->rip += pVmxTransient->cbInstr;<br> VMCPU_HMCF_SET(pVCpu, HM_CHANGED_GUEST_RIP);<br>+ <br>+ X86EFLAGS Eflags;<br>
+ rc = VMXReadVmcs32(VMX_VMCS_GUEST_RFLAGS, &Eflags.u32);<br>+ AssertRCReturn(rc, rc);<br>+ if (Eflags.Bits.u1TF)<br>+ {<br>+ hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx);<br>+ }<br>+ <br>
return rc;<br> }</span><br> <br></div>This fix ensures correct
handling of mentioned condition in all 13 affected VM exit handlers:
VMX_EXIT_CPUID, VMX_EXIT_RDTSC, VMX_EXIT_RDTSCP, VMX_EXIT_RDPMC,
VMX_EXIT_MOV_CRX, VMX_EXIT_MOV_DRX, VMX_EXIT_MWAIT, VMX_EXIT_MONITOR,
VMX_EXIT_RDMSR, VMX_EXIT_WRMSR, VMX_EXIT_INVD, VMX_EXIT_INVLPG,
VMX_EXIT_WBINVD.<br>
<br></div>In the attachment I provided a simple program which can be
used to test this condition on 2 representative instructions: CPUID and
RDTSC. I picked those because they don't require CPL = 0.<br><br></div>I release this patch and test program under MIT license.<br>
<br></div>Best regards,<br></div>Konrad</div>