Skip to content

Commit 6d9256f

Browse files
amlutoIngo Molnar
authored andcommitted
x86/espfix/64: Stop assuming that pt_regs is on the entry stack
When we start using an entry trampoline, a #GP from userspace will be delivered on the entry stack, not on the task stack. Fix the espfix64 #DF fixup to set up #GP according to TSS.SP0, rather than assuming that pt_regs + 1 == SP0. This won't change anything without an entry stack, but it will make the code continue to work when an entry stack is added. While we're at it, improve the comments to explain what's actually going on. Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Borislav Petkov <bp@suse.de> Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Borislav Petkov <bpetkov@suse.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: David Laight <David.Laight@aculab.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Eduardo Valentin <eduval@amazon.com> Cc: Greg KH <gregkh@linuxfoundation.org> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rik van Riel <riel@redhat.com> Cc: Will Deacon <will.deacon@arm.com> Cc: aliguori@amazon.com Cc: daniel.gruss@iaik.tugraz.at Cc: hughd@google.com Cc: keescook@google.com Link: https://lkml.kernel.org/r/20171204150606.130778051@linutronix.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 9aaefe7 commit 6d9256f

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed

arch/x86/kernel/traps.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -348,23 +348,42 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
348348

349349
/*
350350
* If IRET takes a non-IST fault on the espfix64 stack, then we
351-
* end up promoting it to a doublefault. In that case, modify
352-
* the stack to make it look like we just entered the #GP
353-
* handler from user space, similar to bad_iret.
351+
* end up promoting it to a doublefault. In that case, take
352+
* advantage of the fact that we're not using the normal (TSS.sp0)
353+
* stack right now. We can write a fake #GP(0) frame at TSS.sp0
354+
* and then modify our own IRET frame so that, when we return,
355+
* we land directly at the #GP(0) vector with the stack already
356+
* set up according to its expectations.
357+
*
358+
* The net result is that our #GP handler will think that we
359+
* entered from usermode with the bad user context.
354360
*
355361
* No need for ist_enter here because we don't use RCU.
356362
*/
357363
if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY &&
358364
regs->cs == __KERNEL_CS &&
359365
regs->ip == (unsigned long)native_irq_return_iret)
360366
{
361-
struct pt_regs *normal_regs = task_pt_regs(current);
367+
struct pt_regs *gpregs = (struct pt_regs *)this_cpu_read(cpu_tss.x86_tss.sp0) - 1;
368+
369+
/*
370+
* regs->sp points to the failing IRET frame on the
371+
* ESPFIX64 stack. Copy it to the entry stack. This fills
372+
* in gpregs->ss through gpregs->ip.
373+
*
374+
*/
375+
memmove(&gpregs->ip, (void *)regs->sp, 5*8);
376+
gpregs->orig_ax = 0; /* Missing (lost) #GP error code */
362377

363-
/* Fake a #GP(0) from userspace. */
364-
memmove(&normal_regs->ip, (void *)regs->sp, 5*8);
365-
normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */
378+
/*
379+
* Adjust our frame so that we return straight to the #GP
380+
* vector with the expected RSP value. This is safe because
381+
* we won't enable interupts or schedule before we invoke
382+
* general_protection, so nothing will clobber the stack
383+
* frame we just set up.
384+
*/
366385
regs->ip = (unsigned long)general_protection;
367-
regs->sp = (unsigned long)&normal_regs->orig_ax;
386+
regs->sp = (unsigned long)&gpregs->orig_ax;
368387

369388
return;
370389
}
@@ -389,7 +408,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
389408
*
390409
* Processors update CR2 whenever a page fault is detected. If a
391410
* second page fault occurs while an earlier page fault is being
392-
* deliv- ered, the faulting linear address of the second fault will
411+
* delivered, the faulting linear address of the second fault will
393412
* overwrite the contents of CR2 (replacing the previous
394413
* address). These updates to CR2 occur even if the page fault
395414
* results in a double fault or occurs during the delivery of a

0 commit comments

Comments
 (0)