x86: save/restore eflags in context switch
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 18 Sep 2006 23:20:40 +0000 (16:20 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 18 Sep 2006 23:20:40 +0000 (16:20 -0700)
(And reset it on new thread creation)

It turns out that eflags is important to save and restore not just
because of iopl, but due to the magic bits like the NT bit, which we
don't want leaking between different threads.

Tested-by: Mike Galbraith <efault@gmx.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/kernel/entry.S
include/asm-i386/system.h

index 37a7d2eaf4a006608a8321647b96e7323c05e998..87f9f60b803be12deb178df607c169a6cb333afb 100644 (file)
@@ -209,6 +209,10 @@ ENTRY(ret_from_fork)
        GET_THREAD_INFO(%ebp)
        popl %eax
        CFI_ADJUST_CFA_OFFSET -4
+       pushl $0x0202                   # Reset kernel eflags
+       CFI_ADJUST_CFA_OFFSET 4
+       popfl
+       CFI_ADJUST_CFA_OFFSET -4
        jmp syscall_exit
        CFI_ENDPROC
 
index 49928eb33f8bbd830ac1937a7ff5b50de1adec5d..098bcee94e389a615b3b2327fa2be03f117c28c3 100644 (file)
 struct task_struct;    /* one of the stranger aspects of C forward declarations.. */
 extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
 
+/*
+ * Saving eflags is important. It switches not only IOPL between tasks,
+ * it also protects other tasks from NT leaking through sysenter etc.
+ */
 #define switch_to(prev,next,last) do {                                 \
        unsigned long esi,edi;                                          \
-       asm volatile("pushl %%ebp\n\t"                                  \
+       asm volatile("pushfl\n\t"               /* Save flags */        \
+                    "pushl %%ebp\n\t"                                  \
                     "movl %%esp,%0\n\t"        /* save ESP */          \
                     "movl %5,%%esp\n\t"        /* restore ESP */       \
                     "movl $1f,%1\n\t"          /* save EIP */          \
@@ -21,6 +26,7 @@ extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struc
                     "jmp __switch_to\n"                                \
                     "1:\t"                                             \
                     "popl %%ebp\n\t"                                   \
+                    "popfl"                                            \
                     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),  \
                      "=a" (last),"=S" (esi),"=D" (edi)                 \
                     :"m" (next->thread.esp),"m" (next->thread.eip),    \