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)