linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] kvm: x86: Introduce hypercall x86 ops for handling hypercall not in cpl0
       [not found] <cover.1631186996.git.houwenlong93@linux.alibaba.com>
@ 2021-09-09 11:37 ` Hou Wenlong
  2021-09-09 11:37 ` [PATCH 2/3] kvm: x86: Refactor kvm_emulate_hypercall() to no skip instruction Hou Wenlong
  2021-09-09 11:37 ` [PATCH 3/3] kvm: x86: Emulate hypercall instead of fixing hypercall instruction Hou Wenlong
  2 siblings, 0 replies; 3+ messages in thread
From: Hou Wenlong @ 2021-09-09 11:37 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	H. Peter Anvin, Jan Kiszka, Avi Kivity,
	open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)

Per Intel's SDM, use vmcall instruction in non VMX operation for cpl3
it should trigger a #UD. And in VMX root operation, it should
trigger a #GP for cpl3. So hypervisor could inject such exceptions
for guest cpl3 to act like host.

Per AMD's APM, no cpl check for vmmcall instruction. But use it
in host can trigger a #UD, so hypervisor is suitable to inject a #UD.

Fixes: 07708c4af1346 ("KVM: x86: Disallow hypercalls for guest callers in rings > 0")
Signed-off-by: Hou Wenlong <houwenlong93@linux.alibaba.com>
---
 arch/x86/include/asm/kvm-x86-ops.h | 1 +
 arch/x86/include/asm/kvm_host.h    | 1 +
 arch/x86/kvm/svm/svm.c             | 5 +++++
 arch/x86/kvm/vmx/vmx.c             | 9 +++++++++
 arch/x86/kvm/x86.c                 | 6 +++---
 5 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index cefe1d81e2e8..00a8b8c80cb0 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -60,6 +60,7 @@ KVM_X86_OP_NULL(update_emulated_instruction)
 KVM_X86_OP(set_interrupt_shadow)
 KVM_X86_OP(get_interrupt_shadow)
 KVM_X86_OP(patch_hypercall)
+KVM_X86_OP(handle_hypercall_fail)
 KVM_X86_OP(set_irq)
 KVM_X86_OP(set_nmi)
 KVM_X86_OP(queue_exception)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f8f48a7ec577..3548c8047820 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1369,6 +1369,7 @@ struct kvm_x86_ops {
 	u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu);
 	void (*patch_hypercall)(struct kvm_vcpu *vcpu,
 				unsigned char *hypercall_addr);
+	void (*handle_hypercall_fail)(struct kvm_vcpu *vcpu);
 	void (*set_irq)(struct kvm_vcpu *vcpu);
 	void (*set_nmi)(struct kvm_vcpu *vcpu);
 	void (*queue_exception)(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 1a70e11f0487..1a8615bb35db 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3944,6 +3944,11 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
 	hypercall[2] = 0xd9;
 }
 
+static void svm_handl_hypercall_fail(struct kvm_vcpu *vcpu)
+{
+	kvm_queue_exception(vpcu, UD_VECTOR);
+}
+
 static int __init svm_check_processor_compat(void)
 {
 	return 0;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 0c2c0d5ae873..3bd66eb46309 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4921,6 +4921,14 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
 	hypercall[2] = 0xc1;
 }
 
+static void vmx_handle_hypercall_fail(struct kvm_vcpu *vcpu)
+{
+	if (to_vmx(vcpu)->nested.vmxon)
+		kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
+	else
+		kvm_queue_exception(vcpu, UD_VECTOR);
+}
+
 /* called to set cr0 as appropriate for a mov-to-cr0 exit. */
 static int handle_set_cr0(struct kvm_vcpu *vcpu, unsigned long val)
 {
@@ -7606,6 +7614,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
 	.set_interrupt_shadow = vmx_set_interrupt_shadow,
 	.get_interrupt_shadow = vmx_get_interrupt_shadow,
 	.patch_hypercall = vmx_patch_hypercall,
+	.handle_hypercall_fail = vmx_handle_hypercall_fail,
 	.set_irq = vmx_inject_irq,
 	.set_nmi = vmx_inject_nmi,
 	.queue_exception = vmx_queue_exception,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 28ef14155726..4e2836b94a01 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8665,8 +8665,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 	}
 
 	if (static_call(kvm_x86_get_cpl)(vcpu) != 0) {
-		ret = -KVM_EPERM;
-		goto out;
+		static_call(kvm_x86_handle_hypercall_fail)(vcpu);
+		return 1;
 	}
 
 	ret = -KVM_ENOSYS;
@@ -8727,7 +8727,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 		ret = -KVM_ENOSYS;
 		break;
 	}
-out:
+
 	if (!op_64_bit)
 		ret = (u32)ret;
 	kvm_rax_write(vcpu, ret);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/3] kvm: x86: Refactor kvm_emulate_hypercall() to no skip instruction
       [not found] <cover.1631186996.git.houwenlong93@linux.alibaba.com>
  2021-09-09 11:37 ` [PATCH 1/3] kvm: x86: Introduce hypercall x86 ops for handling hypercall not in cpl0 Hou Wenlong
