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 --- .../security/advisories/FreeBSD-EN-18:07.pmap.asc | 144 ++++++++ .../advisories/FreeBSD-SA-18:07.lazyfpu.asc | 147 ++++++++ share/security/patches/EN-18:07/pmap.patch | 78 +++++ share/security/patches/EN-18:07/pmap.patch.asc | 18 + share/security/patches/SA-18:07/lazyfpu-11.patch | 373 +++++++++++++++++++++ .../security/patches/SA-18:07/lazyfpu-11.patch.asc | 18 + share/xml/advisories.xml | 13 + share/xml/notices.xml | 13 + 8 files changed, 804 insertions(+) create mode 100644 share/security/advisories/FreeBSD-EN-18:07.pmap.asc create mode 100644 share/security/advisories/FreeBSD-SA-18:07.lazyfpu.asc create mode 100644 share/security/patches/EN-18:07/pmap.patch create mode 100644 share/security/patches/EN-18:07/pmap.patch.asc 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') diff --git a/share/security/advisories/FreeBSD-EN-18:07.pmap.asc b/share/security/advisories/FreeBSD-EN-18:07.pmap.asc new file mode 100644 index 0000000000..f55482206f --- /dev/null +++ b/share/security/advisories/FreeBSD-EN-18:07.pmap.asc @@ -0,0 +1,144 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +============================================================================= +FreeBSD-EN-18:07.pmap Errata Notice + The FreeBSD Project + +Topic: Incorrect TLB shootdown for Xen based guests + +Category: core +Module: kernel +Announced: 2018-06-21 +Credits: Colin Percival +Affects: FreeBSD 11.1 +Corrected: 2018-05-22 14:36:46 UTC (stable/11, 11.2-BETA2) + 2018-06-21 05:18:08 UTC (releng/11.1, 11.1-RELEASE-p11) + +For general information regarding FreeBSD Errata Notices and Security +Advisories, including descriptions of the fields above, security +branches, and the following sections, please visit +. + +I. Background + +CPUs rely on a Translation Lookaside Buffer (TLB) to cache virtual memory +paging information. When a page is unmapped from the virtual address space +of a process on a multiprocessor system, an Inter-Processor Interrupt (IPI) +may be sent to instruct other CPUs to invalidate ("shoot down") their TLB +entries for the addresses in question. + +For virtualization-related performance reasons, FreeBSD has IPI code for the +Xen platform which is separate from the generic x86 IPI code. + +II. Problem Description + +In the course of changes to the FreeBSD virtual memory system to address +FreeBSD-SA-18:03.speculative_execution, changes were made to the IPIs used +for shooting down TLB entries. Unfortunately, the IPI handlers for Xen were +left non-PTI, even when PTI was enabled, which result in TLB shootdowns for +the user mode portion of the address space not being consistently performed +correctly. + +III. Impact + +Processes on Xen based guests may "see" pages of memory which were previously +mapped but have since been unmapped, resulted in data being corrupted and/or +processes crashing due to internal data structures becoming inconsistent. + +IV. Workaround + +Only Xen based guests are affected by this issue. All other platforms are +not susceptible. + +For Xen based guests, disabling PTI will workaround the issue. Add the +following line to /boot/loader.conf: + vm.pmap.pti=0 + +Please be aware, by disabling PTI, the system will be vulnerable to +FreeBSD-SA-18:03.speculative_execution. + +V. Solution + +Perform one of the following: + +1) Upgrade your system to a supported FreeBSD stable or release / security +branch (releng) dated after the correction date. + +Afterward, reboot the system. + +2) To update your system via a binary patch: + +Systems running a RELEASE version of FreeBSD on the i386 or amd64 +platforms can be updated via the freebsd-update(8) utility: + +# freebsd-update fetch +# freebsd-update install + +Afterward, reboot the system. + +3) To update your system via a source code patch: + +The following patches have been verified to apply to the applicable +FreeBSD release branches. + +a) Download the relevant patch from the location below, and verify the +detached PGP signature using your PGP utility. + +[FreeBSD 11.1] +# fetch https://security.FreeBSD.org/patches/EN-18:07/pmap.patch +# fetch https://security.FreeBSD.org/patches/EN-18:07/pmap.patch.asc +# gpg --verify pmap.patch.asc + +b) Apply the patch. Execute the following commands as root: + +# cd /usr/src +# patch < /path/to/patch + +c) Recompile your kernel as described in + and reboot the +system. + +VI. Correction details + +The following list contains the correction revision numbers for each +affected branch. + +Branch/path Revision +- ------------------------------------------------------------------------- +stable/11/ r334047 +releng/11.1/ r335466 +- ------------------------------------------------------------------------- + +To see which files were modified by a particular revision, run the +following command, replacing NNNNNN with the revision number, on a +machine with Subversion installed: + +# svn diff -cNNNNNN --summarize svn://svn.freebsd.org/base + +Or visit the following URL, replacing NNNNNN with the revision number: + + + +VII. References + +The latest revision of this notice is available at + +-----BEGIN PGP SIGNATURE----- + +iQKTBAEBCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN3hfFIAAAAAALgAo +aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD +MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n +5cIOow/+P+zdQ8dmZcEIy7HjYdpTAbPIGNnSdvuXV5O5XGamOziTJOuEEDBxeNiE +QE9VM8a94Ybl0CJZhfBVPhqrDpYuXOqKvnfHlcXWjppDliUPWohF6kTj4ugqGKrl +T2VckEvjltgJQ1/XqnkE7n1LuezLcqF/RbW3xOeRkAhf3X+IXd/E3uCuw/n4yknl +O5EvLmjq3bGlN7OfHOM4E+PHvYOxxfbjYH5S+1Z9g0/apR6HOUi9WU0hV5YEB9Cz +hUCsnx15Nla97jD9P1xy0tr3FkPpvZRJGj2BelNaQoFNrZB7oWB9xwOmwSqxye/b +zvp+/WUuGlo1KWU8RldzVPP6A7piuL6oAvYqW8/wcpwd9HqNGXblWz1XodpE3x1F +TKHTGcP/e/wgU6810SolylwJKxhGVZaQK3UH1iVKPRRTw+HUR1OVDY+q7XAyFD7c +QbKRyWQIYr2X98LhiT8TMVssharFg7AcviRSDEdCYt+A6S9jiDWMe+C3hGndSSET +Cf/0q6PQ89GQKw3lQOgwvtWlMaKPwfg3W8lxkusK5o935aXWhbRee3Hzkld7eUl0 +8/uGBCgDnSk7hPIHLDcddIKI+QT0IpHKCPlBRRoTJUhpXo/g5bVkbUnMKBZ7zf3O +mBvci+KPc2yqp///fw1eMhgRTOOOOnXAHUMsb/FH1b+yIcikudo= +=fw9I +-----END PGP SIGNATURE----- diff --git a/share/security/advisories/FreeBSD-SA-18:07.lazyfpu.asc b/share/security/advisories/FreeBSD-SA-18:07.lazyfpu.asc new file mode 100644 index 0000000000..8da46d4a80 --- /dev/null +++ b/share/security/advisories/FreeBSD-SA-18:07.lazyfpu.asc @@ -0,0 +1,147 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +============================================================================= +FreeBSD-SA-18:07.lazyfpu Security Advisory + The FreeBSD Project + +Topic: Lazy FPU State Restore Information Disclosure + +Category: core +Module: kernel +Announced: 2018-06-21 +Credits: Julian Stecklina from Amazon Germany + Thomas Prescher from Cyberus Technology GmbH + Zdenek Sojka from SYSGO AG + Colin Percival +Affects: All supported version of FreeBSD. +Corrected: 2018-06-14 18:50:49 UTC (stable/11, 11.2-PRERELEASE) + 2018-06-15 13:21:37 UTC (releng/11.2, 11.2-RC3) + 2018-06-21 05:17:13 UTC (releng/11.1, 11.1-RELEASE-p11) +CVE Name: CVE-2018-3665 + +Special Note: This advisory only addresses this issue for FreeBSD 11.x on + i386 and amd64. We expect to update this advisory to include + 10.x in the near future. + +For general information regarding FreeBSD Security Advisories, +including descriptions of the fields above, security branches, and the +following sections, please visit . + +I. Background + +Modern CPUs have a floating point unit (FPU) which needs to maintain state +per thread. One technique is to only save and to only restore the FPU state +for a thread when a thread attempts to utilize the FPU. This technique is +called Lazy FPU state restore. + +II. Problem Description + +A subset of Intel processors can allow a local thread to infer data from +another thread through a speculative execution side channel when Lazy FPU +state restore is used. + +III. Impact + +Any local thread can potentially read FPU state information from other +threads running on the host. This could include cryptographic keys when the +AES-NI CPU feature is present. + +IV. Workaround + +No workaround is available, but non-Intel branded CPUs are not believed +to be vulnerable. + +V. Solution + +The patch changes from Lazy FPU state restore to Eager FPU state restore. +This new technique is the recommended practice from Intel and in some cases +can actually increase performance, depending on workload. + +Perform one of the following: + +1) Upgrade your vulnerable system to a supported FreeBSD stable or +release / security branch (releng) dated after the correction date. + +Afterward, reboot the system. + +2) To update your vulnerable system via a binary patch: + +Systems running a RELEASE version of FreeBSD on the i386 or amd64 +platforms can be updated via the freebsd-update(8) utility: + +# freebsd-update fetch +# freebsd-update install + +Afterward, reboot the system. + +3) To update your vulnerable system via a source code patch: + +The following patches have been verified to apply to the applicable +FreeBSD release branches. + +a) Download the relevant patch from the location below, and verify the +detached PGP signature using your PGP utility. + +[FreeBSD 11.1] +# fetch https://security.FreeBSD.org/patches/SA-18:07/lazyfpu-11.patch +# fetch https://security.FreeBSD.org/patches/SA-18:07/lazyfpu-11.patch.asc +# gpg --verify lazyfpu-11.patch.asc + +b) Apply the patch. Execute the following commands as root: + +# cd /usr/src +# patch < /path/to/patch + +c) Recompile your kernel as described in + and reboot the +system. + +VI. Correction details + +The following list contains the correction revision numbers for each +affected branch. + +Branch/path Revision +- ------------------------------------------------------------------------- +stable/11/ r335169 +releng/11.2/ r335196 +releng/11.1/ r335465 +- ------------------------------------------------------------------------- + +To see which files were modified by a particular revision, run the +following command, replacing NNNNNN with the revision number, on a +machine with Subversion installed: + +# svn diff -cNNNNNN --summarize svn://svn.freebsd.org/base + +Or visit the following URL, replacing NNNNNN with the revision number: + + + +VII. References + + + + + +The latest revision of this advisory is available at + +-----BEGIN PGP SIGNATURE----- + +iQKTBAEBCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN1hfFIAAAAAALgAo +aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD +MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n +5cJTLA/+Kt7QLkNCVudaiE+d+VMuC2f1aGhqoyd+36xL9rNsn2ShZhIo+gq1dhXn +2lJiOYCPN5cJkasj1YdP2bSIv25nTcFMp0rKOww0A1scOnzi66LAD+DXmGVUhmaA +MPyrnuL7rbuPq9ls9FGAO2XURwB9IrGYtqPuVWmNyn+HyKBYcGCkL5+UEnHeUCg8 +oopJudZgrGBVMFCsqG6K/b+3uc397Hyq0PZzpyWFfkaxrbTwVMMwgWyTxIYaPVs7 +2g7WK2JWjJNk0IWQGot9qpKYDRyxc9PPFX/0blwOLe1Wwrt5nEF+9av89HQJ6PXF ++Ws5w8Gnhi9wWuK19ew1j0nvP+f0zw09r4GuEzhZXADAz733HNK5dtsS/dMJi2wa +9fQ0s1joT3JFDvWZKUQS2mNuhpvBfYoI0d0OEJT2H2eycFYe4B+VNhB2V1e9wLn6 +9X4+Vbc2LEOF09klQQFMYNMEyQzLtfq2gHIoD37sCw9mMrYKWjgy3NhY5AKrfGHG +OcBsvnaXCW/x9/kV9Pfoel/psrmjcQdp4QEKAZbRNwvJG5sGhtsQXTp0Nk+BCuVy +G0NNB9306dLfk0OTZ02SiOUjVagXObyo+LgWTBO6FryDlHVkopsYNkB5oRx9fLrm +68r7OXidl0ndGqnh87meMVH1/Fu/rr09Jd4osIzS+Gc0Dt7NOEQ= +=8fnI +-----END PGP SIGNATURE----- diff --git a/share/security/patches/EN-18:07/pmap.patch b/share/security/patches/EN-18:07/pmap.patch new file mode 100644 index 0000000000..e0b0f2ca7b --- /dev/null +++ b/share/security/patches/EN-18:07/pmap.patch @@ -0,0 +1,78 @@ +--- sys/x86/xen/xen_apic.c.orig ++++ sys/x86/xen/xen_apic.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -439,6 +440,46 @@ + invltlb_pcid_handler(); + return (FILTER_HANDLED); + } ++ ++static int ++xen_invltlb_invpcid_pti(void *arg) ++{ ++ ++ invltlb_invpcid_pti_handler(); ++ return (FILTER_HANDLED); ++} ++ ++static int ++xen_invlpg_invpcid_handler(void *arg) ++{ ++ ++ invlpg_invpcid_handler(); ++ return (FILTER_HANDLED); ++} ++ ++static int ++xen_invlpg_pcid_handler(void *arg) ++{ ++ ++ invlpg_pcid_handler(); ++ return (FILTER_HANDLED); ++} ++ ++static int ++xen_invlrng_invpcid_handler(void *arg) ++{ ++ ++ invlrng_invpcid_handler(); ++ return (FILTER_HANDLED); ++} ++ ++static int ++xen_invlrng_pcid_handler(void *arg) ++{ ++ ++ invlrng_pcid_handler(); ++ return (FILTER_HANDLED); ++} + #endif + + static int +@@ -529,8 +570,18 @@ + + #ifdef __amd64__ + if (pmap_pcid_enabled) { +- xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = invpcid_works ? +- xen_invltlb_invpcid : xen_invltlb_pcid; ++ if (pti) ++ xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = ++ invpcid_works ? xen_invltlb_invpcid_pti : ++ xen_invltlb_pcid; ++ else ++ xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = ++ invpcid_works ? xen_invltlb_invpcid : ++ xen_invltlb_pcid; ++ xen_ipis[IPI_TO_IDX(IPI_INVLPG)].filter = invpcid_works ? ++ xen_invlpg_invpcid_handler : xen_invlpg_pcid_handler; ++ xen_ipis[IPI_TO_IDX(IPI_INVLRNG)].filter = invpcid_works ? ++ xen_invlrng_invpcid_handler : xen_invlrng_pcid_handler; + } + #endif + CPU_FOREACH(i) diff --git a/share/security/patches/EN-18:07/pmap.patch.asc b/share/security/patches/EN-18:07/pmap.patch.asc new file mode 100644 index 0000000000..269024cd58 --- /dev/null +++ b/share/security/patches/EN-18:07/pmap.patch.asc @@ -0,0 +1,18 @@ +-----BEGIN PGP SIGNATURE----- + +iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAlsrN4FfFIAAAAAALgAo +aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD +MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n +5cI6+Q//dTnLur/Dtcz8y2b00OBdUvC1GL3kcFjFhk/fwcvceIdY1m6cC6u6ypxp +Mehewv2YENgLw0fkIu61OsqtyCDmQ+O1LKuFNZpkYqPuiVRvhwAlXTHEWjVHmP8f +52oSgspKxuZbpMKIDIZaQUiH3Ff7BcGIx8ru50wcsfe4dWXD0YJebqkK1etPuUYV +HuMNrqbq7cH8BgBBaRzlAABqz6qeXjLZryyE3bDT4QGEdQPvyrs0muj/TtKzqmZB +axX/V+aClQwnXARQ+EhGxCHDU+OoX4inH1N20+ZPwq7aGTjo0B19Yo/03cV1C7vs +3NDJWKk4oxM6QP1bUIYZ37qlX+WSXH25q8PGtWucd/YdVZR04iXOwC4G1ncmEUWi +1jEj9V7FOBzoLqCGdL2izibemVbKjza5FvODW2gq+Xzbe2F4eube0v12wOiLRED/ +mTn71RWsImgzsRvywIsGMkaZCZm4j7gWi53dgBqNteitmw75esM000tcKhy5T5yl +VuxkhttAODFAujz7k4BRpUebzAf0autiRjec6QTHWek5jqD+bM3nGnlPVJMIzQrX +GVibFJga+zrqHhXVXAEKM6QEgcF4nPOlwWOIJ1mBGxomnCM5dKt+Fr1W9lFsurun +w83zqwX12Wz+gUENgBYeAawk9O86KoXC0gqf2pphjPnihN6x7Pc= +=6sV+ +-----END PGP SIGNATURE----- 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----- diff --git a/share/xml/advisories.xml b/share/xml/advisories.xml index 3020aabc5a..d9c6f21970 100644 --- a/share/xml/advisories.xml +++ b/share/xml/advisories.xml @@ -7,6 +7,19 @@ 2018 + + 6 + + + 21 + + + FreeBSD-SA-18:07.lazyfpu + + + + + 5 diff --git a/share/xml/notices.xml b/share/xml/notices.xml index 2f54d167c9..13896f3f52 100644 --- a/share/xml/notices.xml +++ b/share/xml/notices.xml @@ -7,6 +7,19 @@ 2018 + + 6 + + + 21 + + + FreeBSD-EN-18:07.pmap + + + + + 5 -- cgit v1.2.3