* [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
* [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
* 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
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).