Fix x86/32 do_iret implementation, fixes VM86 mode.
authorIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Fri, 13 Jan 2006 11:04:04 +0000 (11:04 +0000)
committerIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Fri, 13 Jan 2006 11:04:04 +0000 (11:04 +0000)
Do not clobber a freshly restored esp when performing an iret.

Signed-off-by: Keir Fraser <keir@xensource.com>
Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
xen/arch/x86/x86_32/traps.c

index e9c98d8aa815681339a163dc65523a29b18410b3..95b69a14bdced0f12fd1f5a5006d873d2b5ef9bc 100644 (file)
@@ -157,14 +157,6 @@ asmlinkage void do_double_fault(void)
         __asm__ __volatile__ ( "hlt" );
 }
 
-static inline void pop_from_guest_stack(
-    void *dst, struct cpu_user_regs *regs, unsigned int bytes)
-{
-    if ( unlikely(__copy_from_user(dst, (void __user *)regs->esp, bytes)) )
-        domain_crash_synchronous();
-    regs->esp += bytes;
-}
-
 asmlinkage unsigned long do_iret(void)
 {
     struct cpu_user_regs *regs = guest_cpu_user_regs();
@@ -175,22 +167,29 @@ asmlinkage unsigned long do_iret(void)
         domain_crash_synchronous();
 
     /* Pop and restore EAX (clobbered by hypercall). */
-    pop_from_guest_stack(&regs->eax, regs, 4);
+    if ( unlikely(__copy_from_user(&regs->eax, (void __user *)regs->esp, 4)) )
+        domain_crash_synchronous();
+    regs->esp += 4;
 
     /* Pop and restore CS and EIP. */
-    pop_from_guest_stack(&regs->eip, regs, 8);
+    if ( unlikely(__copy_from_user(&regs->eip, (void __user *)regs->esp, 8)) )
+        domain_crash_synchronous();
+    regs->esp += 8;
 
     /*
      * Pop, fix up and restore EFLAGS. We fix up in a local staging area
      * to avoid firing the BUG_ON(IOPL) check in arch_getdomaininfo_ctxt.
      */
-    pop_from_guest_stack(&eflags, regs, 4);
+    if ( unlikely(__copy_from_user(&eflags, (void __user *)regs->esp, 4)) )
+        domain_crash_synchronous();
+    regs->esp += 4;
     regs->eflags = (eflags & ~X86_EFLAGS_IOPL) | X86_EFLAGS_IF;
 
     if ( VM86_MODE(regs) )
     {
         /* Return to VM86 mode: pop and restore ESP,SS,ES,DS,FS and GS. */
-        pop_from_guest_stack(&regs->esp, regs, 24);
+        if ( __copy_from_user(&regs->esp, (void __user *)regs->esp, 24) )
+            domain_crash_synchronous();
     }
     else if ( unlikely(RING_0(regs)) )
     {
@@ -199,7 +198,8 @@ asmlinkage unsigned long do_iret(void)
     else if ( !RING_1(regs) )
     {
         /* Return to ring 2/3: pop and restore ESP and SS. */
-        pop_from_guest_stack(&regs->esp, regs, 8);
+        if ( __copy_from_user(&regs->esp, (void __user *)regs->esp, 8) )
+            domain_crash_synchronous();
     }
 
     /* No longer in NMI context. */