x86: gtests: add new test for vmread/vmwrite flags preservation
PATCH RESEND 1/1 x86: gtests: add new test for vmread/vmwrite flags preservation
This commit adds new unit tests for commit a4d956b93904 ("KVM: nVMX:
vmread should not set rflags to specify success in case of #PF")
The two new tests force a vmread and a vmwrite on an unmapped address to cause a #PF and verify that the low byte of %rflags is preserved and that %rip is not advanced. The cherry-pick fixed a bug in vmread, but we include a test for vmwrite as well for completeness.
Before the aforementioned commit, the ALU flags would be incorrectly cleared and %rip would be advanced (for vmread).
--- x86/vmx.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+)
x86/vmx.c +121 -0
@@ -32,6 +32,7 @@#include "processor.h" #include "alloc_page.h" #include "vm.h" +#include "vmalloc.h" #include "desc.h" #include "vmx.h" #include "msr.h"
@@ -368,6 +369,122 @@ static void test_vmwrite_vmread(void)free_page (vmcs); } +ulong finish_fault; +u8 sentinel; +bool handler_called; +static void pf_handler (struct ex_regs *regs) +{ +// check that RIP was not improperly advanced and that the +// flags value was preserved. +report ("RIP has not been advanced!" , + regs->rip < finish_fault); +report ("The low byte of RFLAGS was preserved!" , + ((u8 )regs->rflags == ((sentinel |2 ) &0xd7 ))); + + regs->rip = finish_fault; + handler_called = true; + +} + +static void prep_flags_test_env (void **vpage,struct vmcs **vmcs,handler *old) +{ +// get an unbacked address that will cause a #PF + *vpage =alloc_vpage (); + +// set up VMCS so we have something to read from + *vmcs =alloc_page (); + +memset (*vmcs,0 ,PAGE_SIZE ); + (*vmcs)->hdr.revision_id = basic.revision; +assert (!vmcs_clear (*vmcs)); +assert (!make_vmcs_current (*vmcs)); + + *old =handle_exception (PF_VECTOR , &pf_handler); +} + +static void test_read_sentinel (void ) +{ +void *vpage; +struct vmcs *vmcs; +handler old; + +prep_flags_test_env (&vpage, &vmcs, &old); + +// set the proper label +extern char finish_read_fault; + + finish_fault = (ulong)&finish_read_fault; + +// execute the vmread instruction that will cause a #PF + handler_called = false; + asmvolatile ("movb %[byte], %%ah\n\t" +"sahf\n\t" +"vmread %[enc], %[val]; finish_read_fault:" + : [val]"=m" (*(u64 *)vpage) + : [byte]"Krm" (sentinel), + [enc]"r" ((u64 )GUEST_SEL_SS ) + :"cc" ,"ah" + ); +report ("The #PF handler was invoked" , handler_called); + +// restore old #PF handler +handle_exception (PF_VECTOR , old); +} + +static void test_vmread_flags_touch (void ) +{ +// set up the sentinel value in the flags register. we +// choose these two values because they candy-stripe +// the 5 flags that sahf sets. + sentinel =0x91 ; +test_read_sentinel (); + + sentinel =0x45 ; +test_read_sentinel (); +} + +static void test_write_sentinel (void ) +{ +void *vpage; +struct vmcs *vmcs; +handler old; + +prep_flags_test_env (&vpage, &vmcs, &old); + +// set the proper label +extern char finish_write_fault; + + finish_fault = (ulong)&finish_write_fault; + +// execute the vmwrite instruction that will cause a #PF + handler_called = false; + asmvolatile ("movb %[byte], %%ah\n\t" +"sahf\n\t" +"vmwrite %[val], %[enc]; finish_write_fault:" + : [val]"=m" (*(u64 *)vpage) + : [byte]"Krm" (sentinel), + [enc]"r" ((u64 )GUEST_SEL_SS ) + :"cc" ,"ah" + ); +report ("The #PF handler was invoked" , handler_called); + +// restore old #PF handler +handle_exception (PF_VECTOR , old); +} + +static void test_vmwrite_flags_touch (void ) +{ +// set up the sentinel value in the flags register. we +// choose these two values because they candy-stripe +// the 5 flags that sahf sets. + sentinel =0x91 ; +test_write_sentinel (); + + sentinel =0x45 ; +test_write_sentinel (); +} + +static void test_vmcs_high (void ) {struct vmcs *vmcs =alloc_page ();
@@ -1994,6 +2111,10 @@ int main(int argc, const char *argv[])test_vmcs_lifecycle ();if (test_wanted ("test_vmx_caps" , argv, argc))test_vmx_caps (); +if (test_wanted ("test_vmread_flags_touch" , argv, argc)) +test_vmread_flags_touch (); +if (test_wanted ("test_vmwrite_flags_touch" , argv, argc)) +test_vmwrite_flags_touch ();/* Balance vmxon from test_vmxon. */ vmx_off ();
Signature · 1 line
2.26.0.110.g2183baf09c-goog
s/gtest/nVMX for the shortlog. I thought this was somehow related to the Google Test framework, especially coming from a @google.com address.
Quoted 8 lines · Simon Smith
This commit adds new unit tests for commit
a4d956b93904("KVM: nVMX:
vmread should not set rflags to specify success in case of #PF")The two new tests force a vmread and a vmwrite on an unmapped address to cause a #PF and verify that the low byte of %rflags is preserved and that %rip is not advanced. The cherry-pick fixed a bug in vmread, but we include a test for vmwrite as well for completeness.
I think some of Google's process is bleeding into kvm-unit-tests, I'm pretty sure the aforementioned commit wasn't cherry-picked into Paolo's tree. :-D
Quoted 2 lines
Before the aforementioned commit, the ALU flags would be incorrectly cleared and %rip would be advanced (for vmread).
Quoted 8 lines · Sean Christopherson
s/gtest/nVMX for the shortlog. I thought this was somehow related to the Google Test framework, especially coming from a @google.com address.
Quoted 3 lines · Simon Smith
This commit adds new unit tests for commit
a4d956b93904("KVM: nVMX:
vmread should not set rflags to specify success in case of #PF")
Quoted 8 lines
Quoted 5 lines
The two new tests force a vmread and a vmwrite on an unmapped address to cause a #PF and verify that the low byte of %rflags is preserved and that %rip is not advanced. The cherry-pick fixed a bug in vmread, but we include a test for vmwrite as well for completeness.
I think some of Google's process is bleeding into kvm-unit-tests, I'm pretty sure the aforementioned commit wasn't cherry-picked into Paolo's tree. :-D
I see it in Linus' tree.
Quoted 2 lines
Quoted 2 lines
Before the aforementioned commit, the ALU flags would be incorrectly cleared and %rip would be advanced (for vmread).
Quoted 17 lines · Jim Mattson
Quoted 14 lines · Sean Christopherson
s/gtest/nVMX for the shortlog. I thought this was somehow related to the Google Test framework, especially coming from a @google.com address.
Quoted 8 lines · Simon Smith
This commit adds new unit tests for commit
a4d956b93904("KVM: nVMX:
vmread should not set rflags to specify success in case of #PF")The two new tests force a vmread and a vmwrite on an unmapped address to cause a #PF and verify that the low byte of %rflags is preserved and that %rip is not advanced. The cherry-pick fixed a bug in vmread, but we include a test for vmwrite as well for completeness.
Quoted 4 lines
Quoted 2 lines
I think some of Google's process is bleeding into kvm-unit-tests, I'm pretty sure the aforementioned commit wasn't cherry-picked into Paolo's tree. :-D
I see it in Linus' tree.
Oh, I see what you mean. s/cherry-pick/commit/.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Before the aforementioned commit, the ALU flags would be incorrectly cleared and %rip would be advanced (for vmread).