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/01ef665e1eac
branches:  trunk
changeset: 321534:01ef665e1eac
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 23cd9cf26fed -r 01ef665e1eac 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 23cd9cf26fed -r 01ef665e1eac 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