Module Name: src
Committed By: maxv
Date: Tue May 8 17:20:44 UTC 2018
Modified Files:
src/sys/arch/amd64/amd64: amd64_trap.S machdep.c
src/sys/arch/x86/include: pmap.h
Log Message:
Mitigation for the SS bug, CVE-2018-8897. We disabled dbregs a month ago
in -current and -8 so we are not particularly affected anymore.
The #DB handler runs on ist3, if we decide to process the exception we
copy the iret frame on the correct non-ist stack and continue as usual.
To generate a diff of this commit:
cvs rdiff -u -r1.40 -r1.41 src/sys/arch/amd64/amd64/amd64_trap.S
cvs rdiff -u -r1.303 -r1.304 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.76 -r1.77 src/sys/arch/x86/include/pmap.h
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.40 src/sys/arch/amd64/amd64/amd64_trap.S:1.41
--- src/sys/arch/amd64/amd64/amd64_trap.S:1.40 Wed Mar 28 16:02:49 2018
+++ src/sys/arch/amd64/amd64/amd64_trap.S Tue May 8 17:20:44 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: amd64_trap.S,v 1.40 2018/03/28 16:02:49 maxv Exp $ */
+/* $NetBSD: amd64_trap.S,v 1.41 2018/05/08 17:20:44 maxv Exp $ */
/*
* Copyright (c) 1998, 2007, 2008, 2017 The NetBSD Foundation, Inc.
@@ -106,14 +106,132 @@
.text
+/*
+ * ASM macro, used to leave the IST3 stack and to put ourselves on a non-IST
+ * stack. Only RDX, RCX and RAX are allowed to be used.
+ *
+ * +------------------------------+
+ * The iret frame we copy is: | rip | cs | rflags | rsp | ss |
+ * +------------------------------+
+ */
+.macro IST3_LEAVE is_user
+ .if \is_user
+ movq CPUVAR(CURLWP),%rax
+ movq L_PCB(%rax),%rax
+ movq PCB_RSP0(%rax),%rax
+ .else
+ movq TF_RSP(%rsp),%rax
+ .endif
+
+ subq $(5*8),%rax
+ movq %rax,CPUVAR(SCRATCH)
+
+ /* Copy the iret frame. */
+ movq TF_SS(%rsp),%rcx
+ movq %rcx,(4*8)(%rax)
+ movq TF_RSP(%rsp),%rcx
+ movq %rcx,(3*8)(%rax)
+ movq TF_RFLAGS(%rsp),%rcx
+ movq %rcx,(2*8)(%rax)
+ movq TF_CS(%rsp),%rcx
+ movq %rcx,(1*8)(%rax)
+ movq TF_RIP(%rsp),%rcx
+ movq %rcx,(0*8)(%rax)
+
+ /* Restore. */
+ movq TF_RDX(%rsp),%rdx
+ movq TF_RCX(%rsp),%rcx
+ movq TF_RAX(%rsp),%rax
+
+ /* Zero out the stack we used, RDX+RCX+RAX+IRET. */
+ movq $0,TF_RDX(%rsp)
+ movq $0,TF_RCX(%rsp)
+ movq $0,TF_RAX(%rsp)
+ movq $0,TF_RIP(%rsp)
+ movq $0,TF_CS(%rsp)
+ movq $0,TF_RFLAGS(%rsp)
+ movq $0,TF_RSP(%rsp)
+ movq $0,TF_SS(%rsp)
+
+ movq CPUVAR(SCRATCH),%rsp
+.endm
+
TEXT_USER_BEGIN
IDTVEC(trap00)
ZTRAP(T_DIVIDE)
IDTVEC_END(trap00)
+/*
+ * Handle the SS shadow, CVE-2018-8897.
+ *
+ * We are running on the IST3 stack. If we are under an SS shadow, ignore
+ * the exception and return immediately. Otherwise, copy the iret frame
+ * onto the non-IST stack, and ZTRAP on it as usual.
+ *
+ * IST3 is used temporarily, and is mapped in userland by SVS. It contains
+ * a few secrets, the values of the CPU context. These secrets are zeroed
+ * out when we leave.
+ *
+ * When we ignore an SS shadow, we can't zero out the iret frame. It is
+ * not a problem, because in this particular case, the frame is known not
+ * to contain secrets.
+ */
IDTVEC(trap01)
+#ifndef XEN
+ subq $(TF_REGSIZE+16),%rsp
+
+ /* We clobber only RDX, RCX and RAX. */
+ movq %rdx,TF_RDX(%rsp)
+ movq %rcx,TF_RCX(%rsp)
+ movq %rax,TF_RAX(%rsp)
+
+ testb $SEL_UPL,TF_CS(%rsp)
+ jnz .Luser_dbentry
+
+ movl $MSR_GSBASE,%ecx
+ rdmsr
+ cmpl $VM_MIN_KERNEL_ADDRESS_HIGH32,%edx
+ jae .Lkern_dbentry
+
+ /* SS shadow, ignore the exception. */
+ xorq %rax,%rax
+ movq %rax,%dr6
+
+ /* Restore and zero out. */
+ movq TF_RDX(%rsp),%rdx
+ movq TF_RCX(%rsp),%rcx
+ movq TF_RAX(%rsp),%rax
+ movq $0,TF_RDX(%rsp)
+ movq $0,TF_RCX(%rsp)
+ movq $0,TF_RAX(%rsp)
+
+ addq $(TF_REGSIZE+16),%rsp
+ iretq
+
+.Lkern_dbentry:
+ IST3_LEAVE 0
ZTRAP(T_TRCTRAP)
+
+.Luser_dbentry:
+ swapgs
+ SVS_ENTER_ALTSTACK
+ IST3_LEAVE 1
+ ZTRAP_NJ(T_TRCTRAP)
+ subq $TF_REGSIZE,%rsp
+ INTR_SAVE_GPRS
+ cld
+ SMAP_ENABLE
+ IBRS_ENTER
+ movw %gs,TF_GS(%rsp)
+ movw %fs,TF_FS(%rsp)
+ movw %es,TF_ES(%rsp)
+ movw %ds,TF_DS(%rsp)
+
+ jmp .Lalltraps_noentry
+#else
+ ZTRAP(T_TRCTRAP)
+#endif
IDTVEC_END(trap01)
/*
Index: src/sys/arch/amd64/amd64/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.303 src/sys/arch/amd64/amd64/machdep.c:1.304
--- src/sys/arch/amd64/amd64/machdep.c:1.303 Wed Apr 4 12:59:49 2018
+++ src/sys/arch/amd64/amd64/machdep.c Tue May 8 17:20:44 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.303 2018/04/04 12:59:49 maxv Exp $ */
+/* $NetBSD: machdep.c,v 1.304 2018/05/08 17:20:44 maxv Exp $ */
/*
* Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -110,7 +110,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.303 2018/04/04 12:59:49 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.304 2018/05/08 17:20:44 maxv Exp $");
/* #define XENDEBUG_LOW */
@@ -545,6 +545,14 @@ cpu_init_tss(struct cpu_info *ci)
#endif
cputss->tss.tss_ist[2] = p + PAGE_SIZE - 16;
+ /* DB */
+#ifdef __HAVE_PCPU_AREA
+ p = (vaddr_t)&pcpuarea->ent[cid].ist3;
+#else
+ p = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
+#endif
+ cputss->tss.tss_ist[3] = p + PAGE_SIZE - 16;
+
ci->ci_tss = cputss;
ci->ci_tss_sel = tss_alloc(&cputss->tss);
}
@@ -1773,6 +1781,9 @@ init_x86_64(paddr_t first_avail)
#ifndef XEN
idt_vec_reserve(x);
switch (x) {
+ case 1: /* DB */
+ ist = 4;
+ break;
case 2: /* NMI */
ist = 3;
break;
Index: src/sys/arch/x86/include/pmap.h
diff -u src/sys/arch/x86/include/pmap.h:1.76 src/sys/arch/x86/include/pmap.h:1.77
--- src/sys/arch/x86/include/pmap.h:1.76 Sun Mar 4 10:13:08 2018
+++ src/sys/arch/x86/include/pmap.h Tue May 8 17:20:44 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.76 2018/03/04 10:13:08 jdolecek Exp $ */
+/* $NetBSD: pmap.h,v 1.77 2018/05/08 17:20:44 maxv Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -163,6 +163,7 @@ struct pcpu_entry {
uint8_t ist0[PAGE_SIZE];
uint8_t ist1[PAGE_SIZE];
uint8_t ist2[PAGE_SIZE];
+ uint8_t ist3[PAGE_SIZE];
uint8_t rsp0[2 * PAGE_SIZE];
} __packed;