diff options
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/entry.S | 3 | ||||
-rw-r--r-- | arch/i386/kernel/process.c | 12 |
2 files changed, 14 insertions, 1 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 1e45ff292bc9..3c73dc865ead 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S | |||
@@ -245,6 +245,9 @@ syscall_exit: | |||
245 | 245 | ||
246 | restore_all: | 246 | restore_all: |
247 | movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS | 247 | movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS |
248 | # Warning: OLDSS(%esp) contains the wrong/random values if we | ||
249 | # are returning to the kernel. | ||
250 | # See comments in process.c:copy_thread() for details. | ||
248 | movb OLDSS(%esp), %ah | 251 | movb OLDSS(%esp), %ah |
249 | movb CS(%esp), %al | 252 | movb CS(%esp), %al |
250 | andl $(VM_MASK | (4 << 8) | 3), %eax | 253 | andl $(VM_MASK | (4 << 8) | 3), %eax |
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index c36fedf40e95..36145efc61b5 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c | |||
@@ -405,7 +405,17 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, | |||
405 | childregs->esp = esp; | 405 | childregs->esp = esp; |
406 | 406 | ||
407 | p->thread.esp = (unsigned long) childregs; | 407 | p->thread.esp = (unsigned long) childregs; |
408 | p->thread.esp0 = (unsigned long) (childregs+1); | 408 | /* |
409 | * The below -8 is to reserve 8 bytes on top of the ring0 stack. | ||
410 | * This is necessary to guarantee that the entire "struct pt_regs" | ||
411 | * is accessable even if the CPU haven't stored the SS/ESP registers | ||
412 | * on the stack (interrupt gate does not save these registers | ||
413 | * when switching to the same priv ring). | ||
414 | * Therefore beware: accessing the xss/esp fields of the | ||
415 | * "struct pt_regs" is possible, but they may contain the | ||
416 | * completely wrong values. | ||
417 | */ | ||
418 | p->thread.esp0 = (unsigned long) (childregs+1) - 8; | ||
409 | 419 | ||
410 | p->thread.eip = (unsigned long) ret_from_fork; | 420 | p->thread.eip = (unsigned long) ret_from_fork; |
411 | 421 | ||