diff mbox series

[RFC,3/3] x86/kvm/hyper-v: don't allow to turn on unsupported VMX controls for nested guests

Message ID 20200115171014.56405-4-vkuznets@redhat.com (mailing list archive)
State New, archived
Headers show
Series x86/kvm/hyper-v: fix enlightened VMCS & QEMU4.2 | expand

Commit Message

Vitaly Kuznetsov Jan. 15, 2020, 5:10 p.m. UTC
Sane L1 hypervisors are not supposed to turn any of the unsupported VMX
controls on for its guests and nested_vmx_check_controls() checks for
that. This is, however, not the case for the controls which are supported
on the host but are missing in enlightened VMCS and when eVMCS is in use.

It would certainly be possible to add these missing checks to
nested_check_vm_execution_controls()/_vm_exit_controls()/.. but it seems
preferable to keep eVMCS-specific stuff in eVMCS and reduce the impact on
non-eVMCS guests by doing less unrelated checks. Create a separate
nested_evmcs_check_controls() for this purpose.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
 arch/x86/kvm/vmx/evmcs.c  | 56 ++++++++++++++++++++++++++++++++++++++-
 arch/x86/kvm/vmx/evmcs.h  |  1 +
 arch/x86/kvm/vmx/nested.c |  3 +++
 3 files changed, 59 insertions(+), 1 deletion(-)

Comments