@ 2021-09-09 11:37 ` Hou Wenlong
  2021-09-09 11:37 ` [PATCH 3/3] kvm: x86: Emulate hypercall instead of fixing hypercall instruction Hou Wenlong
  2 siblings, 0 replies; 3+ messages in thread
From: Hou Wenlong @ 2021-09-09 11:37 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	H. Peter Anvin, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)

Refactor kvm_emulate_hypercall() to no skip instruction, it can
be used in next patch for emulating hypercall in instruction
emulation.

Signed-off-by: Hou Wenlong <houwenlong93@linux.alibaba.com>
---
 arch/x86/kvm/x86.c | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4e2836b94a01..b8d799e1c57c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8636,17 +8636,11 @@ static int complete_hypercall_exit(struct kvm_vcpu *vcpu)
 	return kvm_skip_emulated_instruction(vcpu);
 }
 
-int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
+static int kvm_emulate_hypercall_noskip(struct kvm_vcpu *vcpu)
 {
 	unsigned long nr, a0, a1, a2, a3, ret;
 	int op_64_bit;
 
-	if (kvm_xen_hypercall_enabled(vcpu->kvm))
-		return kvm_xen_hypercall(vcpu);
-
-	if (kvm_hv_hypercall_enabled(vcpu))
-		return kvm_hv_hypercall(vcpu);
-
 	nr = kvm_rax_read(vcpu);
 	a0 = kvm_rbx_read(vcpu);
 	a1 = kvm_rcx_read(vcpu);
@@ -8664,11 +8658,6 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 		a3 &= 0xFFFFFFFF;
 	}
 
-	if (static_call(kvm_x86_get_cpl)(vcpu) != 0) {
-		static_call(kvm_x86_handle_hypercall_fail)(vcpu);
-		return 1;
-	}
-
 	ret = -KVM_ENOSYS;
 
 	switch (nr) {
@@ -8733,7 +8722,28 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 	kvm_rax_write(vcpu, ret);
 
 	++vcpu->stat.hypercalls;
-	return kvm_skip_emulated_instruction(vcpu);
+	return 1;
+}
+
+int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
+{
+	int ret;
+
+	if (kvm_xen_hypercall_enabled(vcpu->kvm))
+		return kvm_xen_hypercall(vcpu);
+
+	if (kvm_hv_hypercall_enabled(vcpu))
+		return kvm_hv_hypercall(vcpu);
+
+	if (static_call(kvm_x86_get_cpl)(vcpu) != 0) {
+		static_call(kvm_x86_handle_hypercall_fail)(vcpu);
+		return 1;
+	}
+
+	ret = kvm_emulate_hypercall_noskip(vcpu);
+	if (ret)
+		return kvm_skip_emulated_instruction(vcpu);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_hypercall);
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 3/3] kvm: x86: Emulate hypercall instead of fixing hypercall instruction
       [not found] <cover.1631186996.git.houwenlong93@linux.alibaba.com>
  2021-09-09 11:37 ` [PATCH 1/3] kvm: x86: Introduce hypercall x86 ops for handling hypercall not in cpl0 Hou Wenlong
  2021-09-09 11:37 ` [PATCH 2/3] kvm: x86: Refactor kvm_emulate_hypercall() to no skip instruction Hou Wenlong
