bitkeeper revision 1.1236.25.22 (4235e4fbkgMjr8FNbH_NCE7pnfV92g)
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 14 Mar 2005 19:24:43 +0000 (19:24 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Mon, 14 Mar 2005 19:24:43 +0000 (19:24 +0000)
Inform guest kernel whether it interrupts kernel or user context
by using RPL of saved CS selector (0 == kernel context;
3 == user context). Add some security checking and enforcement to
switch_to_user hypercall.

xen/arch/x86/domain.c
xen/arch/x86/x86_32/mm.c
xen/arch/x86/x86_64/entry.S
xen/arch/x86/x86_64/mm.c
xen/include/asm-x86/desc.h

index 44638b854308f7b9fd1889b375949926af40f7f2..5f0a0b8ece7bc662b35e0d712d153d43eadba55e 100644 (file)
@@ -655,11 +655,10 @@ static void switch_segments(
             (unsigned long *)regs->rsp : 
             (unsigned long *)n->arch.kernel_sp;
 
-        /* Set the kernel-mode indicator byte at the top of RFLAGS. */
-        ((char *)regs->rflags)[7] = !!(n->arch.flags & TF_kernel_mode);
-
         if ( !(n->arch.flags & TF_kernel_mode) )
             toggle_guest_mode(n);
+        else
+            regs->cs &= ~3;
 
         if ( put_user(regs->ss,     rsp- 1) |
              put_user(regs->rsp,    rsp- 2) |
@@ -699,10 +698,10 @@ long do_switch_to_user(void)
     toggle_guest_mode(ed);
 
     regs->rip    = stu.rip;
-    regs->cs     = stu.cs;
+    regs->cs     = stu.cs | 3; /* force guest privilege */
     regs->rflags = stu.rflags;
     regs->rsp    = stu.rsp;
-    regs->ss     = stu.ss;
+    regs->ss     = stu.ss | 3; /* force guest privilege */
 
     if ( !(stu.flags & ECF_IN_SYSCALL) )
     {
index db77bbe8c000a7cafc2066ad87b1f80bcd51a5d5..2f3ce50c5cbce68b56e72648467a3cce8849a126 100644 (file)
@@ -202,8 +202,7 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
     int nr = smp_processor_id();
     struct tss_struct *t = &init_tss[nr];
 
-    /* We need to do this check as we load and use SS on guest's behalf. */
-    if ( (ss & 3) == 0 )
+    if ( (ss & 3) != 1 )
         return -EPERM;
 
     current->arch.kernel_ss = ss;
@@ -275,21 +274,9 @@ int check_descriptor(struct desc_struct *d)
     if ( (b & _SEGMENT_G) )
         limit <<= 12;
 
-    if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
-    {
-        /*
-         * Grows-down limit check. 
-         * NB. limit == 0xFFFFF provides no access      (if G=1).
-         *     limit == 0x00000 provides 4GB-4kB access (if G=1).
-         */
-        if ( (base + limit) > base )
-        {
-            limit = -(base & PAGE_MASK);
-            goto truncate;
-        }
-    }
-    else
+    switch ( b & (_SEGMENT_CODE | _SEGMENT_EC) )
     {
+    case 0: /* Data segment, grows-up */
         /*
          * Grows-up limit check.
          * NB. limit == 0xFFFFF provides 4GB access (if G=1).
@@ -306,6 +293,23 @@ int check_descriptor(struct desc_struct *d)
             d->a &= ~0x0ffff; d->a |= limit & 0x0ffff;
             d->b &= ~0xf0000; d->b |= limit & 0xf0000;
         }
+        goto good;
+    case _SEGMENT_EC: /* Data segment, grows-down */
+        /*
+         * Grows-down limit check. 
+         * NB. limit == 0xFFFFF provides no access      (if G=1).
+         *     limit == 0x00000 provides 4GB-4kB access (if G=1).
+         */
+        if ( (base + limit) > base )
+        {
+            limit = -(base & PAGE_MASK);
+            goto truncate;
+        }
+        goto good;
+    case _SEGMENT_CODE: /* Code segment, non-conforming */
+        goto good;
+    case _SEGMENT_CODE|_SEGMENT_EC: /* Code segment, conforming */
+        goto bad;
     }
 
  good:
index 912ed7b0d1d5dc5855a106a7422af4e18bdb9048..16b5850d60c6e098ce4d6f84e7d78b5714d5caeb 100644 (file)
@@ -162,20 +162,19 @@ process_softirqs:
 /* %rdx: trap_bounce, %rbx: struct exec_domain                           */
 /* On return only %rbx is guaranteed non-clobbered.                      */
 create_bounce_frame:
-        /* Push new frame at existing %rsp if already in guest-OS mode. */
-        movq  XREGS_rsp+8(%rsp),%rsi
         testb $TF_kernel_mode,EDOMAIN_thread_flags(%rbx)
-        /* Set kernel-mode indicator byte (RFLAGS[63:56]). */
-        setnz XREGS_eflags+15(%rsp)
         jnz   1f
         /* Push new frame at registered guest-OS stack base. */
-        /* Then call to C: toggle_guest_mode(current) */
         movq  EDOMAIN_kernel_sp(%rbx),%rsi
-        movq  %rbx,%rdi
         pushq %rdx
+        movq  %rbx,%rdi
         call  SYMBOL_NAME(toggle_guest_mode)
         popq  %rdx
-1:      movq  $HYPERVISOR_VIRT_START,%rax
+        jmp   2f
+1:      /* In kernel context already: push new frame at existing %rsp. */
+        movq  XREGS_rsp+8(%rsp),%rsi
+        andb  $0xfc,XREGS_cs+8(%rsp)    # Indicate kernel context to guest.
+2:      movq  $HYPERVISOR_VIRT_START,%rax
         cmpq  %rax,%rsi
         jb    1f                        # In +ve address space? Then okay.
         movq  $HYPERVISOR_VIRT_END+60,%rax
index b0de7df3295d171b4504e028b0af2430affe22e0..aeee7fc0ba6f39fdf1507ad96fd8cf6e6963d7c6 100644 (file)
@@ -287,9 +287,14 @@ int check_descriptor(struct desc_struct *d)
     if ( (b & _SEGMENT_DPL) != 3 )
         goto bad;
 
-    /* Any code or data segment is okay. No base/limit checking. */
+    /* Most code and data segments are okay. No base/limit checking. */
     if ( (b & _SEGMENT_S) )
+    {
+        /* Disallow conforming code segments. I'm not sure they're safe. */
+        if ( (b & (_SEGMENT_CODE|_SEGMENT_EC)) == (_SEGMENT_CODE|_SEGMENT_EC) )
+            goto bad;
         goto good;
+    }
 
     /* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
     if ( (b & _SEGMENT_TYPE) == 0x000 )
index 39732982a0b791c18e42965f8a560e6a0bfe2405..a05bb752e9f48ab5b6dbeb930e43f7aab7ab07b9 100644 (file)
@@ -6,18 +6,23 @@
 
 #define load_TR(n)  __asm__ __volatile__ ("ltr  %%ax" : : "a" (__TSS(n)<<3) )
 
+#if defined(__x86_64__)
+#define GUEST_KERNEL_RPL 3
+#elif defined(__i386__)
+#define GUEST_KERNEL_RPL 1
+#endif
+
 /*
- * Guest OS must provide its own code selectors, or use the one we provide. The
- * RPL must be 1, as we only create bounce frames to ring 1. Any LDT selector
- * value is okay. Note that checking only the RPL is insufficient: if the
- * selector is poked into an interrupt, trap or call gate then the RPL is
- * ignored when the gate is accessed.
+ * Guest OS must provide its own code selectors, or use the one we provide. Any
+ * LDT selector value is okay. Note that checking only the RPL is insufficient:
+ * if the selector is poked into an interrupt, trap or call gate then the RPL
+ * is ignored when the gate is accessed.
  */
 #define VALID_SEL(_s)                                                      \
     (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) ||                            \
       (((_s)>>3) >  LAST_RESERVED_GDT_ENTRY) ||                            \
       ((_s)&4)) &&                                                         \
-     (((_s)&3) == 1))
+     (((_s)&3) == GUEST_KERNEL_RPL))
 #define VALID_CODESEL(_s) ((_s) == FLAT_KERNEL_CS || VALID_SEL(_s))
 
 /* These are bitmasks for the high 32 bits of a descriptor table entry. */