diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-18 19:20:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-18 19:20:40 -0400 |
commit | 47a5c6fa0e204a2b63309c648bb2fde36836c826 (patch) | |
tree | 688b6c12c72fed720dc4a047f310cd292e88a6f1 | |
parent | 1d19f176a2884d31c4fe2c7018349ff884a819b1 (diff) |
x86: save/restore eflags in context switch
(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>
-rw-r--r-- | arch/i386/kernel/entry.S | 4 | ||||
-rw-r--r-- | include/asm-i386/system.h | 8 |
2 files changed, 11 insertions, 1 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 37a7d2eaf4a..87f9f60b803 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S | |||
@@ -209,6 +209,10 @@ ENTRY(ret_from_fork) | |||
209 | GET_THREAD_INFO(%ebp) | 209 | GET_THREAD_INFO(%ebp) |
210 | popl %eax | 210 | popl %eax |
211 | CFI_ADJUST_CFA_OFFSET -4 | 211 | CFI_ADJUST_CFA_OFFSET -4 |
212 | pushl $0x0202 # Reset kernel eflags | ||
213 | CFI_ADJUST_CFA_OFFSET 4 | ||
214 | popfl | ||
215 | CFI_ADJUST_CFA_OFFSET -4 | ||
212 | jmp syscall_exit | 216 | jmp syscall_exit |
213 | CFI_ENDPROC | 217 | CFI_ENDPROC |
214 | 218 | ||
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index 49928eb33f8..098bcee94e3 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h | |||
@@ -11,9 +11,14 @@ | |||
11 | struct task_struct; /* one of the stranger aspects of C forward declarations.. */ | 11 | struct task_struct; /* one of the stranger aspects of C forward declarations.. */ |
12 | extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); | 12 | extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); |
13 | 13 | ||
14 | /* | ||
15 | * Saving eflags is important. It switches not only IOPL between tasks, | ||
16 | * it also protects other tasks from NT leaking through sysenter etc. | ||
17 | */ | ||
14 | #define switch_to(prev,next,last) do { \ | 18 | #define switch_to(prev,next,last) do { \ |
15 | unsigned long esi,edi; \ | 19 | unsigned long esi,edi; \ |
16 | asm volatile("pushl %%ebp\n\t" \ | 20 | asm volatile("pushfl\n\t" /* Save flags */ \ |
21 | "pushl %%ebp\n\t" \ | ||
17 | "movl %%esp,%0\n\t" /* save ESP */ \ | 22 | "movl %%esp,%0\n\t" /* save ESP */ \ |
18 | "movl %5,%%esp\n\t" /* restore ESP */ \ | 23 | "movl %5,%%esp\n\t" /* restore ESP */ \ |
19 | "movl $1f,%1\n\t" /* save EIP */ \ | 24 | "movl $1f,%1\n\t" /* save EIP */ \ |
@@ -21,6 +26,7 @@ extern struct task_struct * FASTCALL(__switch_to(struct task_struct *prev, struc | |||
21 | "jmp __switch_to\n" \ | 26 | "jmp __switch_to\n" \ |
22 | "1:\t" \ | 27 | "1:\t" \ |
23 | "popl %%ebp\n\t" \ | 28 | "popl %%ebp\n\t" \ |
29 | "popfl" \ | ||
24 | :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \ | 30 | :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \ |
25 | "=a" (last),"=S" (esi),"=D" (edi) \ | 31 | "=a" (last),"=S" (esi),"=D" (edi) \ |
26 | :"m" (next->thread.esp),"m" (next->thread.eip), \ | 32 | :"m" (next->thread.esp),"m" (next->thread.eip), \ |