wbenny / hvpp

hvpp is a lightweight Intel x64/VT-x hypervisor written in C++ focused primarily on virtualization of already running operating system
MIT License
1.11k stars 220 forks source link

proper use of mtf #39

Open purripurri opened 5 years ago

purripurri commented 5 years ago

hi wbenny, thanks for awesome project :) i am having a bit of trouble to use mtf correctly and hoped you might be able to help.

in ept violation handler sometimes i set mtf so i can change permissions again but i seem to enter an endless loop of ept violations and page permissions get screwed up. am i using it incorrectly?

//set permissions
vp.ept().map_4kb(.....)

//enable mtf 
auto procbased_ctls = vp.processor_based_controls();
procbased_ctls.monitor_trap_flag = true;
vp.processor_based_controls(procbased_ctls);

vp.suppress_rip_adjust();

return;
void vmexit_custom_handler::handle_monitor_trap_flag(vcpu_t& vp) noexcept
{
 //restore permissions
 vp.ept().map_4kb(...);

 //disable mtf
 auto procbased_ctls = vp.processor_based_controls();
 procbased_ctls.monitor_trap_flag = false;
 vp.processor_based_controls(procbased_ctls);
}
wbenny commented 5 years ago

Hi! Did you try flushing EPT in handle_monitor_trap_flag()?

purripurri commented 5 years ago

thank you for responding :) yes I did try, but seems I am still in an infinite loop of ept violation -> mtf 😕

void vmexit_custom_handler::handle_monitor_trap_flag(vcpu_t& vp) noexcept
{
  //restore permissions
  vp.ept().map_4kb(...);
  vmx::invept_single_context(vp.ept().ept_pointer());

  //disable mtf
  auto procbased_ctls = vp.processor_based_controls();
  procbased_ctls.monitor_trap_flag = false;
  vp.processor_based_controls(procbased_ctls);

}
rianquinn commented 5 years ago

I don't know if this is your issue or not as there could be several things that could cause that, but one thing that we have seen a lot with Bareflank users is that an interrupt will fire which will cause the MFT to complete on an instruction that has nothing to do with the EPT page that you are trying to monitor. As a result, you end up in an infinite loop because you think your code executed and it didn't.

purripurri commented 5 years ago

rian, thank you for your suggestion! i tested this and sadly this is not my issue. the infinite loop only seems to occur when i change page permissions again within the mtf vmexit. commenting out vp.ept().map_4kb(...); in the mtf vmexit causes it to function as expected. 🤔

rianquinn commented 5 years ago

I don't think that test proves that is not the case. If you don't reenable your EPT trap, as soon as the interrupt is complete, it will complete the instruction you intended to trap on. The only way I know to show if the infinite loop is due to an interrupt would be to store RIP and output it from the MTF handler.

Note that this inifinite loop issue with MTF (assuming you are doing the EPT stuff properly) is a common problem with VT-x. There is a whole thread about it in KVM. I personnally was able to reproduce the issue with simple instructions like rdpmc. IMO, in general, MTF should be avoided in favor of other approaches (like injecting int 3 mods in shadow pages which is a trick that DRAKVUF uses https://drakvuf.com/.... the author of that project is a good friend of mine).

purripurri commented 5 years ago

oh cool, i will gladly look into that 😄 thank you! i seem to have found my issue...and it is a rather embarrassing one. suffice it to say i was doing something very stupid with the page permissions. it is working as expected now! thank you guys!

wbenny commented 5 years ago

@rianquinn I experienced exactly what you're talking about. For my needs I've set MTF together with "blocking by mov ss"-bit, that essentially disabled interrupts for the next instruction. At that moment I've thought how elegant solution it was :)

wbenny commented 5 years ago

@purripurri Sorry for leaving you hanging for so long. Try putting vp.suppress_rip_adjust(); at the end of the MTF handler. If you won't do it, you'll end up in the infinite loop.

busy10 commented 1 year ago

"For my needs I've set MTF together with "blocking by mov ss"-bit, that essentially disabled interrupts for the next instruction. At that moment I've thought how elegant solution it was :)"

But there are some other solutions to ensure that the output exactly occurs in the same "rip"?