Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/amd64/amd64 (Re)Fix handling of segment register fa...
details: https://anonhg.NetBSD.org/src/rev/ca7e40344a49
branches: trunk
changeset: 360646:ca7e40344a49
user: maxv <maxv%NetBSD.org@localhost>
date: Tue Mar 20 18:27:58 2018 +0000
description:
(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.)
diffstat:
sys/arch/amd64/amd64/amd64_trap.S | 37 +++++++++++++++++++++----------------
sys/arch/amd64/amd64/locore.S | 7 +++----
2 files changed, 24 insertions(+), 20 deletions(-)
diffs (115 lines):
diff -r 6c36b9b767f3 -r ca7e40344a49 sys/arch/amd64/amd64/amd64_trap.S
--- a/sys/arch/amd64/amd64/amd64_trap.S Tue Mar 20 17:15:20 2018 +0000
+++ b/sys/arch/amd64/amd64/amd64_trap.S Tue Mar 20 18:27:58 2018 +0000
@@ -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 @@
* 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 @@
* |
* +---------------------------------+
* |
- * | +---------------------------------------------------+
- * +--> | 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 @@
* 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 @@
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
- pushq %rax
- movq 16(%rsp),%rax /* 16(%rsp) = current TF_TRAPNO */
- movq %rax,(%rdi) /* (%rdi) = outer TF_TRAPNO */
- popq %rax
+ /* 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 */
- movq %rdi,%rsp
+ /* Restore %rdi */
+ movq (%rdi),%rdi
+
jmp .Lnormal_entry
END(kernuser_reenter)
#endif
diff -r 6c36b9b767f3 -r ca7e40344a49 sys/arch/amd64/amd64/locore.S
--- a/sys/arch/amd64/amd64/locore.S Tue Mar 20 17:15:20 2018 +0000
+++ b/sys/arch/amd64/amd64/locore.S Tue Mar 20 18:27:58 2018 +0000
@@ -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 @@
* 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 @@
SWAPGS
.Lkexit:
- addq $16,%rsp /* 16 = T_xxx + error code */
do_iret:
iretq
END(intrfastexit)
Home |
Main Index |
Thread Index |
Old Index