aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2011-01-03 07:28:52 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2011-03-17 12:08:25 -0400
commita9179499350d30446d8983d272a9157963604b0f (patch)
tree32ad44938298a460f047f16f5942f037c22e853c /arch/x86/kvm/vmx.c
parentd0ba64f9b4b3e41e7b91681fe04a334bc8bfc8f5 (diff)
KVM: VMX: Avoid leaking fake realmode state to userspace
When emulating real mode, we fake some state: - tr.base points to a fake vm86 tss - segment registers are made to conform to vm86 restrictions change vmx_get_segment() not to expose this fake state to userspace; instead, return the original state. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r--arch/x86/kvm/vmx.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index a2e83a9729fc..87ad551b525b 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2032,23 +2032,40 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
2032 vmcs_writel(GUEST_CR4, hw_cr4); 2032 vmcs_writel(GUEST_CR4, hw_cr4);
2033} 2033}
2034 2034
2035static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
2036{
2037 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
2038
2039 return vmcs_readl(sf->base);
2040}
2041
2042static void vmx_get_segment(struct kvm_vcpu *vcpu, 2035static void vmx_get_segment(struct kvm_vcpu *vcpu,
2043 struct kvm_segment *var, int seg) 2036 struct kvm_segment *var, int seg)
2044{ 2037{
2038 struct vcpu_vmx *vmx = to_vmx(vcpu);
2045 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; 2039 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
2040 struct kvm_save_segment *save;
2046 u32 ar; 2041 u32 ar;
2047 2042
2043 if (vmx->rmode.vm86_active
2044 && (seg == VCPU_SREG_TR || seg == VCPU_SREG_ES
2045 || seg == VCPU_SREG_DS || seg == VCPU_SREG_FS
2046 || seg == VCPU_SREG_GS)
2047 && !emulate_invalid_guest_state) {
2048 switch (seg) {
2049 case VCPU_SREG_TR: save = &vmx->rmode.tr; break;
2050 case VCPU_SREG_ES: save = &vmx->rmode.es; break;
2051 case VCPU_SREG_DS: save = &vmx->rmode.ds; break;
2052 case VCPU_SREG_FS: save = &vmx->rmode.fs; break;
2053 case VCPU_SREG_GS: save = &vmx->rmode.gs; break;
2054 default: BUG();
2055 }
2056 var->selector = save->selector;
2057 var->base = save->base;
2058 var->limit = save->limit;
2059 ar = save->ar;
2060 if (seg == VCPU_SREG_TR
2061 || var->selector == vmcs_read16(sf->selector))
2062 goto use_saved_rmode_seg;
2063 }
2048 var->base = vmcs_readl(sf->base); 2064 var->base = vmcs_readl(sf->base);
2049 var->limit = vmcs_read32(sf->limit); 2065 var->limit = vmcs_read32(sf->limit);
2050 var->selector = vmcs_read16(sf->selector); 2066 var->selector = vmcs_read16(sf->selector);
2051 ar = vmcs_read32(sf->ar_bytes); 2067 ar = vmcs_read32(sf->ar_bytes);
2068use_saved_rmode_seg:
2052 if ((ar & AR_UNUSABLE_MASK) && !emulate_invalid_guest_state) 2069 if ((ar & AR_UNUSABLE_MASK) && !emulate_invalid_guest_state)
2053 ar = 0; 2070 ar = 0;
2054 var->type = ar & 15; 2071 var->type = ar & 15;
@@ -2062,6 +2079,18 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
2062 var->unusable = (ar >> 16) & 1; 2079 var->unusable = (ar >> 16) & 1;
2063} 2080}
2064 2081
2082static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
2083{
2084 struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
2085 struct kvm_segment s;
2086
2087 if (to_vmx(vcpu)->rmode.vm86_active) {
2088 vmx_get_segment(vcpu, &s, seg);
2089 return s.base;
2090 }
2091 return vmcs_readl(sf->base);
2092}
2093
2065static int vmx_get_cpl(struct kvm_vcpu *vcpu) 2094static int vmx_get_cpl(struct kvm_vcpu *vcpu)
2066{ 2095{
2067 if (!is_protmode(vcpu)) 2096 if (!is_protmode(vcpu))