Module Name:    src
Committed By:   maxv
Date:           Tue Mar 20 18:27:58 UTC 2018

Modified Files:
        src/sys/arch/amd64/amd64: amd64_trap.S locore.S

Log Message:
(Re)Fix handling of segment register faults. My previous attempt did fix
faults occuring when reloading %es/%ds/%fs/%gs, but it did not fix faults
occuring when executing 'iretq', because before iretq we needed to do +16
in %rsp, and the resulting stack layout was not the one kernuser_reenter()
expected (tf_trapno and tf_err were not there).

So now: pop tf_trapno and tf_err right away in intrfastexit(), and update
the layout in kernuser_reenter() accordingly. The resulting code is
actually simpler.

Tested by "hardcoding" an iretq fault; the process correctly receives a
SIGSEGV.

(Note that segment register faults do not happen in the wild, you really
need to try hard to trigger one.)


To generate a diff of this commit:
cvs rdiff -u -r1.38 -r1.39 src/sys/arch/amd64/amd64/amd64_trap.S
cvs rdiff -u -r1.158 -r1.159 src/sys/arch/amd64/amd64/locore.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/amd64/amd64/amd64_trap.S
diff -u src/sys/arch/amd64/amd64/amd64_trap.S:1.38 src/sys/arch/amd64/amd64/amd64_trap.S:1.39
--- src/sys/arch/amd64/amd64/amd64_trap.S:1.38	Tue Mar 20 14:26:49 2018
+++ src/sys/arch/amd64/amd64/amd64_trap.S	Tue Mar 20 18:27:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: amd64_trap.S,v 1.38 2018/03/20 14:26:49 maxv Exp $	*/
+/*	$NetBSD: amd64_trap.S,v 1.39 2018/03/20 18:27:58 maxv Exp $	*/
 
 /*
  * Copyright (c) 1998, 2007, 2008, 2017 The NetBSD Foundation, Inc.
@@ -388,8 +388,8 @@ IDTVEC_END(intrspurious)
  * When this happens, the kernel is re-entered in kernel mode, but the
  * previous context is in kernel mode too.
  *
- * We have two iret frames in the stack. In the first one, the 'rsp' field
- * points to the outer iret frame:
+ * We have two iret frames in the stack. In the first one, we also pushed
+ * 'trapno' and 'err'. The 'rsp' field points to the outer iret frame:
  *
  * +---------------------------------------------------+
  * | trapno | err | rip | cs=ring0 | rflags | rsp | ss |
@@ -397,19 +397,19 @@ IDTVEC_END(intrspurious)
  *                                             |
  *           +---------------------------------+
  *           |
- *           |    +---------------------------------------------------+
- *           +--> | trapno | err | rip | cs=ring3 | rflags | rsp | ss |
- *                +---------------------------------------------------+
+ *           |    +------------------------------------+
+ *           +--> | rip | cs=ring3 | rflags | rsp | ss |
+ *                +------------------------------------+
  *
  * We perform a three-step procedure:
  *
- *  o We copy the 'trapno' field of the current frame into the 'trapno'
- *    field of the outer frame.
- *
  *  o We update RSP to point to the outer frame. This outer frame is in the
  *    same stack as the current frame, and likely just after the current
  *    frame.
  *
+ *  o We push, in this outer frame, the 'err' and 'trapno' fields of the
+ *    CURRENT frame.
+ *
  *  o We do a normal INTRENTRY. Now that RSP points to the outer frame,
  *    everything behaves as if we had received a trap from the outer frame,
  *    that is to say, from userland directly.
@@ -429,7 +429,7 @@ IDTVEC_END(intrspurious)
  *    stack (nested), and would double-fault because it touches the redzone
  *    below the stack (see the documentation in x86/x86/svs.c). By popping
  *    the GPR part of the stack, we leave enough stack for the CPU to push
- *    an iret frame, and for us to push two 8-byte registers too.
+ *    an iret frame, and for us to push one 8-byte register (%rdi) too.
  */
 	_ALIGN_TEXT
 LABEL(kernuser_reenter)
@@ -480,14 +480,19 @@ LABEL(kernuser_reenter)
 	jmp	.Lnormal_entry
 
 .Lkernelmode_but_user:
-	movq	TF_SMALL_REGPUSHED(TF_RSP, %rsp),%rdi
+	/*
+	 * Here we have %rdi pushed on the stack, hence 8+.
+	 */
+	movq	%rsp,%rdi
+	movq	TF_SMALL_REGPUSHED(TF_RSP, %rsp),%rsp
+
+	/* Push tf_err and tf_trapno */
+	pushq	8+8(%rdi)	/* 8+8(%rdi) = current TF_ERR */
+	pushq	8+0(%rdi)	/* 8+0(%rdi) = current TF_TRAPNO */
 
-	pushq	%rax
-	movq	16(%rsp),%rax	/* 16(%rsp) = current TF_TRAPNO */
-	movq	%rax,(%rdi)	/* (%rdi) = outer TF_TRAPNO */
-	popq	%rax
+	/* Restore %rdi */
+	movq	(%rdi),%rdi
 
-	movq	%rdi,%rsp
 	jmp	.Lnormal_entry
 END(kernuser_reenter)
 #endif

Index: src/sys/arch/amd64/amd64/locore.S
diff -u src/sys/arch/amd64/amd64/locore.S:1.158 src/sys/arch/amd64/amd64/locore.S:1.159
--- src/sys/arch/amd64/amd64/locore.S:1.158	Tue Mar 20 14:26:49 2018
+++ src/sys/arch/amd64/amd64/locore.S	Tue Mar 20 18:27:58 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: locore.S,v 1.158 2018/03/20 14:26:49 maxv Exp $	*/
+/*	$NetBSD: locore.S,v 1.159 2018/03/20 18:27:58 maxv Exp $	*/
 
 /*
  * Copyright-o-rama!
@@ -1548,14 +1548,14 @@ END(pagezero)
  * documentation in amd64_trap.S for an explanation.
  */
 
-#define TF_BACKW(val, reg)	(val - TF_REGSIZE)(reg)
+#define TF_BACKW(val, reg)	(val - (TF_REGSIZE+16))(reg)
 
 	_ALIGN_TEXT
 LABEL(intrfastexit)
 	NOT_XEN(cli;)
 	SVS_LEAVE
 	INTR_RESTORE_GPRS
-	addq	$TF_REGSIZE,%rsp	/* iret frame */
+	addq	$(TF_REGSIZE+16),%rsp	/* iret frame */
 
 	testb	$SEL_UPL,TF_BACKW(TF_CS, %rsp)
 	jz	.Lkexit
@@ -1586,7 +1586,6 @@ do_mov_gs:
 	SWAPGS
 
 .Lkexit:
-	addq	$16,%rsp	/* 16 = T_xxx + error code */
 do_iret:
 	iretq
 END(intrfastexit)

Reply via email to