@ 2021-09-09 11:37 ` Hou Wenlong
  2 siblings, 0 replies; 3+ messages in thread
From: Hou Wenlong @ 2021-09-09 11:37 UTC (permalink / raw)
  To: kvm
  Cc: Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li,
	Jim Mattson, Joerg Roedel, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	H. Peter Anvin, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)

It is guest's resposibility to use right instruction for hypercall,
hypervisor could emulate wrong instruction instead of modifying
guest's instruction.

Signed-off-by: Hou Wenlong <houwenlong93@linux.alibaba.com>
---
 arch/x86/kvm/emulate.c     | 20 +++++++++-----------
 arch/x86/kvm/kvm_emulate.h |  2 +-
 arch/x86/kvm/x86.c         | 17 ++++++++---------
 3 files changed, 18 insertions(+), 21 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 2837110e66ed..671008a4ee20 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3732,13 +3732,11 @@ static int em_clts(struct x86_emulate_ctxt *ctxt)
 
 static int em_hypercall(struct x86_emulate_ctxt *ctxt)
 {
-	int rc = ctxt->ops->fix_hypercall(ctxt);
+	int rc = ctxt->ops->hypercall(ctxt);
 
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
 
-	/* Let the processor re-execute the fixed hypercall */
-	ctxt->_eip = ctxt->eip;
 	/* Disable writeback. */
 	ctxt->dst.type = OP_NONE;
 	return X86EMUL_CONTINUE;
@@ -4298,14 +4296,14 @@ static const struct opcode group7_rm2[] = {
 };
 
 static const struct opcode group7_rm3[] = {
-	DIP(SrcNone | Prot | Priv,		vmrun,		check_svme_pa),
-	II(SrcNone  | Prot | EmulateOnUD,	em_hypercall,	vmmcall),
-	DIP(SrcNone | Prot | Priv,		vmload,		check_svme_pa),
-	DIP(SrcNone | Prot | Priv,		vmsave,		check_svme_pa),
-	DIP(SrcNone | Prot | Priv,		stgi,		check_svme),
-	DIP(SrcNone | Prot | Priv,		clgi,		check_svme),
-	DIP(SrcNone | Prot | Priv,		skinit,		check_svme),
-	DIP(SrcNone | Prot | Priv,		invlpga,	check_svme),
+	DIP(SrcNone | Prot | Priv,			vmrun,		check_svme_pa),
+	II(SrcNone  | Prot | Priv | EmulateOnUD,	em_hypercall,	vmmcall),
+	DIP(SrcNone | Prot | Priv,			vmload,		check_svme_pa),
+	DIP(SrcNone | Prot | Priv,			vmsave,		check_svme_pa),
+	DIP(SrcNone | Prot | Priv,			stgi,		check_svme),
+	DIP(SrcNone | Prot | Priv,			clgi,		check_svme),
+	DIP(SrcNone | Prot | Priv,			skinit,		check_svme),
+	DIP(SrcNone | Prot | Priv,			invlpga,	check_svme),
 };
 
 static const struct opcode group7_rm7[] = {
diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
index 68b420289d7e..b090ec0688a6 100644
--- a/arch/x86/kvm/kvm_emulate.h
+++ b/arch/x86/kvm/kvm_emulate.h
@@ -216,7 +216,7 @@ struct x86_emulate_ops {
 	int (*read_pmc)(struct x86_emulate_ctxt *ctxt, u32 pmc, u64 *pdata);
 	void (*halt)(struct x86_emulate_ctxt *ctxt);
 	void (*wbinvd)(struct x86_emulate_ctxt *ctxt);
-	int (*fix_hypercall)(struct x86_emulate_ctxt *ctxt);
+	int (*hypercall)(struct x86_emulate_ctxt *ctxt);
 	int (*intercept)(struct x86_emulate_ctxt *ctxt,
 			 struct x86_instruction_info *info,
 			 enum x86_intercept_stage stage);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index b8d799e1c57c..aee3b08a1d85 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -329,7 +329,7 @@ static struct kmem_cache *kvm_alloc_emulator_cache(void)
 					  size - useroffset, NULL);
 }
 
-static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt);
+static int emulator_hypercall(struct x86_emulate_ctxt *ctxt);
 
 static inline void kvm_async_pf_hash_reset(struct kvm_vcpu *vcpu)
 {
@@ -7352,7 +7352,7 @@ static const struct x86_emulate_ops emulate_ops = {
 	.read_pmc            = emulator_read_pmc,
 	.halt                = emulator_halt,
 	.wbinvd              = emulator_wbinvd,
-	.fix_hypercall       = emulator_fix_hypercall,
+	.hypercall           = emulator_hypercall,
 	.intercept           = emulator_intercept,
 	.get_cpuid           = emulator_get_cpuid,
 	.guest_has_long_mode = emulator_guest_has_long_mode,
@@ -8747,16 +8747,15 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_hypercall);
 
-static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
+static int emulator_hypercall(struct x86_emulate_ctxt *ctxt)
 {
+	int ret;
 	struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
-	char instruction[3];
-	unsigned long rip = kvm_rip_read(vcpu);
-
-	static_call(kvm_x86_patch_hypercall)(vcpu, instruction);
 
-	return emulator_write_emulated(ctxt, rip, instruction, 3,
-		&ctxt->exception);
+	ret = kvm_emulate_hypercall_noskip(vcpu);
+	if (ret)
+		return X86EMUL_CONTINUE;
+	return X86EMUL_IO_NEEDED;
 }
 
 static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-09-09 11:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <cover.1631186996.git.houwenlong93@linux.alibaba.com>
2021-09-09 11:37 ` [PATCH 1/3] kvm: x86: Introduce hypercall x86 ops for handling hypercall not in cpl0 Hou Wenlong
2021-09-09 11:37 ` [PATCH 2/3] kvm: x86: Refactor kvm_emulate_hypercall() to no skip instruction Hou Wenlong
2021-09-09 11:37 ` [PATCH 3/3] kvm: x86: Emulate hypercall instead of fixing hypercall instruction Hou Wenlong

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