Liran Alon Jan. 15, 2020, 10:59 p.m. UTC | #1
> On 15 Jan 2020, at 19:10, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> 
> Sane L1 hypervisors are not supposed to turn any of the unsupported VMX
> controls on for its guests and nested_vmx_check_controls() checks for
> that. This is, however, not the case for the controls which are supported
> on the host but are missing in enlightened VMCS and when eVMCS is in use.
> 
> It would certainly be possible to add these missing checks to
> nested_check_vm_execution_controls()/_vm_exit_controls()/.. but it seems
> preferable to keep eVMCS-specific stuff in eVMCS and reduce the impact on
> non-eVMCS guests by doing less unrelated checks. Create a separate
> nested_evmcs_check_controls() for this purpose.
> 
> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> ---
> arch/x86/kvm/vmx/evmcs.c  | 56 ++++++++++++++++++++++++++++++++++++++-
> arch/x86/kvm/vmx/evmcs.h  |  1 +
> arch/x86/kvm/vmx/nested.c |  3 +++
> 3 files changed, 59 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/kvm/vmx/evmcs.c b/arch/x86/kvm/vmx/evmcs.c
> index b5d6582ba589..88f462866396 100644
> --- a/arch/x86/kvm/vmx/evmcs.c
> +++ b/arch/x86/kvm/vmx/evmcs.c
> @@ -4,9 +4,11 @@
> #include <linux/smp.h>
> 
> #include "../hyperv.h"
> -#include "evmcs.h"
> #include "vmcs.h"
> +#include "vmcs12.h"
> +#include "evmcs.h"
> #include "vmx.h"
> +#include "trace.h"
> 
> DEFINE_STATIC_KEY_FALSE(enable_evmcs);
> 
> @@ -378,6 +380,58 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
> 	*pdata = ctl_low | ((u64)ctl_high << 32);
> }
> 
> +int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
> +{
> +	int ret = 0;
> +	u32 unsupp_ctl;
> +
> +	unsupp_ctl = vmcs12->pin_based_vm_exec_control &
> +		EVMCS1_UNSUPPORTED_PINCTRL;
> +	if (unsupp_ctl) {
> +		trace_kvm_nested_vmenter_failed(
> +			"eVMCS: unsupported pin-based VM-execution controls",
> +			unsupp_ctl);

Why not move "CC” macro from nested.c to nested.h and use it here as-well instead of replicating it’s logic?

-Liran
Vitaly Kuznetsov Jan. 16, 2020, 8:55 a.m. UTC | #2
Liran Alon <liran.alon@oracle.com> writes:

>> On 15 Jan 2020, at 19:10, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>> 
>> Sane L1 hypervisors are not supposed to turn any of the unsupported VMX
>> controls on for its guests and nested_vmx_check_controls() checks for
>> that. This is, however, not the case for the controls which are supported
>> on the host but are missing in enlightened VMCS and when eVMCS is in use.
>> 
>> It would certainly be possible to add these missing checks to
>> nested_check_vm_execution_controls()/_vm_exit_controls()/.. but it seems
>> preferable to keep eVMCS-specific stuff in eVMCS and reduce the impact on
>> non-eVMCS guests by doing less unrelated checks. Create a separate
>> nested_evmcs_check_controls() for this purpose.
>> 
>> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
>> ---
>> arch/x86/kvm/vmx/evmcs.c  | 56 ++++++++++++++++++++++++++++++++++++++-
>> arch/x86/kvm/vmx/evmcs.h  |  1 +
>> arch/x86/kvm/vmx/nested.c |  3 +++
>> 3 files changed, 59 insertions(+), 1 deletion(-)
>> 
>> diff --git a/arch/x86/kvm/vmx/evmcs.c b/arch/x86/kvm/vmx/evmcs.c
>> index b5d6582ba589..88f462866396 100644
>> --- a/arch/x86/kvm/vmx/evmcs.c
>> +++ b/arch/x86/kvm/vmx/evmcs.c
>> @@ -4,9 +4,11 @@
>> #include <linux/smp.h>
>> 
>> #include "../hyperv.h"
>> -#include "evmcs.h"
>> #include "vmcs.h"
>> +#include "vmcs12.h"
>> +#include "evmcs.h"
>> #include "vmx.h"
>> +#include "trace.h"
>> 
>> DEFINE_STATIC_KEY_FALSE(enable_evmcs);
>> 
>> @@ -378,6 +380,58 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
>> 	*pdata = ctl_low | ((u64)ctl_high << 32);
>> }
>> 
>> +int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
>> +{
>> +	int ret = 0;
>> +	u32 unsupp_ctl;
>> +
>> +	unsupp_ctl = vmcs12->pin_based_vm_exec_control &
>> +		EVMCS1_UNSUPPORTED_PINCTRL;
>> +	if (unsupp_ctl) {
>> +		trace_kvm_nested_vmenter_failed(
>> +			"eVMCS: unsupported pin-based VM-execution controls",
>> +			unsupp_ctl);
>
> Why not move "CC” macro from nested.c to nested.h and use it here as-well instead of replicating it’s logic?
>

Because error messages I add are both human readable and conform to SDM!
:-)

On a more serious not yes, we should probably do that. We may even want
to use it in non-nesting (and non VMX) code in KVM.

Thanks,
Sean Christopherson Jan. 16, 2020, 4:21 p.m. UTC | #3
On Thu, Jan 16, 2020 at 09:55:57AM +0100, Vitaly Kuznetsov wrote:
> Liran Alon <liran.alon@oracle.com> writes:
> 
> >> On 15 Jan 2020, at 19:10, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
> >> 
> >> Sane L1 hypervisors are not supposed to turn any of the unsupported VMX
> >> controls on for its guests and nested_vmx_check_controls() checks for
> >> that. This is, however, not the case for the controls which are supported
> >> on the host but are missing in enlightened VMCS and when eVMCS is in use.
> >> 
> >> It would certainly be possible to add these missing checks to
> >> nested_check_vm_execution_controls()/_vm_exit_controls()/.. but it seems
> >> preferable to keep eVMCS-specific stuff in eVMCS and reduce the impact on
> >> non-eVMCS guests by doing less unrelated checks. Create a separate
> >> nested_evmcs_check_controls() for this purpose.
> >> 
> >> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> >> ---
> >> arch/x86/kvm/vmx/evmcs.c  | 56 ++++++++++++++++++++++++++++++++++++++-
> >> arch/x86/kvm/vmx/evmcs.h  |  1 +
> >> arch/x86/kvm/vmx/nested.c |  3 +++
> >> 3 files changed, 59 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/arch/x86/kvm/vmx/evmcs.c b/arch/x86/kvm/vmx/evmcs.c
> >> index b5d6582ba589..88f462866396 100644
> >> --- a/arch/x86/kvm/vmx/evmcs.c
> >> +++ b/arch/x86/kvm/vmx/evmcs.c
> >> @@ -4,9 +4,11 @@
> >> #include <linux/smp.h>
> >> 
> >> #include "../hyperv.h"
> >> -#include "evmcs.h"
> >> #include "vmcs.h"
> >> +#include "vmcs12.h"
> >> +#include "evmcs.h"
> >> #include "vmx.h"
> >> +#include "trace.h"
> >> 
> >> DEFINE_STATIC_KEY_FALSE(enable_evmcs);
> >> 
> >> @@ -378,6 +380,58 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
> >> 	*pdata = ctl_low | ((u64)ctl_high << 32);
> >> }
> >> 
> >> +int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
> >> +{
> >> +	int ret = 0;
> >> +	u32 unsupp_ctl;
> >> +
> >> +	unsupp_ctl = vmcs12->pin_based_vm_exec_control &
> >> +		EVMCS1_UNSUPPORTED_PINCTRL;
> >> +	if (unsupp_ctl) {
> >> +		trace_kvm_nested_vmenter_failed(
> >> +			"eVMCS: unsupported pin-based VM-execution controls",
> >> +			unsupp_ctl);
> >
> > Why not move "CC” macro from nested.c to nested.h and use it here as-well instead of replicating it’s logic?
> >
> 
> Because error messages I add are both human readable and conform to SDM!
> :-)
> 
> On a more serious not yes, we should probably do that. We may even want
> to use it in non-nesting (and non VMX) code in KVM.

No, the CC() macro is short for Consistency Check, i.e. specific to nVMX.
Even if KVM ends up adding nested_evmcs_check_controls(), which I'm hoping
can be avoided, I'd still be hesitant to expose CC() in nested.h.
Paolo Bonzini Jan. 19, 2020, 8:57 a.m. UTC | #4
On 16/01/20 17:21, Sean Christopherson wrote:
> On Thu, Jan 16, 2020 at 09:55:57AM +0100, Vitaly Kuznetsov wrote:
>> Liran Alon <liran.alon@oracle.com> writes:
>>
>>>> On 15 Jan 2020, at 19:10, Vitaly Kuznetsov <vkuznets@redhat.com> wrote:
>>>>
>>>> Sane L1 hypervisors are not supposed to turn any of the unsupported VMX
>>>> controls on for its guests and nested_vmx_check_controls() checks for
>>>> that. This is, however, not the case for the controls which are supported
>>>> on the host but are missing in enlightened VMCS and when eVMCS is in use.
>>>>
>>>> It would certainly be possible to add these missing checks to
>>>> nested_check_vm_execution_controls()/_vm_exit_controls()/.. but it seems
>>>> preferable to keep eVMCS-specific stuff in eVMCS and reduce the impact on
>>>> non-eVMCS guests by doing less unrelated checks. Create a separate
>>>> nested_evmcs_check_controls() for this purpose.
>>>>
>>>> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
>>>> ---
>>>> arch/x86/kvm/vmx/evmcs.c  | 56 ++++++++++++++++++++++++++++++++++++++-
>>>> arch/x86/kvm/vmx/evmcs.h  |  1 +
>>>> arch/x86/kvm/vmx/nested.c |  3 +++
>>>> 3 files changed, 59 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/arch/x86/kvm/vmx/evmcs.c b/arch/x86/kvm/vmx/evmcs.c
>>>> index b5d6582ba589..88f462866396 100644
>>>> --- a/arch/x86/kvm/vmx/evmcs.c
>>>> +++ b/arch/x86/kvm/vmx/evmcs.c
>>>> @@ -4,9 +4,11 @@
>>>> #include <linux/smp.h>
>>>>
>>>> #include "../hyperv.h"
>>>> -#include "evmcs.h"
>>>> #include "vmcs.h"
>>>> +#include "vmcs12.h"
>>>> +#include "evmcs.h"
>>>> #include "vmx.h"
>>>> +#include "trace.h"
>>>>
>>>> DEFINE_STATIC_KEY_FALSE(enable_evmcs);
>>>>
>>>> @@ -378,6 +380,58 @@ void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
>>>> 	*pdata = ctl_low | ((u64)ctl_high << 32);
>>>> }
>>>>
>>>> +int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
>>>> +{
>>>> +	int ret = 0;
>>>> +	u32 unsupp_ctl;
>>>> +
>>>> +	unsupp_ctl = vmcs12->pin_based_vm_exec_control &
>>>> +		EVMCS1_UNSUPPORTED_PINCTRL;
>>>> +	if (unsupp_ctl) {
>>>> +		trace_kvm_nested_vmenter_failed(
>>>> +			"eVMCS: unsupported pin-based VM-execution controls",
>>>> +			unsupp_ctl);
>>>
>>> Why not move "CC” macro from nested.c to nested.h and use it here as-well instead of replicating it’s logic?
>>>
>>
>> Because error messages I add are both human readable and conform to SDM!
>> :-)
>>
>> On a more serious not yes, we should probably do that. We may even want
>> to use it in non-nesting (and non VMX) code in KVM.
> 
> No, the CC() macro is short for Consistency Check, i.e. specific to nVMX.
> Even if KVM ends up adding nested_evmcs_check_controls(), which I'm hoping
> can be avoided, I'd still be hesitant to expose CC() in nested.h.
> 

For now let's keep Vitaly's patch as is.  It's definitely a good one as
it would catch Hyper-V's issue immediately even without patch 2 (which
is the only really contentious change).

Paolo
diff mbox series

Patch

diff --git a/arch/x86/kvm/vmx/evmcs.c b/arch/x86/kvm/vmx/evmcs.c
index b5d6582ba589..88f462866396 100644
--- a/arch/x86/kvm/vmx/evmcs.c
+++ b/arch/x86/kvm/vmx/evmcs.c
@@ -4,9 +4,11 @@ 
 #include <linux/smp.h>
 
 #include "../hyperv.h"
-#include "evmcs.h"
 #include "vmcs.h"
+#include "vmcs12.h"
+#include "evmcs.h"
 #include "vmx.h"
+#include "trace.h"
 
 DEFINE_STATIC_KEY_FALSE(enable_evmcs);
 
@@ -378,6 +380,58 @@  void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata)
 	*pdata = ctl_low | ((u64)ctl_high << 32);
 }
 
