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;