Commit dd2d6042 authored by Jim Mattson's avatar Jim Mattson Committed by Paolo Bonzini

kvm: nVMX: VMWRITE checks VMCS-link pointer before VMCS field

According to the SDM, a VMWRITE in VMX non-root operation with an
invalid VMCS-link pointer results in VMfailInvalid before the validity
of the VMCS field in the secondary source operand is checked.

For consistency, modify both handle_vmwrite and handle_vmread, even
though there was no problem with the latter.

Fixes: 6d894f49 ("KVM: nVMX: vmread/vmwrite: Use shadow vmcs12 if running L2")
Signed-off-by: default avatarJim Mattson <jmattson@google.com>
Cc: Liran Alon <liran.alon@oracle.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
Reviewed-by: default avatarPeter Shier <pshier@google.com>
Reviewed-by: default avatarOliver Upton <oupton@google.com>
Reviewed-by: default avatarJon Cargille <jcargill@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 5e3d394f
...@@ -4753,32 +4753,28 @@ static int handle_vmread(struct kvm_vcpu *vcpu) ...@@ -4753,32 +4753,28 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
{ {
unsigned long field; unsigned long field;
u64 field_value; u64 field_value;
struct vcpu_vmx *vmx = to_vmx(vcpu);
unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
int len; int len;
gva_t gva = 0; gva_t gva = 0;
struct vmcs12 *vmcs12; struct vmcs12 *vmcs12 = is_guest_mode(vcpu) ? get_shadow_vmcs12(vcpu)
: get_vmcs12(vcpu);
struct x86_exception e; struct x86_exception e;
short offset; short offset;
if (!nested_vmx_check_permission(vcpu)) if (!nested_vmx_check_permission(vcpu))
return 1; return 1;
if (to_vmx(vcpu)->nested.current_vmptr == -1ull) /*
* In VMX non-root operation, when the VMCS-link pointer is -1ull,
* any VMREAD sets the ALU flags for VMfailInvalid.
*/
if (vmx->nested.current_vmptr == -1ull ||
(is_guest_mode(vcpu) &&
get_vmcs12(vcpu)->vmcs_link_pointer == -1ull))
return nested_vmx_failInvalid(vcpu); return nested_vmx_failInvalid(vcpu);
if (!is_guest_mode(vcpu))
vmcs12 = get_vmcs12(vcpu);
else {
/*
* When vmcs->vmcs_link_pointer is -1ull, any VMREAD
* to shadowed-field sets the ALU flags for VMfailInvalid.
*/
if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull)
return nested_vmx_failInvalid(vcpu);
vmcs12 = get_shadow_vmcs12(vcpu);
}
/* Decode instruction info and find the field to read */ /* Decode instruction info and find the field to read */
field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
...@@ -4855,13 +4851,20 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) ...@@ -4855,13 +4851,20 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
*/ */
u64 field_value = 0; u64 field_value = 0;
struct x86_exception e; struct x86_exception e;
struct vmcs12 *vmcs12; struct vmcs12 *vmcs12 = is_guest_mode(vcpu) ? get_shadow_vmcs12(vcpu)
: get_vmcs12(vcpu);
short offset; short offset;
if (!nested_vmx_check_permission(vcpu)) if (!nested_vmx_check_permission(vcpu))
return 1; return 1;
if (vmx->nested.current_vmptr == -1ull) /*
* In VMX non-root operation, when the VMCS-link pointer is -1ull,
* any VMWRITE sets the ALU flags for VMfailInvalid.
*/
if (vmx->nested.current_vmptr == -1ull ||
(is_guest_mode(vcpu) &&
get_vmcs12(vcpu)->vmcs_link_pointer == -1ull))
return nested_vmx_failInvalid(vcpu); return nested_vmx_failInvalid(vcpu);
if (vmx_instruction_info & (1u << 10)) if (vmx_instruction_info & (1u << 10))
...@@ -4889,24 +4892,12 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) ...@@ -4889,24 +4892,12 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
return nested_vmx_failValid(vcpu, return nested_vmx_failValid(vcpu,
VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT); VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT);
if (!is_guest_mode(vcpu)) { /*
vmcs12 = get_vmcs12(vcpu); * Ensure vmcs12 is up-to-date before any VMWRITE that dirties
* vmcs12, else we may crush a field or consume a stale value.
/* */
* Ensure vmcs12 is up-to-date before any VMWRITE that dirties if (!is_guest_mode(vcpu) && !is_shadow_field_rw(field))
* vmcs12, else we may crush a field or consume a stale value. copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
*/
if (!is_shadow_field_rw(field))
copy_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
} else {
/*
* When vmcs->vmcs_link_pointer is -1ull, any VMWRITE
* to shadowed-field sets the ALU flags for VMfailInvalid.
*/
if (get_vmcs12(vcpu)->vmcs_link_pointer == -1ull)
return nested_vmx_failInvalid(vcpu);
vmcs12 = get_shadow_vmcs12(vcpu);
}
offset = vmcs_field_to_offset(field); offset = vmcs_field_to_offset(field);
if (offset < 0) if (offset < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment