From 94c673d3909a12b9b7fb4d1a7c27d168aedf9b6f Mon Sep 17 00:00:00 2001 From: Gordon Tetlow Date: Thu, 21 Jun 2018 05:37:37 +0000 Subject: Add today's advisory and notices. Approved by: so Sponsored by: The FreeBSD Foundation --- share/security/patches/SA-18:07/lazyfpu-11.patch | 373 +++++++++++++++++++++ .../security/patches/SA-18:07/lazyfpu-11.patch.asc | 18 + 2 files changed, 391 insertions(+) create mode 100644 share/security/patches/SA-18:07/lazyfpu-11.patch create mode 100644 share/security/patches/SA-18:07/lazyfpu-11.patch.asc (limited to 'share/security/patches/SA-18:07') diff --git a/share/security/patches/SA-18:07/lazyfpu-11.patch b/share/security/patches/SA-18:07/lazyfpu-11.patch new file mode 100644 index 0000000000..39330e4cda --- /dev/null +++ b/share/security/patches/SA-18:07/lazyfpu-11.patch @@ -0,0 +1,373 @@ +--- sys/amd64/amd64/cpu_switch.S.orig ++++ sys/amd64/amd64/cpu_switch.S +@@ -105,10 +105,10 @@ + + /* have we used fp, and need a save? */ + cmpq %rdi,PCPU(FPCURTHREAD) +- jne 3f ++ jne 2f + movq PCB_SAVEFPU(%r8),%r8 + clts +- cmpl $0,use_xsave ++ cmpl $0,use_xsave(%rip) + jne 1f + fxsave (%r8) + jmp 2f +@@ -120,12 +120,7 @@ + /* This is patched to xsaveopt if supported, see fpuinit_bsp1() */ + xsave (%r8) + movq %rcx,%rdx +-2: smsw %ax +- orb $CR0_TS,%al +- lmsw %ax +- xorl %eax,%eax +- movq %rax,PCPU(FPCURTHREAD) +-3: ++2: + /* Save is done. Now fire up new thread. Leave old vmspace. */ + movq %rsi,%r12 + movq %rdi,%r13 +@@ -212,6 +207,8 @@ + movq PCB_RBX(%r8),%rbx + movq PCB_RIP(%r8),%rax + movq %rax,(%rsp) ++ movq PCPU(CURTHREAD),%rdi ++ call fpu_activate_sw + ret + + /* +--- sys/amd64/amd64/fpu.c.orig ++++ sys/amd64/amd64/fpu.c +@@ -139,6 +139,11 @@ + SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, + SYSCTL_NULL_INT_PTR, 1, "Floating point instructions executed in hardware"); + ++int lazy_fpu_switch = 0; ++SYSCTL_INT(_hw, OID_AUTO, lazy_fpu_switch, CTLFLAG_RWTUN | CTLFLAG_NOFETCH, ++ &lazy_fpu_switch, 0, ++ "Lazily load FPU context after context switch"); ++ + int use_xsave; /* non-static for cpu_switch.S */ + uint64_t xsave_mask; /* the same */ + static uma_zone_t fpu_save_area_zone; +@@ -204,6 +209,7 @@ + u_int cp[4]; + uint64_t xsave_mask_user; + ++ TUNABLE_INT_FETCH("hw.lazy_fpu_switch", &lazy_fpu_switch); + if ((cpu_feature2 & CPUID2_XSAVE) != 0) { + use_xsave = 1; + TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave); +@@ -611,6 +617,45 @@ + return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]); + } + ++static void ++restore_fpu_curthread(struct thread *td) ++{ ++ struct pcb *pcb; ++ ++ /* ++ * Record new context early in case frstor causes a trap. ++ */ ++ PCPU_SET(fpcurthread, td); ++ ++ stop_emulating(); ++ fpu_clean_state(); ++ pcb = td->td_pcb; ++ ++ if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { ++ /* ++ * This is the first time this thread has used the FPU or ++ * the PCB doesn't contain a clean FPU state. Explicitly ++ * load an initial state. ++ * ++ * We prefer to restore the state from the actual save ++ * area in PCB instead of directly loading from ++ * fpu_initialstate, to ignite the XSAVEOPT ++ * tracking engine. ++ */ ++ bcopy(fpu_initialstate, pcb->pcb_save, ++ cpu_max_ext_state_size); ++ fpurestore(pcb->pcb_save); ++ if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__) ++ fldcw(pcb->pcb_initial_fpucw); ++ if (PCB_USER_FPU(pcb)) ++ set_pcb_flags(pcb, PCB_FPUINITDONE | ++ PCB_USERFPUINITDONE); ++ else ++ set_pcb_flags(pcb, PCB_FPUINITDONE); ++ } else ++ fpurestore(pcb->pcb_save); ++} ++ + /* + * Device Not Available (DNA, #NM) exception handler. + * +@@ -621,7 +666,9 @@ + void + fpudna(void) + { ++ struct thread *td; + ++ td = curthread; + /* + * This handler is entered with interrupts enabled, so context + * switches may occur before critical_enter() is executed. If +@@ -635,49 +682,38 @@ + + KASSERT((curpcb->pcb_flags & PCB_FPUNOSAVE) == 0, + ("fpudna while in fpu_kern_enter(FPU_KERN_NOCTX)")); +- if (PCPU_GET(fpcurthread) == curthread) { +- printf("fpudna: fpcurthread == curthread\n"); ++ if (__predict_false(PCPU_GET(fpcurthread) == td)) { ++ /* ++ * Some virtual machines seems to set %cr0.TS at ++ * arbitrary moments. Silently clear the TS bit ++ * regardless of the eager/lazy FPU context switch ++ * mode. ++ */ + stop_emulating(); +- critical_exit(); +- return; ++ } else { ++ if (__predict_false(PCPU_GET(fpcurthread) != NULL)) { ++ panic( ++ "fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n", ++ PCPU_GET(fpcurthread), ++ PCPU_GET(fpcurthread)->td_tid, td, td->td_tid); ++ } ++ restore_fpu_curthread(td); + } +- if (PCPU_GET(fpcurthread) != NULL) { +- panic("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n", +- PCPU_GET(fpcurthread), PCPU_GET(fpcurthread)->td_tid, +- curthread, curthread->td_tid); +- } +- stop_emulating(); +- /* +- * Record new context early in case frstor causes a trap. +- */ +- PCPU_SET(fpcurthread, curthread); ++ critical_exit(); ++} + +- fpu_clean_state(); ++void fpu_activate_sw(struct thread *td); /* Called from the context switch */ ++void ++fpu_activate_sw(struct thread *td) ++{ + +- if ((curpcb->pcb_flags & PCB_FPUINITDONE) == 0) { +- /* +- * This is the first time this thread has used the FPU or +- * the PCB doesn't contain a clean FPU state. Explicitly +- * load an initial state. +- * +- * We prefer to restore the state from the actual save +- * area in PCB instead of directly loading from +- * fpu_initialstate, to ignite the XSAVEOPT +- * tracking engine. +- */ +- bcopy(fpu_initialstate, curpcb->pcb_save, +- cpu_max_ext_state_size); +- fpurestore(curpcb->pcb_save); +- if (curpcb->pcb_initial_fpucw != __INITIAL_FPUCW__) +- fldcw(curpcb->pcb_initial_fpucw); +- if (PCB_USER_FPU(curpcb)) +- set_pcb_flags(curpcb, +- PCB_FPUINITDONE | PCB_USERFPUINITDONE); +- else +- set_pcb_flags(curpcb, PCB_FPUINITDONE); +- } else +- fpurestore(curpcb->pcb_save); +- critical_exit(); ++ if (lazy_fpu_switch || (td->td_pflags & TDP_KTHREAD) != 0 || ++ !PCB_USER_FPU(td->td_pcb)) { ++ PCPU_SET(fpcurthread, NULL); ++ start_emulating(); ++ } else if (PCPU_GET(fpcurthread) != td) { ++ restore_fpu_curthread(td); ++ } + } + + void +--- sys/i386/i386/swtch.s.orig ++++ sys/i386/i386/swtch.s +@@ -293,6 +293,12 @@ + cpu_switch_load_gs: + mov PCB_GS(%edx),%gs + ++ pushl %edx ++ pushl PCPU(CURTHREAD) ++ call npxswitch ++ popl %edx ++ popl %edx ++ + /* Test if debug registers should be restored. */ + testl $PCB_DBREGS,PCB_FLAGS(%edx) + jz 1f +--- sys/i386/isa/npx.c.orig ++++ sys/i386/isa/npx.c +@@ -191,6 +191,11 @@ + SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, + &hw_float, 0, "Floating point instructions executed in hardware"); + ++int lazy_fpu_switch = 0; ++SYSCTL_INT(_hw, OID_AUTO, lazy_fpu_switch, CTLFLAG_RWTUN | CTLFLAG_NOFETCH, ++ &lazy_fpu_switch, 0, ++ "Lazily load FPU context after context switch"); ++ + int use_xsave; + uint64_t xsave_mask; + static uma_zone_t fpu_save_area_zone; +@@ -327,6 +332,7 @@ + u_int cp[4]; + uint64_t xsave_mask_user; + ++ TUNABLE_INT_FETCH("hw.lazy_fpu_switch", &lazy_fpu_switch); + if (cpu_fxsr && (cpu_feature2 & CPUID2_XSAVE) != 0) { + use_xsave = 1; + TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave); +@@ -785,47 +791,20 @@ + return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]); + } + +-/* +- * Implement device not available (DNA) exception +- * +- * It would be better to switch FP context here (if curthread != fpcurthread) +- * and not necessarily for every context switch, but it is too hard to +- * access foreign pcb's. +- */ +- +-static int err_count = 0; +- +-int +-npxdna(void) ++static void ++restore_npx_curthread(struct thread *td, struct pcb *pcb) + { + +- if (!hw_float) +- return (0); +- critical_enter(); +- if (PCPU_GET(fpcurthread) == curthread) { +- printf("npxdna: fpcurthread == curthread %d times\n", +- ++err_count); +- stop_emulating(); +- critical_exit(); +- return (1); +- } +- if (PCPU_GET(fpcurthread) != NULL) { +- printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n", +- PCPU_GET(fpcurthread), +- PCPU_GET(fpcurthread)->td_proc->p_pid, +- curthread, curthread->td_proc->p_pid); +- panic("npxdna"); +- } +- stop_emulating(); + /* + * Record new context early in case frstor causes a trap. + */ +- PCPU_SET(fpcurthread, curthread); ++ PCPU_SET(fpcurthread, td); + ++ stop_emulating(); + if (cpu_fxsr) + fpu_clean_state(); + +- if ((curpcb->pcb_flags & PCB_NPXINITDONE) == 0) { ++ if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) { + /* + * This is the first time this thread has used the FPU or + * the PCB doesn't contain a clean FPU state. Explicitly +@@ -836,18 +815,54 @@ + * npx_initialstate, to ignite the XSAVEOPT + * tracking engine. + */ +- bcopy(npx_initialstate, curpcb->pcb_save, cpu_max_ext_state_size); +- fpurstor(curpcb->pcb_save); +- if (curpcb->pcb_initial_npxcw != __INITIAL_NPXCW__) +- fldcw(curpcb->pcb_initial_npxcw); +- curpcb->pcb_flags |= PCB_NPXINITDONE; +- if (PCB_USER_FPU(curpcb)) +- curpcb->pcb_flags |= PCB_NPXUSERINITDONE; ++ bcopy(npx_initialstate, pcb->pcb_save, cpu_max_ext_state_size); ++ fpurstor(pcb->pcb_save); ++ if (pcb->pcb_initial_npxcw != __INITIAL_NPXCW__) ++ fldcw(pcb->pcb_initial_npxcw); ++ pcb->pcb_flags |= PCB_NPXINITDONE; ++ if (PCB_USER_FPU(pcb)) ++ pcb->pcb_flags |= PCB_NPXUSERINITDONE; + } else { +- fpurstor(curpcb->pcb_save); ++ fpurstor(pcb->pcb_save); + } ++} ++ ++/* ++ * Implement device not available (DNA) exception ++ * ++ * It would be better to switch FP context here (if curthread != fpcurthread) ++ * and not necessarily for every context switch, but it is too hard to ++ * access foreign pcb's. ++ */ ++int ++npxdna(void) ++{ ++ struct thread *td; ++ ++ if (!hw_float) ++ return (0); ++ td = curthread; ++ critical_enter(); ++ if (__predict_false(PCPU_GET(fpcurthread) == td)) { ++ /* ++ * Some virtual machines seems to set %cr0.TS at ++ * arbitrary moments. Silently clear the TS bit ++ * regardless of the eager/lazy FPU context switch ++ * mode. ++ */ ++ stop_emulating(); ++ } else { ++ if (__predict_false(PCPU_GET(fpcurthread) != NULL)) { ++ printf( ++ "npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n", ++ PCPU_GET(fpcurthread), ++ PCPU_GET(fpcurthread)->td_proc->p_pid, ++ td, td->td_proc->p_pid); ++ panic("npxdna"); ++ } ++ restore_npx_curthread(td, td->td_pcb); ++ } + critical_exit(); +- + return (1); + } + +@@ -869,10 +884,22 @@ + xsaveopt((char *)addr, xsave_mask); + else + fpusave(addr); +- start_emulating(); +- PCPU_SET(fpcurthread, NULL); + } + ++void npxswitch(struct thread *td, struct pcb *pcb); ++void ++npxswitch(struct thread *td, struct pcb *pcb) ++{ ++ ++ if (lazy_fpu_switch || (td->td_pflags & TDP_KTHREAD) != 0 || ++ !PCB_USER_FPU(pcb)) { ++ start_emulating(); ++ PCPU_SET(fpcurthread, NULL); ++ } else if (PCPU_GET(fpcurthread) != td) { ++ restore_npx_curthread(td, pcb); ++ } ++} ++ + /* + * Unconditionally save the current co-processor state across suspend and + * resume. diff --git a/share/security/patches/SA-18:07/lazyfpu-11.patch.asc b/share/security/patches/SA-18:07/lazyfpu-11.patch.asc new file mode 100644 index 0000000000..2479fd9255 --- /dev/null +++ b/share/security/patches/SA-18:07/lazyfpu-11.patch.asc @@ -0,0 +1,18 @@ +-----BEGIN PGP SIGNATURE----- + +iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN2xfFIAAAAAALgAo +aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD +MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n +5cJY2Q/+KyfnyHr1YphdZkXYLPTtIKCJasfR1jWSh+6Amr/QDCSvMSvvjvbg6PL0 +snVq9108ycrKU7xOBebBQRYNYuS1KlRsjcw396dhpjoVwaoQ5mxuWqeiRbSudy/N +hFuX91E22832j1o4AsovV/vpqTREz0o4BnMrw9fUiZvuhEiPXs3VHoBcn3lCflXf +ubJVptVVCjIK7miVY/oGtvUnzNoSujjNQekpdhHmKyWxU+PrHHhh/kJg+CVEKNr9 +IkeJV8w2NkpbXEkf59rMUxoMd4OkxlVlNuoPqWekXBwcLGwd5Uux7GAeI+X8crGA +cim6F8zniozsip7AptQU5e8yQL/mKYsoWpsghASEu1uanvwTjkmu82f3ER7/FX08 +0MmhWcSkqGEvKlenQAajCLA7CTzXiMcB3QoCd3VYUmXZOJqcnDAijaDRZ/FMuVJV +wGDFus4cMiDhuC+WJTE699DGmveov3C3N6O65K7KNMdsECFwfP38xzzv+wvjzCbj +JzaYW14YYr5cgsBdL24z0Yl8Pz9vXexiFdPH+VxOaRIHZGMSQqRe0TXG85M8Pv9F +X0tje/gbMMnBpgHui3lUY3x45srRLSn8qt/v/j3W5zoxXINZTDTdqoZT7T9pKWpD +EmWdlLMRDDDvQceXdDebZytM/cMAUf2PS2RtWipSwC4Frqz9eYY= +=dd45 +-----END PGP SIGNATURE----- -- cgit v1.2.3