[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] x86: segment attribute handling adjustments



commit 366ff5f1b3252f9069d5aedb2ffc2567bb0a37c9
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Fri Jan 20 14:39:12 2017 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Fri Jan 20 14:39:12 2017 +0100

    x86: segment attribute handling adjustments
    
    Null selector loads into SS (possible in 64-bit mode only, and only in
    rings other than ring 3) must not alter SS.DPL. (This was found to be
    an issue on KVM, and fixed in Linux commit 33ab91103b.)
    
    Further arch_set_info_hvm_guest() didn't make sure that the ASSERT()s
    in hvm_set_segment_register() wouldn't trigger: Add further checks, but
    tolerate (adjust) clear accessed (CS, SS, DS, ES) and busy (TR) bits.
    
    Finally the setting of the accessed bits for user segments was lost by
    commit dd5c85e312 ("x86/hvm: Reposition the modification of raw segment
    data from the VMCB/VMCS"), yet VMX requires them to be set for usable
    segments. Add respective ASSERT()s (the only path not properly setting
    them was arch_set_info_hvm_guest()).
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
 xen/arch/x86/domain.c                  | 25 +++++++++++++++++--------
 xen/arch/x86/hvm/hvm.c                 |  4 ++++
 xen/arch/x86/x86_emulate/x86_emulate.c |  5 +++++
 3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 3409054..5a4e7f9 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1294,16 +1294,24 @@ static inline int check_segment(struct segment_register 
*reg,
         return 0;
     }
 
-    if ( seg != x86_seg_tr && !reg->attr.fields.s )
+    if ( seg == x86_seg_tr )
     {
-        gprintk(XENLOG_ERR,
-                "System segment provided for a code or data segment\n");
-        return -EINVAL;
-    }
+        if ( reg->attr.fields.s )
+        {
+            gprintk(XENLOG_ERR, "Code or data segment provided for TR\n");
+            return -EINVAL;
+        }
 
-    if ( seg == x86_seg_tr && reg->attr.fields.s )
+        if ( reg->attr.fields.type != SYS_DESC_tss_busy )
+        {
+            gprintk(XENLOG_ERR, "Non-32-bit-TSS segment provided for TR\n");
+            return -EINVAL;
+        }
+    }
+    else if ( !reg->attr.fields.s )
     {
-        gprintk(XENLOG_ERR, "Code or data segment provided for TR\n");
+        gprintk(XENLOG_ERR,
+                "System segment provided for a code or data segment\n");
         return -EINVAL;
     }
 
@@ -1366,7 +1374,8 @@ int arch_set_info_hvm_guest(struct vcpu *v, const 
vcpu_hvm_context_t *ctx)
 #define SEG(s, r) ({                                                        \
     s = (struct segment_register){ .base = (r)->s ## _base,                 \
                                    .limit = (r)->s ## _limit,               \
-                                   .attr.bytes = (r)->s ## _ar };           \
+                                   .attr.bytes = (r)->s ## _ar |            \
+                                       (x86_seg_##s != x86_seg_tr ? 1 : 2) }; \
     check_segment(&s, x86_seg_ ## s); })
 
         rc = SEG(cs, regs);
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 63748dc..6ab60d2 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -5731,6 +5731,7 @@ void hvm_set_segment_register(struct vcpu *v, enum 
x86_segment seg,
     case x86_seg_cs:
         ASSERT(reg->attr.fields.p);                  /* Usable. */
         ASSERT(reg->attr.fields.s);                  /* User segment. */
+        ASSERT(reg->attr.fields.type & 0x1);         /* Accessed. */
         ASSERT((reg->base >> 32) == 0);              /* Upper bits clear. */
         break;
 
@@ -5740,6 +5741,7 @@ void hvm_set_segment_register(struct vcpu *v, enum 
x86_segment seg,
             ASSERT(reg->attr.fields.s);              /* User segment. */
             ASSERT(!(reg->attr.fields.type & 0x8));  /* Data segment. */
             ASSERT(reg->attr.fields.type & 0x2);     /* Writeable. */
+            ASSERT(reg->attr.fields.type & 0x1);     /* Accessed. */
             ASSERT((reg->base >> 32) == 0);          /* Upper bits clear. */
         }
         break;
@@ -5755,6 +5757,8 @@ void hvm_set_segment_register(struct vcpu *v, enum 
x86_segment seg,
             if ( reg->attr.fields.type & 0x8 )
                 ASSERT(reg->attr.fields.type & 0x2); /* Readable. */
 
+            ASSERT(reg->attr.fields.type & 0x1);     /* Accessed. */
+
             if ( seg == x86_seg_fs || seg == x86_seg_gs )
                 ASSERT(is_canonical_address(reg->base));
             else
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c 
b/xen/arch/x86/x86_emulate/x86_emulate.c
index 1c76379..2810c73 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -1471,6 +1471,11 @@ protmode_load_seg(
         else
             sreg->attr.bytes = 0;
         sreg->sel = sel;
+
+        /* Since CPL == SS.DPL, we need to put back DPL. */
+        if ( seg == x86_seg_ss )
+            sreg->attr.fields.dpl = sel;
+
         return X86EMUL_OKAY;
     }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.