@@ -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