+int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
+{
+	int ret = 0;
+	u32 unsupp_ctl;
+
+	unsupp_ctl = vmcs12->pin_based_vm_exec_control &
+		EVMCS1_UNSUPPORTED_PINCTRL;
+	if (unsupp_ctl) {
+		trace_kvm_nested_vmenter_failed(
+			"eVMCS: unsupported pin-based VM-execution controls",
+			unsupp_ctl);
+		ret = -EINVAL;
+	}
+
+	unsupp_ctl = vmcs12->secondary_vm_exec_control &
+		EVMCS1_UNSUPPORTED_2NDEXEC;
+	if (unsupp_ctl) {
+		trace_kvm_nested_vmenter_failed(
+			"eVMCS: unsupported secondary VM-execution controls",
+			unsupp_ctl);
+		ret = -EINVAL;
+	}
+
+	unsupp_ctl = vmcs12->vm_exit_controls &
+		EVMCS1_UNSUPPORTED_VMEXIT_CTRL;
+	if (unsupp_ctl) {
+		trace_kvm_nested_vmenter_failed(
+			"eVMCS: unsupported VM-exit controls",
+			unsupp_ctl);
+		ret = -EINVAL;
+	}
+
+	unsupp_ctl = vmcs12->vm_entry_controls &
+		EVMCS1_UNSUPPORTED_VMENTRY_CTRL;
+	if (unsupp_ctl) {
+		trace_kvm_nested_vmenter_failed(
+			"eVMCS: unsupported VM-entry controls",
+			unsupp_ctl);
+		ret = -EINVAL;
+	}
+
+	unsupp_ctl = vmcs12->vm_function_control & EVMCS1_UNSUPPORTED_VMFUNC;
+	if (unsupp_ctl) {
+		trace_kvm_nested_vmenter_failed(
+			"eVMCS: unsupported VM-function controls",
+			unsupp_ctl);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 int nested_enable_evmcs(struct kvm_vcpu *vcpu,
 			uint16_t *vmcs_version)
 {
diff --git a/arch/x86/kvm/vmx/evmcs.h b/arch/x86/kvm/vmx/evmcs.h
index b88d9807a796..cb7517a5a41c 100644
--- a/arch/x86/kvm/vmx/evmcs.h
+++ b/arch/x86/kvm/vmx/evmcs.h
@@ -202,5 +202,6 @@  uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
 int nested_enable_evmcs(struct kvm_vcpu *vcpu,
 			uint16_t *vmcs_version);
 void nested_evmcs_filter_control_msr(u32 msr_index, u64 *pdata);
+int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
 
 #endif /* __KVM_X86_VMX_EVMCS_H */
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 4aea7d304beb..7c720b095663 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -2767,6 +2767,9 @@  static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
 	    nested_check_vm_entry_controls(vcpu, vmcs12))
 		return -EINVAL;
 
+	if (to_vmx(vcpu)->nested.enlightened_vmcs_enabled)
+		return nested_evmcs_check_controls(vmcs12);
+
 	return 0;
 }