On Tue, Feb 05, 2019 at 05:34:27PM -0500, Krish Sadhukhan wrote: > According to section "Checks on VMX Controls" in Intel SDM vol 3C, the > following check is performed on vmentry of L2 guests: > > On processors that support Intel 64 architecture, the IA32_SYSENTER_ESP > field and the IA32_SYSENTER_EIP field must each contain a canonical > address. > > Signed-off-by: Krish Sadhukhan <krish.sadhukhan@xxxxxxxxxx> > Reviewed-by: Mihai Carabas <mihai.carabas@xxxxxxxxxx> > --- > x86/unittests.cfg | 6 ++++ > x86/vmx_tests.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 81 insertions(+) > > diff --git a/x86/unittests.cfg b/x86/unittests.cfg > index d7975e9..580dd8c 100644 > --- a/x86/unittests.cfg > +++ b/x86/unittests.cfg > @@ -542,6 +542,12 @@ extra_params = -cpu host,+vmx -m 2560 -append vmx_controls_test > arch = x86_64 > groups = vmx > > +[vmx_host_state_area] Personal preference, but I like vmx_host_state, i.e. drop "_area". To me "area" makes it sounds like were somehow testing an actual physical part of the VMCS. > +file = vmx.flat > +extra_params = -cpu host,+vmx -m 2560 -append vmx_host_state_area_test > +arch = x86_64 > +groups = vmx > + > [vmx_vmentry_movss_shadow_test] > file = vmx.flat > extra_params = -cpu host,+vmx -m 2560 -append vmentry_movss_shadow_test > diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c > index b69a7d9..487eb6f 100644 > --- a/x86/vmx_tests.c > +++ b/x86/vmx_tests.c > @@ -4935,6 +4935,80 @@ static void vmx_controls_test(void) > test_vm_entry_ctls(); > } > > +/* > + * On processors that support Intel 64 architecture, the IA32_SYSENTER_ESP > + * field and the IA32_SYSENTER_EIP field must each contain a canonical > + * address. > + * > + * [Intel SDM] > + */ > +static void test_host_ctl_regs(void) SYSENTER_{EIP,ESP} are MSRs, not control registers. And I don't think you need this function anyways (see bottom). > +{ > + u64 addr_saved = vmcs_read(HOST_SYSENTER_ESP); > + u64 addr = addr_saved; > + > + if (!is_canonical(addr)) { Consuming unknown prior state is a big no-no for unit tests, e.g. this behavior could cause all sorts of reproducibility problems if someone adds a test that happens to write HOST_SYSENTER_ESP. The KVM unit tests don't always do a great job of sanitizing dependent state but we should at least explicitly set the field being tested. > + report_prefix_pushf("HOST_SYSENTER_ESP non-canonical"); > + test_vmlaunch(false, false, > + VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); > + report_prefix_pop(); > + } else { > + report_prefix_pushf("HOST_SYSENTER_ESP canonical"); > + test_vmlaunch(true, false, > + VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); > + report_prefix_pop(); > + > + addr |= 1ull << 48; This will break if 5 level paging is configured, or if @addr contains a value with the upper bits set. Write a predetermined value that is guaranteed to cause a non-canonical violation. There's even a #define for this: NONCANONICAL. > + vmcs_write(HOST_SYSENTER_ESP, addr); > + report_prefix_pushf("HOST_SYSENTER_ESP non-canonical"); > + test_vmlaunch(false, false, > + VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); > + report_prefix_pop(); > + > + vmcs_write(HOST_SYSENTER_ESP, addr_saved); > + } > + > + addr_saved = vmcs_read(HOST_SYSENTER_EIP); > + addr = addr_saved; > + > + if (!is_canonical(addr)) { > + report_prefix_pushf("HOST_SYSENTER_EIP non-canonical"); > + test_vmlaunch(false, false, > + VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); > + report_prefix_pop(); > + } else { > + report_prefix_pushf("HOST_SYSENTER_EIP canonical"); > + test_vmlaunch(true, false, > + VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); > + report_prefix_pop(); > + > + addr |= 1ull << 48; > + vmcs_write(HOST_SYSENTER_EIP, addr); > + report_prefix_pushf("HOST_SYSENTER_EIP non-canonical"); > + test_vmlaunch(false, false, > + VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); > + report_prefix_pop(); > + > + vmcs_write(HOST_SYSENTER_EIP, addr_saved); > + } This code is basically identical to HOST_SYSENTER_ESP, reusing the code via a helper is trivial, e.g.: static void test_sysenter_field(u32 field, const char *name) { u64 addr_saved = vmcs_read(field); bool success; vmcs_write(field, NONCANONICAL); report_prefix_pushf("%s non-canonical", name); success = vmlaunch_succeeds(); report("vmlaunch %s", !success, "fails"); if (!success) check_vmx_instr_err(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD); report_prefix_pop(); vmcs_write(field, 0xffffffff); report_prefix_pushf("%s canonical", name); report("vmlaunch %s", success, "succeeds"); report_prefix_pop(); vmcs_write(HOST_SYSENTER_ESP, addr_saved); } > +} > + > +/* > + * Check that the virtual CPU checks the VMX Host State Area as > + * documented in the Intel SDM. > + */ > +static void vmx_host_state_area_test(void) > +{ > + /* > + * Bit 1 of the guest's RFLAGS must be 1, or VM-entry will > + * fail due to invalid guest state, should we make it that > + * far. > + */ > + vmcs_write(GUEST_RFLAGS, 0); > + > + test_host_ctl_regs(); > +} > + > static bool valid_vmcs_for_vmentry(void) > { > struct vmcs *current_vmcs = NULL; > @@ -6356,6 +6430,7 @@ struct vmx_test vmx_tests[] = { > TEST(invvpid_test_v2), > /* VM-entry tests */ > TEST(vmx_controls_test), > + TEST(vmx_host_state_area_test), > TEST(vmentry_movss_shadow_test), > /* APICv tests */ > TEST(vmx_eoi_bitmap_ioapic_scan_test), > -- > 2.17.2 >