* [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID @ 2020-10-27 23:10 Oliver Upton 2020-10-27 23:10 ` [PATCH 1/6] selftests: kvm: add tsc_msrs_test binary to gitignore Oliver Upton ` (6 more replies) 0 siblings, 7 replies; 9+ messages in thread From: Oliver Upton @ 2020-10-27 23:10 UTC (permalink / raw) To: kvm; +Cc: Paolo Bonzini, Sean Christopherson, Oliver Upton Patches 1-2 address some small issues with documentation and the kvm selftests, unrelated to the overall intent of this series. Patch 3 applies the same PV MSR filtering mechanism to guest reads of KVM paravirt msrs. Patch 4 makes enabling KVM_CAP_ENFORCE_PV_FEATURE_CPUID idempotent with regards to when userspace sets the guest's CPUID, ensuring that the cached copy of KVM_CPUID_FEATURES.EAX is always current. Patch 5 fixes a regression introduced with KVM_CAP_ENFORCE_PV_CPUID, wherein the kvm masterclock isn't updated every time the guest uses a different system time msr than before. Lastly, Patch 6 introduces a test for the overall paravirtual restriction mechanism, verifying that guests GP when touching MSRs they shouldn't and get -KVM_ENOSYS when using restricted kvm hypercalls. Please note that this test is dependent upon patches 1-3 of Aaron's userspace MSR test, which add support for guest handling of the IDT in KVM selftests [1]. This series (along with Aaron's aforementioned changes) applies to commit 77377064c3a9 ("KVM: ioapic: break infinite recursion on lazy EOI"). [1] http://lore.kernel.org/r/20201012194716.3950330-1-aaronlewis@google.com Oliver Upton (6): selftests: kvm: add tsc_msrs_test binary to gitignore Documentation: kvm: fix ordering of msr filter, pv documentation kvm: x86: reads of restricted pv msrs should also result in #GP kvm: x86: ensure pv_cpuid.features is initialized when enabling cap kvm: x86: request masterclock update any time guest uses different msr selftests: kvm: test enforcement of paravirtual cpuid features Documentation/virt/kvm/api.rst | 4 +- arch/x86/kvm/cpuid.c | 23 +- arch/x86/kvm/cpuid.h | 1 + arch/x86/kvm/x86.c | 38 ++- tools/testing/selftests/kvm/.gitignore | 2 + tools/testing/selftests/kvm/Makefile | 1 + .../testing/selftests/kvm/include/kvm_util.h | 2 + .../selftests/kvm/include/x86_64/processor.h | 12 + tools/testing/selftests/kvm/lib/kvm_util.c | 28 +++ .../selftests/kvm/lib/x86_64/processor.c | 29 +++ .../selftests/kvm/x86_64/kvm_pv_test.c | 234 ++++++++++++++++++ 11 files changed, 364 insertions(+), 10 deletions(-) create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_pv_test.c -- 2.29.0.rc2.309.g374f81d7ae-goog ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/6] selftests: kvm: add tsc_msrs_test binary to gitignore 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton @ 2020-10-27 23:10 ` Oliver Upton 2020-10-27 23:10 ` [PATCH 2/6] Documentation: kvm: fix ordering of msr filter, pv documentation Oliver Upton ` (5 subsequent siblings) 6 siblings, 0 replies; 9+ messages in thread From: Oliver Upton @ 2020-10-27 23:10 UTC (permalink / raw) To: kvm; +Cc: Paolo Bonzini, Sean Christopherson, Oliver Upton Fixes: 0c899c25d754 ("KVM: x86: do not attempt TSC synchronization on guest writes") Signed-off-by: Oliver Upton <oupton@google.com> --- tools/testing/selftests/kvm/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 307ceaadbbb9..0f19f5999b88 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -15,6 +15,7 @@ /x86_64/vmx_preemption_timer_test /x86_64/svm_vmcall_test /x86_64/sync_regs_test +/x86_64/tsc_msrs_test /x86_64/vmx_close_while_nested_test /x86_64/vmx_dirty_log_test /x86_64/vmx_set_nested_state_test -- 2.29.0.rc2.309.g374f81d7ae-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/6] Documentation: kvm: fix ordering of msr filter, pv documentation 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton 2020-10-27 23:10 ` [PATCH 1/6] selftests: kvm: add tsc_msrs_test binary to gitignore Oliver Upton @ 2020-10-27 23:10 ` Oliver Upton 2020-10-27 23:10 ` [PATCH 3/6] kvm: x86: reads of restricted pv msrs should also result in #GP Oliver Upton ` (4 subsequent siblings) 6 siblings, 0 replies; 9+ messages in thread From: Oliver Upton @ 2020-10-27 23:10 UTC (permalink / raw) To: kvm; +Cc: Paolo Bonzini, Sean Christopherson, Oliver Upton, Aaron Lewis Both were added around the same time, so it seems they collide for the next heading number. Fixes: 1a155254ff93 ("KVM: x86: Introduce MSR filtering") Fixes: 66570e966dd9 ("kvm: x86: only provide PV features if enabled in guest's CPUID") Signed-off-by: Oliver Upton <oupton@google.com> Reviewed-by: Aaron Lewis <aaronlewis@google.com> --- Documentation/virt/kvm/api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 76317221d29f..fbc6a5e4585f 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6367,7 +6367,7 @@ accesses that would usually trigger a #GP by KVM into the guest will instead get bounced to user space through the KVM_EXIT_X86_RDMSR and KVM_EXIT_X86_WRMSR exit notifications. -8.25 KVM_X86_SET_MSR_FILTER +8.27 KVM_X86_SET_MSR_FILTER --------------------------- :Architectures: x86 @@ -6382,7 +6382,7 @@ trap and emulate MSRs that are outside of the scope of KVM as well as limit the attack surface on KVM's MSR emulation code. -8.26 KVM_CAP_ENFORCE_PV_CPUID +8.28 KVM_CAP_ENFORCE_PV_CPUID ----------------------------- Architectures: x86 -- 2.29.0.rc2.309.g374f81d7ae-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/6] kvm: x86: reads of restricted pv msrs should also result in #GP 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton 2020-10-27 23:10 ` [PATCH 1/6] selftests: kvm: add tsc_msrs_test binary to gitignore Oliver Upton 2020-10-27 23:10 ` [PATCH 2/6] Documentation: kvm: fix ordering of msr filter, pv documentation Oliver Upton @ 2020-10-27 23:10 ` Oliver Upton 2020-10-27 23:10 ` [PATCH 4/6] kvm: x86: ensure pv_cpuid.features is initialized when enabling cap Oliver Upton ` (3 subsequent siblings) 6 siblings, 0 replies; 9+ messages in thread From: Oliver Upton @ 2020-10-27 23:10 UTC (permalink / raw) To: kvm; +Cc: Paolo Bonzini, Sean Christopherson, Oliver Upton, Peter Shier commit 66570e966dd9 ("kvm: x86: only provide PV features if enabled in guest's CPUID") only protects against disallowed guest writes to KVM paravirtual msrs, leaving msr reads unchecked. Fix this by enforcing KVM_CPUID_FEATURES for msr reads as well. Fixes: 66570e966dd9 ("kvm: x86: only provide PV features if enabled in guest's CPUID") Signed-off-by: Oliver Upton <oupton@google.com> Reviewed-by: Peter Shier <pshier@google.com> --- arch/x86/kvm/x86.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 397f599b20e5..4016c07c8920 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3463,29 +3463,63 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vcpu->arch.efer; break; case MSR_KVM_WALL_CLOCK: + if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE)) + return 1; + + msr_info->data = vcpu->kvm->arch.wall_clock; + break; case MSR_KVM_WALL_CLOCK_NEW: + if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE2)) + return 1; + msr_info->data = vcpu->kvm->arch.wall_clock; break; case MSR_KVM_SYSTEM_TIME: + if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE)) + return 1; + + msr_info->data = vcpu->arch.time; + break; case MSR_KVM_SYSTEM_TIME_NEW: + if (!guest_pv_has(vcpu, KVM_FEATURE_CLOCKSOURCE2)) + return 1; + msr_info->data = vcpu->arch.time; break; case MSR_KVM_ASYNC_PF_EN: + if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF)) + return 1; + msr_info->data = vcpu->arch.apf.msr_en_val; break; case MSR_KVM_ASYNC_PF_INT: + if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF_INT)) + return 1; + msr_info->data = vcpu->arch.apf.msr_int_val; break; case MSR_KVM_ASYNC_PF_ACK: + if (!guest_pv_has(vcpu, KVM_FEATURE_ASYNC_PF)) + return 1; + msr_info->data = 0; break; case MSR_KVM_STEAL_TIME: + if (!guest_pv_has(vcpu, KVM_FEATURE_STEAL_TIME)) + return 1; + msr_info->data = vcpu->arch.st.msr_val; break; case MSR_KVM_PV_EOI_EN: + if (!guest_pv_has(vcpu, KVM_FEATURE_PV_EOI)) + return 1; + msr_info->data = vcpu->arch.pv_eoi.msr_val; break; case MSR_KVM_POLL_CONTROL: + if (!guest_pv_has(vcpu, KVM_FEATURE_POLL_CONTROL)) + return 1; + msr_info->data = vcpu->arch.msr_kvm_poll_control; break; case MSR_IA32_P5_MC_ADDR: -- 2.29.0.rc2.309.g374f81d7ae-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/6] kvm: x86: ensure pv_cpuid.features is initialized when enabling cap 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton ` (2 preceding siblings ...) 2020-10-27 23:10 ` [PATCH 3/6] kvm: x86: reads of restricted pv msrs should also result in #GP Oliver Upton @ 2020-10-27 23:10 ` Oliver Upton 2020-10-27 23:10 ` [PATCH 5/6] kvm: x86: request masterclock update any time guest uses different msr Oliver Upton ` (2 subsequent siblings) 6 siblings, 0 replies; 9+ messages in thread From: Oliver Upton @ 2020-10-27 23:10 UTC (permalink / raw) To: kvm; +Cc: Paolo Bonzini, Sean Christopherson, Oliver Upton, Peter Shier Make the paravirtual cpuid enforcement mechanism idempotent to ioctl() ordering by updating pv_cpuid.features whenever userspace requests the capability. Extract this update out of kvm_update_cpuid_runtime() into a new helper function and move its other call site into kvm_vcpu_after_set_cpuid() where it more likely belongs. Fixes: 66570e966dd9 ("kvm: x86: only provide PV features if enabled in guest's CPUID") Signed-off-by: Oliver Upton <oupton@google.com> Reviewed-by: Peter Shier <pshier@google.com> --- arch/x86/kvm/cpuid.c | 23 ++++++++++++++++------- arch/x86/kvm/cpuid.h | 1 + arch/x86/kvm/x86.c | 2 ++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 06a278b3701d..d50041f570e8 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -90,6 +90,20 @@ static int kvm_check_cpuid(struct kvm_cpuid_entry2 *entries, int nent) return 0; } +void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *best; + + best = kvm_find_cpuid_entry(vcpu, KVM_CPUID_FEATURES, 0); + + /* + * save the feature bitmap to avoid cpuid lookup for every PV + * operation + */ + if (best) + vcpu->arch.pv_cpuid.features = best->eax; +} + void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; @@ -124,13 +138,6 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu) (best->eax & (1 << KVM_FEATURE_PV_UNHALT))) best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT); - /* - * save the feature bitmap to avoid cpuid lookup for every PV - * operation - */ - if (best) - vcpu->arch.pv_cpuid.features = best->eax; - if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) { best = kvm_find_cpuid_entry(vcpu, 0x1, 0); if (best) @@ -162,6 +169,8 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.guest_supported_xcr0 = (best->eax | ((u64)best->edx << 32)) & supported_xcr0; + kvm_update_pv_runtime(vcpu); + vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu); kvm_mmu_reset_context(vcpu); diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index bf8577947ed2..f7a6e8f83783 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -11,6 +11,7 @@ extern u32 kvm_cpu_caps[NCAPINTS] __read_mostly; void kvm_set_cpu_caps(void); void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu); +void kvm_update_pv_runtime(struct kvm_vcpu *vcpu); struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, u32 function, u32 index); int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4016c07c8920..2970045a885e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4609,6 +4609,8 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, case KVM_CAP_ENFORCE_PV_FEATURE_CPUID: vcpu->arch.pv_cpuid.enforce = cap->args[0]; + if (vcpu->arch.pv_cpuid.enforce) + kvm_update_pv_runtime(vcpu); return 0; -- 2.29.0.rc2.309.g374f81d7ae-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/6] kvm: x86: request masterclock update any time guest uses different msr 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton ` (3 preceding siblings ...) 2020-10-27 23:10 ` [PATCH 4/6] kvm: x86: ensure pv_cpuid.features is initialized when enabling cap Oliver Upton @ 2020-10-27 23:10 ` Oliver Upton 2020-11-06 12:43 ` Paolo Bonzini 2020-10-27 23:10 ` [PATCH 6/6] selftests: kvm: test enforcement of paravirtual cpuid features Oliver Upton 2020-11-03 7:50 ` [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton 6 siblings, 1 reply; 9+ messages in thread From: Oliver Upton @ 2020-10-27 23:10 UTC (permalink / raw) To: kvm; +Cc: Paolo Bonzini, Sean Christopherson, Oliver Upton, Peter Shier commit 66570e966dd9 ("kvm: x86: only provide PV features if enabled in guest's CPUID") subtly changed the behavior of guest writes to MSR_KVM_SYSTEM_TIME(_NEW). Restore the previous behavior; update the masterclock any time the guest uses a different msr than before. Fixes: 66570e966dd9 ("kvm: x86: only provide PV features if enabled in guest's CPUID") Signed-off-by: Oliver Upton <oupton@google.com> Reviewed-by: Peter Shier <pshier@google.com> --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2970045a885e..4f7dce1b1447 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1965,7 +1965,7 @@ static void kvm_write_system_time(struct kvm_vcpu *vcpu, gpa_t system_time, struct kvm_arch *ka = &vcpu->kvm->arch; if (vcpu->vcpu_id == 0 && !host_initiated) { - if (ka->boot_vcpu_runs_old_kvmclock && old_msr) + if (ka->boot_vcpu_runs_old_kvmclock != old_msr) kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); ka->boot_vcpu_runs_old_kvmclock = old_msr; -- 2.29.0.rc2.309.g374f81d7ae-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 5/6] kvm: x86: request masterclock update any time guest uses different msr 2020-10-27 23:10 ` [PATCH 5/6] kvm: x86: request masterclock update any time guest uses different msr Oliver Upton @ 2020-11-06 12:43 ` Paolo Bonzini 0 siblings, 0 replies; 9+ messages in thread From: Paolo Bonzini @ 2020-11-06 12:43 UTC (permalink / raw) To: Oliver Upton, kvm; +Cc: Sean Christopherson, Peter Shier On 28/10/20 00:10, Oliver Upton wrote: > commit 66570e966dd9 ("kvm: x86: only provide PV features if enabled in > guest's CPUID") subtly changed the behavior of guest writes to > MSR_KVM_SYSTEM_TIME(_NEW). Restore the previous behavior; update the > masterclock any time the guest uses a different msr than before. > > Fixes: 66570e966dd9 ("kvm: x86: only provide PV features if enabled in guest's CPUID") > Signed-off-by: Oliver Upton<oupton@google.com> > Reviewed-by: Peter Shier<pshier@google.com> > --- Actually commit 5b9bb0ebbcdc ("kvm: x86: encapsulate wrmsr(MSR_KVM_SYSTEM_TIME) emulation in helper fn", 2020-10-21). Paolo ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 6/6] selftests: kvm: test enforcement of paravirtual cpuid features 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton ` (4 preceding siblings ...) 2020-10-27 23:10 ` [PATCH 5/6] kvm: x86: request masterclock update any time guest uses different msr Oliver Upton @ 2020-10-27 23:10 ` Oliver Upton 2020-11-03 7:50 ` [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton 6 siblings, 0 replies; 9+ messages in thread From: Oliver Upton @ 2020-10-27 23:10 UTC (permalink / raw) To: kvm Cc: Paolo Bonzini, Sean Christopherson, Oliver Upton, Jim Mattson, Peter Shier, Aaron Lewis Add a set of tests that ensure the guest cannot access paravirtual msrs and hypercalls that have been disabled in the KVM_CPUID_FEATURES leaf. Expect a #GP in the case of msr accesses and -KVM_ENOSYS from hypercalls. Cc: Jim Mattson <jmattson@google.com> Signed-off-by: Oliver Upton <oupton@google.com> Reviewed-by: Peter Shier <pshier@google.com> Reviewed-by: Aaron Lewis <aaronlewis@google.com> --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../testing/selftests/kvm/include/kvm_util.h | 2 + .../selftests/kvm/include/x86_64/processor.h | 12 + tools/testing/selftests/kvm/lib/kvm_util.c | 28 +++ .../selftests/kvm/lib/x86_64/processor.c | 29 +++ .../selftests/kvm/x86_64/kvm_pv_test.c | 234 ++++++++++++++++++ 7 files changed, 307 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_pv_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 0f19f5999b88..a10f58a94ff4 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -5,6 +5,7 @@ /x86_64/cr4_cpuid_sync_test /x86_64/debug_regs /x86_64/evmcs_test +/x86_64/kvm_pv_test /x86_64/hyperv_cpuid /x86_64/mmio_warning_test /x86_64/platform_info_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 7ebe71fbca53..23f51e1c21be 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -41,6 +41,7 @@ LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid +TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 919e161dd289..a288afefde56 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -63,6 +63,8 @@ enum vm_mem_backing_src_type { int kvm_check_cap(long cap); int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap); +int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_enable_cap *cap); struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); struct kvm_vm *_vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 82b7fe16a824..936380e1c590 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -338,6 +338,18 @@ uint32_t kvm_get_cpuid_max_basic(void); uint32_t kvm_get_cpuid_max_extended(void); void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits); +/* + * set_cpuid() - overwrites a matching cpuid entry with the provided value. + * matches based on ent->function && ent->index. returns true + * if a match was found and successfully overwritten. + * @cpuid: the kvm cpuid list to modify. + * @ent: cpuid entry to insert + */ +bool set_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *ent); + +uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3); + /* * Basic CPU control in CR0 */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 74776ee228f2..706b19445acc 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -85,6 +85,34 @@ int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) return ret; } +/* VCPU Enable Capability + * + * Input Args: + * vm - Virtual Machine + * vcpu_id - VCPU + * cap - Capability + * + * Output Args: None + * + * Return: On success, 0. On failure a TEST_ASSERT failure is produced. + * + * Enables a capability (KVM_CAP_*) on the VCPU. + */ +int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_enable_cap *cap) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpu_id); + int r; + + TEST_ASSERT(vcpu, "cannot find vcpu %d", vcpu_id); + + r = ioctl(vcpu->fd, KVM_ENABLE_CAP, cap); + TEST_ASSERT(!r, "KVM_ENABLE_CAP vCPU ioctl failed,\n" + " rc: %i, errno: %i", r, errno); + + return r; +} + static void vm_open(struct kvm_vm *vm, int perm) { vm->kvm_fd = open(KVM_DEV_PATH, perm); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index f6eb34eaa0d2..a20bdc6b1228 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1118,3 +1118,32 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits) *va_bits = (entry->eax >> 8) & 0xff; } } + +bool set_cpuid(struct kvm_cpuid2 *cpuid, + struct kvm_cpuid_entry2 *ent) +{ + int i; + + for (i = 0; i < cpuid->nent; i++) { + struct kvm_cpuid_entry2 *cur = &cpuid->entries[i]; + + if (cur->function != ent->function || cur->index != ent->index) + continue; + + memcpy(cur, ent, sizeof(struct kvm_cpuid_entry2)); + return true; + } + + return false; +} + +uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3) +{ + uint64_t r; + + asm volatile("vmcall" + : "=a"(r) + : "b"(a0), "c"(a1), "d"(a2), "S"(a3)); + return r; +} diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c new file mode 100644 index 000000000000..b10a27485bad --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020, Google LLC. + * + * Tests for KVM paravirtual feature disablement + */ +#include <asm/kvm_para.h> +#include <linux/kvm_para.h> +#include <stdint.h> + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +extern unsigned char rdmsr_start; +extern unsigned char rdmsr_end; + +static u64 do_rdmsr(u32 idx) +{ + u32 lo, hi; + + asm volatile("rdmsr_start: rdmsr;" + "rdmsr_end:" + : "=a"(lo), "=c"(hi) + : "c"(idx)); + + return (((u64) hi) << 32) | lo; +} + +extern unsigned char wrmsr_start; +extern unsigned char wrmsr_end; + +static void do_wrmsr(u32 idx, u64 val) +{ + u32 lo, hi; + + lo = val; + hi = val >> 32; + + asm volatile("wrmsr_start: wrmsr;" + "wrmsr_end:" + : : "a"(lo), "c"(idx), "d"(hi)); +} + +static int nr_gp; + +static void guest_gp_handler(struct ex_regs *regs) +{ + unsigned char *rip = (unsigned char *)regs->rip; + bool r, w; + + r = rip == &rdmsr_start; + w = rip == &wrmsr_start; + GUEST_ASSERT(r || w); + + nr_gp++; + + if (r) + regs->rip = (uint64_t)&rdmsr_end; + else + regs->rip = (uint64_t)&wrmsr_end; +} + +struct msr_data { + uint32_t idx; + const char *name; +}; + +#define TEST_MSR(msr) { .idx = msr, .name = #msr } +#define UCALL_PR_MSR 0xdeadbeef +#define PR_MSR(msr) ucall(UCALL_PR_MSR, 1, msr) + +/* + * KVM paravirtual msrs to test. Expect a #GP if any of these msrs are read or + * written, as the KVM_CPUID_FEATURES leaf is cleared. + */ +static struct msr_data msrs_to_test[] = { + TEST_MSR(MSR_KVM_SYSTEM_TIME), + TEST_MSR(MSR_KVM_SYSTEM_TIME_NEW), + TEST_MSR(MSR_KVM_WALL_CLOCK), + TEST_MSR(MSR_KVM_WALL_CLOCK_NEW), + TEST_MSR(MSR_KVM_ASYNC_PF_EN), + TEST_MSR(MSR_KVM_STEAL_TIME), + TEST_MSR(MSR_KVM_PV_EOI_EN), + TEST_MSR(MSR_KVM_POLL_CONTROL), + TEST_MSR(MSR_KVM_ASYNC_PF_INT), + TEST_MSR(MSR_KVM_ASYNC_PF_ACK), +}; + +static void test_msr(struct msr_data *msr) +{ + PR_MSR(msr); + do_rdmsr(msr->idx); + GUEST_ASSERT(READ_ONCE(nr_gp) == 1); + + nr_gp = 0; + do_wrmsr(msr->idx, 0); + GUEST_ASSERT(READ_ONCE(nr_gp) == 1); + nr_gp = 0; +} + +struct hcall_data { + uint64_t nr; + const char *name; +}; + +#define TEST_HCALL(hc) { .nr = hc, .name = #hc } +#define UCALL_PR_HCALL 0xdeadc0de +#define PR_HCALL(hc) ucall(UCALL_PR_HCALL, 1, hc) + +/* + * KVM hypercalls to test. Expect -KVM_ENOSYS when called, as the corresponding + * features have been cleared in KVM_CPUID_FEATURES. + */ +static struct hcall_data hcalls_to_test[] = { + TEST_HCALL(KVM_HC_KICK_CPU), + TEST_HCALL(KVM_HC_SEND_IPI), + TEST_HCALL(KVM_HC_SCHED_YIELD), +}; + +static void test_hcall(struct hcall_data *hc) +{ + uint64_t r; + + PR_HCALL(hc); + r = kvm_hypercall(hc->nr, 0, 0, 0, 0); + GUEST_ASSERT(r == -KVM_ENOSYS); +} + +static void guest_main(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(msrs_to_test); i++) { + test_msr(&msrs_to_test[i]); + } + + for (i = 0; i < ARRAY_SIZE(hcalls_to_test); i++) { + test_hcall(&hcalls_to_test[i]); + } + + GUEST_DONE(); +} + +static void clear_kvm_cpuid_features(struct kvm_cpuid2 *cpuid) +{ + struct kvm_cpuid_entry2 ent = {0}; + + ent.function = KVM_CPUID_FEATURES; + TEST_ASSERT(set_cpuid(cpuid, &ent), + "failed to clear KVM_CPUID_FEATURES leaf"); +} + +static void pr_msr(struct ucall *uc) +{ + struct msr_data *msr = (struct msr_data *)uc->args[0]; + + pr_info("testing msr: %s (%#x)\n", msr->name, msr->idx); +} + +static void pr_hcall(struct ucall *uc) +{ + struct hcall_data *hc = (struct hcall_data *)uc->args[0]; + + pr_info("testing hcall: %s (%lu)\n", hc->name, hc->nr); +} + +static void handle_abort(struct ucall *uc) +{ + TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], + __FILE__, uc->args[1]); +} + +#define VCPU_ID 0 + +static void enter_guest(struct kvm_vm *vm) +{ + struct kvm_run *run; + struct ucall uc; + int r; + + run = vcpu_state(vm, VCPU_ID); + + while (true) { + r = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(!r, "vcpu_run failed: %d\n", r); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "unexpected exit reason: %u (%s)", + run->exit_reason, exit_reason_str(run->exit_reason)); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_PR_MSR: + pr_msr(&uc); + break; + case UCALL_PR_HCALL: + pr_hcall(&uc); + break; + case UCALL_ABORT: + handle_abort(&uc); + return; + case UCALL_DONE: + return; + } + } +} + +int main(void) +{ + struct kvm_enable_cap cap = {0}; + struct kvm_cpuid2 *best; + struct kvm_vm *vm; + + if (!kvm_check_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID)) { + pr_info("will skip kvm paravirt restriction tests.\n"); + return 0; + } + + vm = vm_create_default(VCPU_ID, 0, guest_main); + + cap.cap = KVM_CAP_ENFORCE_PV_FEATURE_CPUID; + cap.args[0] = 1; + vcpu_enable_cap(vm, VCPU_ID, &cap); + + best = kvm_get_supported_cpuid(); + clear_kvm_cpuid_features(best); + vcpu_set_cpuid(vm, VCPU_ID, best); + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vm, VCPU_ID); + vm_handle_exception(vm, GP_VECTOR, guest_gp_handler); + + enter_guest(vm); + kvm_vm_free(vm); +} -- 2.29.0.rc2.309.g374f81d7ae-goog ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton ` (5 preceding siblings ...) 2020-10-27 23:10 ` [PATCH 6/6] selftests: kvm: test enforcement of paravirtual cpuid features Oliver Upton @ 2020-11-03 7:50 ` Oliver Upton 6 siblings, 0 replies; 9+ messages in thread From: Oliver Upton @ 2020-11-03 7:50 UTC (permalink / raw) To: kvm list; +Cc: Paolo Bonzini, Sean Christopherson Friendly ping (this series contains bugfixes) On Tue, Oct 27, 2020 at 4:10 PM Oliver Upton <oupton@google.com> wrote: > > Patches 1-2 address some small issues with documentation and the kvm selftests, > unrelated to the overall intent of this series. > > Patch 3 applies the same PV MSR filtering mechanism to guest reads of KVM > paravirt msrs. > > Patch 4 makes enabling KVM_CAP_ENFORCE_PV_FEATURE_CPUID idempotent with regards > to when userspace sets the guest's CPUID, ensuring that the cached copy of > KVM_CPUID_FEATURES.EAX is always current. > > Patch 5 fixes a regression introduced with KVM_CAP_ENFORCE_PV_CPUID, wherein > the kvm masterclock isn't updated every time the guest uses a different system > time msr than before. > > Lastly, Patch 6 introduces a test for the overall paravirtual restriction > mechanism, verifying that guests GP when touching MSRs they shouldn't and > get -KVM_ENOSYS when using restricted kvm hypercalls. Please note that this test > is dependent upon patches 1-3 of Aaron's userspace MSR test, which add support > for guest handling of the IDT in KVM selftests [1]. > > This series (along with Aaron's aforementioned changes) applies to > commit 77377064c3a9 ("KVM: ioapic: break infinite recursion on lazy > EOI"). > > [1] http://lore.kernel.org/r/20201012194716.3950330-1-aaronlewis@google.com > > Oliver Upton (6): > selftests: kvm: add tsc_msrs_test binary to gitignore > Documentation: kvm: fix ordering of msr filter, pv documentation > kvm: x86: reads of restricted pv msrs should also result in #GP > kvm: x86: ensure pv_cpuid.features is initialized when enabling cap > kvm: x86: request masterclock update any time guest uses different msr > selftests: kvm: test enforcement of paravirtual cpuid features > > Documentation/virt/kvm/api.rst | 4 +- > arch/x86/kvm/cpuid.c | 23 +- > arch/x86/kvm/cpuid.h | 1 + > arch/x86/kvm/x86.c | 38 ++- > tools/testing/selftests/kvm/.gitignore | 2 + > tools/testing/selftests/kvm/Makefile | 1 + > .../testing/selftests/kvm/include/kvm_util.h | 2 + > .../selftests/kvm/include/x86_64/processor.h | 12 + > tools/testing/selftests/kvm/lib/kvm_util.c | 28 +++ > .../selftests/kvm/lib/x86_64/processor.c | 29 +++ > .../selftests/kvm/x86_64/kvm_pv_test.c | 234 ++++++++++++++++++ > 11 files changed, 364 insertions(+), 10 deletions(-) > create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_pv_test.c > > -- > 2.29.0.rc2.309.g374f81d7ae-goog > ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2020-11-06 12:43 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-10-27 23:10 [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton 2020-10-27 23:10 ` [PATCH 1/6] selftests: kvm: add tsc_msrs_test binary to gitignore Oliver Upton 2020-10-27 23:10 ` [PATCH 2/6] Documentation: kvm: fix ordering of msr filter, pv documentation Oliver Upton 2020-10-27 23:10 ` [PATCH 3/6] kvm: x86: reads of restricted pv msrs should also result in #GP Oliver Upton 2020-10-27 23:10 ` [PATCH 4/6] kvm: x86: ensure pv_cpuid.features is initialized when enabling cap Oliver Upton 2020-10-27 23:10 ` [PATCH 5/6] kvm: x86: request masterclock update any time guest uses different msr Oliver Upton 2020-11-06 12:43 ` Paolo Bonzini 2020-10-27 23:10 ` [PATCH 6/6] selftests: kvm: test enforcement of paravirtual cpuid features Oliver Upton 2020-11-03 7:50 ` [PATCH 0/6] Some fixes and a test for KVM_CAP_ENFORCE_PV_CPUID Oliver Upton
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).