kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).