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)