aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2014-11-04 12:31:19 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2014-11-07 09:44:00 -0500
commita2ae9df7c991eca6c1ee6f42dbb18701a64175c3 (patch)
treeb001c08e23ea5a86c3b96ad6e64b36f1c2d63a1b
parent34a1cd60d17f62c1f077c1478a6c2ca8c3d17af4 (diff)
kvm: x86: vmx: avoid returning bool to distinguish success from error
Return a negative error code instead, and WARN() when we should be covering the entire 2-bit space of vmcs_field_type's return value. For increased robustness, add a BUILD_BUG_ON checking the range of vmcs_field_to_offset. Suggested-by: Tiejun Chen <tiejun.chen@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/kvm/vmx.c53
1 files changed, 32 insertions, 21 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 12f6f9a8dd8d..d6e3ddace074 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -720,12 +720,15 @@ static const unsigned short vmcs_field_to_offset_table[] = {
720 FIELD(HOST_RSP, host_rsp), 720 FIELD(HOST_RSP, host_rsp),
721 FIELD(HOST_RIP, host_rip), 721 FIELD(HOST_RIP, host_rip),
722}; 722};
723static const int max_vmcs_field = ARRAY_SIZE(vmcs_field_to_offset_table);
724 723
725static inline short vmcs_field_to_offset(unsigned long field) 724static inline short vmcs_field_to_offset(unsigned long field)
726{ 725{
727 if (field >= max_vmcs_field || vmcs_field_to_offset_table[field] == 0) 726 BUILD_BUG_ON(ARRAY_SIZE(vmcs_field_to_offset_table) > SHRT_MAX);
728 return -1; 727
728 if (field >= ARRAY_SIZE(vmcs_field_to_offset_table) ||
729 vmcs_field_to_offset_table[field] == 0)
730 return -ENOENT;
731
729 return vmcs_field_to_offset_table[field]; 732 return vmcs_field_to_offset_table[field];
730} 733}
731 734
@@ -6492,58 +6495,60 @@ static inline int vmcs_field_readonly(unsigned long field)
6492 * some of the bits we return here (e.g., on 32-bit guests, only 32 bits of 6495 * some of the bits we return here (e.g., on 32-bit guests, only 32 bits of
6493 * 64-bit fields are to be returned). 6496 * 64-bit fields are to be returned).
6494 */ 6497 */
6495static inline bool vmcs12_read_any(struct kvm_vcpu *vcpu, 6498static inline int vmcs12_read_any(struct kvm_vcpu *vcpu,
6496 unsigned long field, u64 *ret) 6499 unsigned long field, u64 *ret)
6497{ 6500{
6498 short offset = vmcs_field_to_offset(field); 6501 short offset = vmcs_field_to_offset(field);
6499 char *p; 6502 char *p;
6500 6503
6501 if (offset < 0) 6504 if (offset < 0)
6502 return 0; 6505 return offset;
6503 6506
6504 p = ((char *)(get_vmcs12(vcpu))) + offset; 6507 p = ((char *)(get_vmcs12(vcpu))) + offset;
6505 6508
6506 switch (vmcs_field_type(field)) { 6509 switch (vmcs_field_type(field)) {
6507 case VMCS_FIELD_TYPE_NATURAL_WIDTH: 6510 case VMCS_FIELD_TYPE_NATURAL_WIDTH:
6508 *ret = *((natural_width *)p); 6511 *ret = *((natural_width *)p);
6509 return 1; 6512 return 0;
6510 case VMCS_FIELD_TYPE_U16: 6513 case VMCS_FIELD_TYPE_U16:
6511 *ret = *((u16 *)p); 6514 *ret = *((u16 *)p);
6512 return 1; 6515 return 0;
6513 case VMCS_FIELD_TYPE_U32: 6516 case VMCS_FIELD_TYPE_U32:
6514 *ret = *((u32 *)p); 6517 *ret = *((u32 *)p);
6515 return 1; 6518 return 0;
6516 case VMCS_FIELD_TYPE_U64: 6519 case VMCS_FIELD_TYPE_U64:
6517 *ret = *((u64 *)p); 6520 *ret = *((u64 *)p);
6518 return 1; 6521 return 0;
6519 default: 6522 default:
6520 return 0; /* can never happen. */ 6523 WARN_ON(1);
6524 return -ENOENT;
6521 } 6525 }
6522} 6526}
6523 6527
6524 6528
6525static inline bool vmcs12_write_any(struct kvm_vcpu *vcpu, 6529static inline int vmcs12_write_any(struct kvm_vcpu *vcpu,
6526 unsigned long field, u64 field_value){ 6530 unsigned long field, u64 field_value){
6527 short offset = vmcs_field_to_offset(field); 6531 short offset = vmcs_field_to_offset(field);
6528 char *p = ((char *) get_vmcs12(vcpu)) + offset; 6532 char *p = ((char *) get_vmcs12(vcpu)) + offset;
6529 if (offset < 0) 6533 if (offset < 0)
6530 return false; 6534 return offset;
6531 6535
6532 switch (vmcs_field_type(field)) { 6536 switch (vmcs_field_type(field)) {
6533 case VMCS_FIELD_TYPE_U16: 6537 case VMCS_FIELD_TYPE_U16:
6534 *(u16 *)p = field_value; 6538 *(u16 *)p = field_value;
6535 return true; 6539 return 0;
6536 case VMCS_FIELD_TYPE_U32: 6540 case VMCS_FIELD_TYPE_U32:
6537 *(u32 *)p = field_value; 6541 *(u32 *)p = field_value;
6538 return true; 6542 return 0;
6539 case VMCS_FIELD_TYPE_U64: 6543 case VMCS_FIELD_TYPE_U64:
6540 *(u64 *)p = field_value; 6544 *(u64 *)p = field_value;
6541 return true; 6545 return 0;
6542 case VMCS_FIELD_TYPE_NATURAL_WIDTH: 6546 case VMCS_FIELD_TYPE_NATURAL_WIDTH:
6543 *(natural_width *)p = field_value; 6547 *(natural_width *)p = field_value;
6544 return true; 6548 return 0;
6545 default: 6549 default:
6546 return false; /* can never happen. */ 6550 WARN_ON(1);
6551 return -ENOENT;
6547 } 6552 }
6548 6553
6549} 6554}
@@ -6576,6 +6581,9 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
6576 case VMCS_FIELD_TYPE_NATURAL_WIDTH: 6581 case VMCS_FIELD_TYPE_NATURAL_WIDTH:
6577 field_value = vmcs_readl(field); 6582 field_value = vmcs_readl(field);
6578 break; 6583 break;
6584 default:
6585 WARN_ON(1);
6586 continue;
6579 } 6587 }
6580 vmcs12_write_any(&vmx->vcpu, field, field_value); 6588 vmcs12_write_any(&vmx->vcpu, field, field_value);
6581 } 6589 }
@@ -6621,6 +6629,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
6621 case VMCS_FIELD_TYPE_NATURAL_WIDTH: 6629 case VMCS_FIELD_TYPE_NATURAL_WIDTH:
6622 vmcs_writel(field, (long)field_value); 6630 vmcs_writel(field, (long)field_value);
6623 break; 6631 break;
6632 default:
6633 WARN_ON(1);
6634 break;
6624 } 6635 }
6625 } 6636 }
6626 } 6637 }
@@ -6659,7 +6670,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
6659 /* Decode instruction info and find the field to read */ 6670 /* Decode instruction info and find the field to read */
6660 field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); 6671 field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
6661 /* Read the field, zero-extended to a u64 field_value */ 6672 /* Read the field, zero-extended to a u64 field_value */
6662 if (!vmcs12_read_any(vcpu, field, &field_value)) { 6673 if (vmcs12_read_any(vcpu, field, &field_value) < 0) {
6663 nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); 6674 nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
6664 skip_emulated_instruction(vcpu); 6675 skip_emulated_instruction(vcpu);
6665 return 1; 6676 return 1;
@@ -6729,7 +6740,7 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
6729 return 1; 6740 return 1;
6730 } 6741 }
6731 6742
6732 if (!vmcs12_write_any(vcpu, field, field_value)) { 6743 if (vmcs12_write_any(vcpu, field, field_value) < 0) {
6733 nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); 6744 nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
6734 skip_emulated_instruction(vcpu); 6745 skip_emulated_instruction(vcpu);
6735 return 1; 6746 return 1;