diff options
author | Colin Percival <cperciva@FreeBSD.org> | 2006-04-19 07:03:14 +0000 |
---|---|---|
committer | Colin Percival <cperciva@FreeBSD.org> | 2006-04-19 07:03:14 +0000 |
commit | 69e48a4731721e86c9bbd2cef46d484ebe906c30 (patch) | |
tree | ae48ad65ae66ce3329dc7106ad584098d218f9a5 | |
parent | 2c82120cef588b7d97bb551b50df5d287aad93e9 (diff) |
MFC: Correct a local information leakage bug affecting AMD FPUs.
Security: FreeBSD-SA-06:14.fpu
Approved by: so (cperciva)
Notes
Notes:
svn path=/releng/5.3/; revision=157863
-rw-r--r-- | UPDATING | 3 | ||||
-rw-r--r-- | sys/amd64/amd64/fpu.c | 36 | ||||
-rw-r--r-- | sys/conf/newvers.sh | 2 | ||||
-rw-r--r-- | sys/i386/isa/npx.c | 42 |
4 files changed, 80 insertions, 3 deletions
@@ -8,6 +8,9 @@ Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. Important recent entries: 20040724 (default X changes). +20060419: p29 FreeBSD-SA-06:14.fpu + Correct a local information leakage bug affecting AMD FPUs. + 20060322: p28 FreeBSD-SA-06:11.ipsec, FreeBSD-SA-06:12.opie, FreeBSD-SA-06:13.sendmail Add missing code needed for the detection of IPSec packet diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c index 38f1c161e794..53bd3e97cbf9 100644 --- a/sys/amd64/amd64/fpu.c +++ b/sys/amd64/amd64/fpu.c @@ -97,6 +97,8 @@ void stop_emulating(void); typedef u_char bool_t; +static void fpu_clean_state(void); + int hw_float = 1; SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, &hw_float, 0, @@ -408,6 +410,8 @@ fpudna() PCPU_SET(fpcurthread, curthread); pcb = PCPU_GET(curpcb); + fpu_clean_state(); + if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { /* * This is the first time this thread has used the FPU, @@ -475,6 +479,7 @@ fpusetregs(struct thread *td, struct savefpu *addr) s = intr_disable(); if (td == PCPU_GET(fpcurthread)) { + fpu_clean_state(); fxrstor(addr); intr_restore(s); } else { @@ -485,6 +490,37 @@ fpusetregs(struct thread *td, struct savefpu *addr) } /* + * On AuthenticAMD processors, the fxrstor instruction does not restore + * the x87's stored last instruction pointer, last data pointer, and last + * opcode values, except in the rare case in which the exception summary + * (ES) bit in the x87 status word is set to 1. + * + * In order to avoid leaking this information across processes, we clean + * these values by performing a dummy load before executing fxrstor(). + */ +static double dummy_variable = 0.0; +static void +fpu_clean_state(void) +{ + u_short status; + + /* + * Clear the ES bit in the x87 status word if it is currently + * set, in order to avoid causing a fault in the upcoming load. + */ + fnstsw(&status); + if (status & 0x80) + fnclex(); + + /* + * Load the dummy variable into the x87 stack. This mangles + * the x87 stack, but we don't care since we're about to call + * fxrstor() anyway. + */ + __asm __volatile("ffree %%st(7); fld %0" : : "m" (dummy_variable)); +} + +/* * This really sucks. We want the acpi version only, but it requires * the isa_if.h file in order to get the definitions. */ diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh index f3e385b93e7e..26ce9b85ced2 100644 --- a/sys/conf/newvers.sh +++ b/sys/conf/newvers.sh @@ -32,7 +32,7 @@ TYPE="FreeBSD" REVISION="5.3" -BRANCH="RELEASE-p28" +BRANCH="RELEASE-p29" RELEASE="${REVISION}-${BRANCH}" VERSION="${TYPE} ${RELEASE}" diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c index 3d625baef4db..9ab1449fab6b 100644 --- a/sys/i386/isa/npx.c +++ b/sys/i386/isa/npx.c @@ -151,6 +151,10 @@ void stop_emulating(void); typedef u_char bool_t; +#ifdef CPU_ENABLE_SSE +static void fpu_clean_state(void); +#endif + static void fpusave(union savefpu *); static void fpurstor(union savefpu *); static int npx_attach(device_t dev); @@ -970,15 +974,49 @@ fpusave(addr) fnsave(addr); } +#ifdef CPU_ENABLE_SSE +/* + * On AuthenticAMD processors, the fxrstor instruction does not restore + * the x87's stored last instruction pointer, last data pointer, and last + * opcode values, except in the rare case in which the exception summary + * (ES) bit in the x87 status word is set to 1. + * + * In order to avoid leaking this information across processes, we clean + * these values by performing a dummy load before executing fxrstor(). + */ +static double dummy_variable = 0.0; +static void +fpu_clean_state(void) +{ + u_short status; + + /* + * Clear the ES bit in the x87 status word if it is currently + * set, in order to avoid causing a fault in the upcoming load. + */ + fnstsw(&status); + if (status & 0x80) + fnclex(); + + /* + * Load the dummy variable into the x87 stack. This mangles + * the x87 stack, but we don't care since we're about to call + * fxrstor() anyway. + */ + __asm __volatile("ffree %%st(7); fld %0" : : "m" (dummy_variable)); +} +#endif /* CPU_ENABLE_SSE */ + static void fpurstor(addr) union savefpu *addr; { #ifdef CPU_ENABLE_SSE - if (cpu_fxsr) + if (cpu_fxsr) { + fpu_clean_state(); fxrstor(addr); - else + } else #endif frstor(addr); } |