Module Name:    src
Committed By:   dsl
Date:           Sun Jan 10 15:21:36 UTC 2010

Modified Files:
        src/sys/arch/i386/i386: trap.c vector.S

Log Message:
If we fault on the 'iret' during return to userpace (eg if %eip is outside
the bounds of %cs) then hack the stack to contain a normal fault frame
for the signal setup code (etc).
Previously the code assumed that the original user trap frame was still
present - at it is for faults when loading the segment registers.


To generate a diff of this commit:
cvs rdiff -u -r1.250 -r1.251 src/sys/arch/i386/i386/trap.c
cvs rdiff -u -r1.49 -r1.50 src/sys/arch/i386/i386/vector.S

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/i386/i386/trap.c
diff -u src/sys/arch/i386/i386/trap.c:1.250 src/sys/arch/i386/i386/trap.c:1.251
--- src/sys/arch/i386/i386/trap.c:1.250	Sat Nov 21 03:11:00 2009
+++ src/sys/arch/i386/i386/trap.c	Sun Jan 10 15:21:36 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap.c,v 1.250 2009/11/21 03:11:00 rmind Exp $	*/
+/*	$NetBSD: trap.c,v 1.251 2010/01/10 15:21:36 dsl Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.250 2009/11/21 03:11:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.251 2010/01/10 15:21:36 dsl Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -123,6 +123,7 @@
 static inline int xmm_si_code(struct lwp *);
 void trap(struct trapframe *);
 void trap_tss(struct i386tss *, int, int);
+void trap_return_iret(struct trapframe *) __dead;
 
 #ifdef KVM86
 #include <machine/kvm86.h>
@@ -406,11 +407,33 @@
 		 * the kernel stack; we presume here that we faulted while
 		 * loading our registers out of the outer one.
 		 */
+
+		KSI_INIT_TRAP(&ksi);
+		ksi.ksi_signo = SIGSEGV;
+		/* There is no fault address! */
+		ksi.ksi_code = SEGV_ACCERR;
+		ksi.ksi_trap = type;
+
 		switch (*(u_char *)frame->tf_eip) {
 		case 0xcf:	/* iret */
-			vframe = (void *)((int)&frame->tf_esp -
+			/*
+			 * The outer trap frame only contains the user space
+			 * return address and stack pointer.
+			 * The user registers are in the inner frame following
+			 * the kernel address of the iret.
+			 * We must copy the registers next to the userspace
+			 * return address so we have a frame for md_regs.
+			 */
+			vframe = (void *)((int *)frame + 3);
+			if (KERNELMODE(vframe->tf_cs, vframe->tf_eflags))
+				goto we_re_toast;
+			memmove(vframe, frame,
 			    offsetof(struct trapframe, tf_eip));
-			break;
+			l->l_md.md_regs = vframe;
+			ksi.ksi_addr = (void *)vframe->tf_eip;
+			(*p->p_emul->e_trapsignal)(l, &ksi);
+			trap_return_iret(vframe);
+			/* NOTREACHED */
 		case 0x8e:
 			switch (*(uint32_t *)frame->tf_eip) {
 			case 0x0c245c8e:	/* movl 0xc(%esp,1),%ds */
@@ -421,11 +444,12 @@
 			default:
 				goto we_re_toast;
 			}
-			vframe = (void *)(int)&frame->tf_esp;
 			break;
 		default:
 			goto we_re_toast;
 		}
+
+		vframe = (void *)(int)&frame->tf_esp;
 		if (KERNELMODE(vframe->tf_cs, vframe->tf_eflags))
 			goto we_re_toast;
 
@@ -445,17 +469,16 @@
 		 * continue to generate traps infinitely with
 		 * interrupts disabled.
 		 */
+		/* We don't want to fault unwinding the inner frame */
 		frame->tf_ds = GSEL(GDATA_SEL, SEL_KPL);
 		frame->tf_es = GSEL(GDATA_SEL, SEL_KPL);
 		frame->tf_gs = GSEL(GDATA_SEL, SEL_KPL);
 		frame->tf_fs = GSEL(GCPU_SEL, SEL_KPL);
+		/* Reload the entire outer (user) frame */
 		frame->tf_eip = (uintptr_t)trapreturn;
 		frame->tf_eflags = (frame->tf_eflags & ~PSL_NT) | PSL_I;
-		KSI_INIT_TRAP(&ksi);
-		ksi.ksi_signo = SIGSEGV;
-		ksi.ksi_addr = (void *)rcr2();
-		ksi.ksi_code = SEGV_ACCERR;
-		ksi.ksi_trap = type & ~T_USER;
+		/* Save outer frame for any signal return */
+		l->l_md.md_regs = vframe;
 		(*p->p_emul->e_trapsignal)(l, &ksi);
 		return;
 

Index: src/sys/arch/i386/i386/vector.S
diff -u src/sys/arch/i386/i386/vector.S:1.49 src/sys/arch/i386/i386/vector.S:1.50
--- src/sys/arch/i386/i386/vector.S:1.49	Wed Nov 25 14:28:50 2009
+++ src/sys/arch/i386/i386/vector.S	Sun Jan 10 15:21:36 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: vector.S,v 1.49 2009/11/25 14:28:50 rmind Exp $	*/
+/*	$NetBSD: vector.S,v 1.50 2010/01/10 15:21:36 dsl Exp $	*/
 
 /*
  * Copyright 2002 (c) Wasabi Systems, Inc.
@@ -65,7 +65,7 @@
  */
 
 #include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.49 2009/11/25 14:28:50 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.50 2010/01/10 15:21:36 dsl Exp $");
 
 #include "opt_ddb.h"
 #include "opt_multiprocessor.h"
@@ -1036,6 +1036,10 @@
 	iret
 	jmp	1b
 
+_C_LABEL(trap_return_iret):	.globl	trap_return_iret
+	mov	4(%esp),%esp	/* frame for user return */
+	jmp	_C_LABEL(trapreturn)
+
 /* LINTSTUB: Ignore */
 NENTRY(alltraps)
 	INTRENTRY

Reply via email to