kvm: vmx: take access length into account when checking the limit
PATCH 2/2 kvm: vmx: take access length into account when checking the limit
There is an imperfection in get_vmx_mem_address(): access length is ignored when checking the limit. To fix this, pass access length as a function argument. The access length is obvious since it is used by callers after get_vmx_mem_address() call.
Signed-off-by Eugene Korenevsky <[email protected]>
--- arch/x86/kvm/vmx/nested.c | 26 +++++++++++++++----------- arch/x86/kvm/vmx/nested.h | 2 +- arch/x86/kvm/vmx/vmx.c | 3 ++- 3 files changed, 18 insertions(+), 13 deletions(-)
arch/x86/kvm/vmx/nested.c +15 -11
@@ -4008,7 +4008,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,* #UD or #GP. */ int get_vmx_mem_address (struct kvm_vcpu *vcpu,unsigned long exit_qualification, -u32 vmx_instruction_info,bool wr,gva_t *ret) +u32 vmx_instruction_info,bool wr,int len,gva_t *ret) {gva_t off;bool exn;
@@ -4134,7 +4134,8 @@ static int nested_vmx_get_vmptr(struct kvm_vcpu *vcpu, gpa_t *vmpointer)struct x86_exception e;if (get_vmx_mem_address (vcpu,vmcs_readl (EXIT_QUALIFICATION ), -vmcs_read32 (VMX_INSTRUCTION_INFO ), false, &gva)) +vmcs_read32 (VMX_INSTRUCTION_INFO ), false, +sizeof (*vmpointer), &gva))return 1 ;if (kvm_read_guest_virt (vcpu, gva, vmpointer,sizeof (*vmpointer), &e)) {
@@ -4386,6 +4387,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)u64 field_value;unsigned long exit_qualification =vmcs_readl (EXIT_QUALIFICATION );u32 vmx_instruction_info =vmcs_read32 (VMX_INSTRUCTION_INFO ); +int len;gva_t gva =0 ;struct vmcs12 *vmcs12;
@@ -4423,12 +4425,12 @@ static int handle_vmread(struct kvm_vcpu *vcpu)kvm_register_writel (vcpu, (((vmx_instruction_info) >>3 ) &0xf ), field_value); }else { + len =is_64_bit_mode (vcpu) ?8 :4 ;if (get_vmx_mem_address (vcpu, exit_qualification, - vmx_instruction_info, true, &gva)) + vmx_instruction_info, true, len, &gva))return 1 ;/* _system ok, nested_vmx_check_permission has verified cpl=0 */ -kvm_write_guest_virt_system (vcpu, gva, &field_value, - (is_long_mode (vcpu) ?8 :4 ),NULL ); +kvm_write_guest_virt_system (vcpu, gva, &field_value, len,NULL ); }return nested_vmx_succeed (vcpu);
@@ -4438,6 +4440,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)static int handle_vmwrite (struct kvm_vcpu *vcpu) {unsigned long field; +int len;gva_t gva;struct vcpu_vmx *vmx =to_vmx (vcpu);unsigned long exit_qualification =vmcs_readl (EXIT_QUALIFICATION );
@@ -4463,11 +4466,11 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) field_value =kvm_register_readl (vcpu, (((vmx_instruction_info) >>3 ) &0xf )); else { + len =is_64_bit_mode (vcpu) ?8 :4 ;if (get_vmx_mem_address (vcpu, exit_qualification, - vmx_instruction_info, false, &gva)) + vmx_instruction_info, false, len, &gva))return 1 ; -if (kvm_read_guest_virt (vcpu, gva, &field_value, - (is_64_bit_mode (vcpu) ?8 :4 ), &e)) { +if (kvm_read_guest_virt (vcpu, gva, &field_value, len, &e)) {kvm_inject_page_fault (vcpu, &e);return 1 ; }
@@ -4615,7 +4618,8 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)if (unlikely (to_vmx (vcpu)->nested.hv_evmcs))return 1 ; -if (get_vmx_mem_address (vcpu, exit_qual, instr_info, true, &gva)) +if (get_vmx_mem_address (vcpu, exit_qual, instr_info, + true,sizeof (gpa_t), &gva))return 1 ;/* *_system ok, nested_vmx_check_permission has verified cpl=0 */ if (kvm_write_guest_virt_system(vcpu, gva, (void *)¤t_vmptr,
@@ -4661,7 +4665,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)* operand is read even if it isn't needed (e.g., for type==global) */ if (get_vmx_mem_address (vcpu,vmcs_readl (EXIT_QUALIFICATION ), - vmx_instruction_info, false, &gva)) + vmx_instruction_info, false,sizeof (operand), &gva))return 1 ;if (kvm_read_guest_virt (vcpu, gva, &operand,sizeof (operand), &e)) {kvm_inject_page_fault (vcpu, &e);
@@ -4723,7 +4727,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)* operand is read even if it isn't needed (e.g., for type==global) */ if (get_vmx_mem_address (vcpu,vmcs_readl (EXIT_QUALIFICATION ), - vmx_instruction_info, false, &gva)) + vmx_instruction_info, false,sizeof (operand), &gva))return 1 ;if (kvm_read_guest_virt (vcpu, gva, &operand,sizeof (operand), &e)) {kvm_inject_page_fault (vcpu, &e);
arch/x86/kvm/vmx/nested.h +1 -1
@@ -21,7 +21,7 @@ void nested_sync_from_vmcs12(struct kvm_vcpu *vcpu);int vmx_set_vmx_msr (struct kvm_vcpu *vcpu,u32 msr_index,u64 data);int vmx_get_vmx_msr (struct nested_vmx_msrs *msrs,u32 msr_index,u64 *pdata);int get_vmx_mem_address (struct kvm_vcpu *vcpu,unsigned long exit_qualification, -u32 vmx_instruction_info,bool wr,gva_t *ret); +u32 vmx_instruction_info,bool wr,int len,gva_t *ret);static inline struct vmcs12 *get_vmcs12 (struct kvm_vcpu *vcpu) {
arch/x86/kvm/vmx/vmx.c +2 -1
@@ -5342,7 +5342,8 @@ static int handle_invpcid(struct kvm_vcpu *vcpu)* is read even if it isn't needed (e.g., for type==all) */ if (get_vmx_mem_address (vcpu,vmcs_readl (EXIT_QUALIFICATION ), - vmx_instruction_info, false, &gva)) + vmx_instruction_info, false, +sizeof (operand), &gva))return 1 ;if (kvm_read_guest_virt (vcpu, gva, &operand,sizeof (operand), &e)) {
Signature · 1 line
2.21.0
Sorry, made mistake here (the len argument is not applied). Will send the fixed version as v2 patchset.
Quoted 6 lines
int get_vmx_mem_address(struct
kvm_vcpu*vcpu, unsigned longexit_qualification,arch/x86/kvm/vmx/nested.c +1
-1- u32 vmx_instruction_info, bool wr, gva_t *ret) + u32 vmx_instruction_info, bool wr, int len, gva_t *ret) { gva_t off;bool exn;
Signature · 1 line
Eugene