Enable eager FPU context switch by default on i386 too, based on
amd64 r335072. Security: CVE-2018-3665 Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
75b6758daa
commit
fc3e80c322
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=335089
|
@ -191,6 +191,11 @@ int hw_float;
|
||||||
SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
|
SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
|
||||||
&hw_float, 0, "Floating point instructions executed in hardware");
|
&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;
|
int use_xsave;
|
||||||
uint64_t xsave_mask;
|
uint64_t xsave_mask;
|
||||||
static uma_zone_t fpu_save_area_zone;
|
static uma_zone_t fpu_save_area_zone;
|
||||||
|
@ -319,6 +324,7 @@ npxinit_bsp1(void)
|
||||||
u_int cp[4];
|
u_int cp[4];
|
||||||
uint64_t xsave_mask_user;
|
uint64_t xsave_mask_user;
|
||||||
|
|
||||||
|
TUNABLE_INT_FETCH("hw.lazy_fpu_switch", &lazy_fpu_switch);
|
||||||
if (cpu_fxsr && (cpu_feature2 & CPUID2_XSAVE) != 0) {
|
if (cpu_fxsr && (cpu_feature2 & CPUID2_XSAVE) != 0) {
|
||||||
use_xsave = 1;
|
use_xsave = 1;
|
||||||
TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
|
TUNABLE_INT_FETCH("hw.use_xsave", &use_xsave);
|
||||||
|
@ -777,6 +783,42 @@ npxtrap_sse(void)
|
||||||
return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]);
|
return (fpetable[(mxcsr & (~mxcsr >> 7)) & 0x3f]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
restore_npx_curthread(struct thread *td, struct pcb *pcb)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record new context early in case frstor causes a trap.
|
||||||
|
*/
|
||||||
|
PCPU_SET(fpcurthread, td);
|
||||||
|
|
||||||
|
stop_emulating();
|
||||||
|
if (cpu_fxsr)
|
||||||
|
fpu_clean_state();
|
||||||
|
|
||||||
|
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
|
||||||
|
* load an initial state.
|
||||||
|
*
|
||||||
|
* We prefer to restore the state from the actual save
|
||||||
|
* area in PCB instead of directly loading from
|
||||||
|
* npx_initialstate, to ignite the XSAVEOPT
|
||||||
|
* tracking engine.
|
||||||
|
*/
|
||||||
|
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(pcb->pcb_save);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implement device not available (DNA) exception
|
* Implement device not available (DNA) exception
|
||||||
*
|
*
|
||||||
|
@ -790,11 +832,13 @@ static int err_count = 0;
|
||||||
int
|
int
|
||||||
npxdna(void)
|
npxdna(void)
|
||||||
{
|
{
|
||||||
|
struct thread *td;
|
||||||
|
|
||||||
if (!hw_float)
|
if (!hw_float)
|
||||||
return (0);
|
return (0);
|
||||||
|
td = curthread;
|
||||||
critical_enter();
|
critical_enter();
|
||||||
if (PCPU_GET(fpcurthread) == curthread) {
|
if (PCPU_GET(fpcurthread) == td) {
|
||||||
printf("npxdna: fpcurthread == curthread %d times\n",
|
printf("npxdna: fpcurthread == curthread %d times\n",
|
||||||
++err_count);
|
++err_count);
|
||||||
stop_emulating();
|
stop_emulating();
|
||||||
|
@ -805,39 +849,10 @@ npxdna(void)
|
||||||
printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n",
|
printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n",
|
||||||
PCPU_GET(fpcurthread),
|
PCPU_GET(fpcurthread),
|
||||||
PCPU_GET(fpcurthread)->td_proc->p_pid,
|
PCPU_GET(fpcurthread)->td_proc->p_pid,
|
||||||
curthread, curthread->td_proc->p_pid);
|
td, td->td_proc->p_pid);
|
||||||
panic("npxdna");
|
panic("npxdna");
|
||||||
}
|
}
|
||||||
stop_emulating();
|
restore_npx_curthread(td, td->td_pcb);
|
||||||
/*
|
|
||||||
* Record new context early in case frstor causes a trap.
|
|
||||||
*/
|
|
||||||
PCPU_SET(fpcurthread, curthread);
|
|
||||||
|
|
||||||
if (cpu_fxsr)
|
|
||||||
fpu_clean_state();
|
|
||||||
|
|
||||||
if ((curpcb->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
|
|
||||||
* load an initial state.
|
|
||||||
*
|
|
||||||
* We prefer to restore the state from the actual save
|
|
||||||
* area in PCB instead of directly loading from
|
|
||||||
* 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;
|
|
||||||
} else {
|
|
||||||
fpurstor(curpcb->pcb_save);
|
|
||||||
}
|
|
||||||
critical_exit();
|
critical_exit();
|
||||||
|
|
||||||
return (1);
|
return (1);
|
||||||
|
@ -861,8 +876,20 @@ npxsave(addr)
|
||||||
xsaveopt((char *)addr, xsave_mask);
|
xsaveopt((char *)addr, xsave_mask);
|
||||||
else
|
else
|
||||||
fpusave(addr);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -283,6 +283,12 @@ sw1:
|
||||||
cpu_switch_load_gs:
|
cpu_switch_load_gs:
|
||||||
mov PCB_GS(%edx),%gs
|
mov PCB_GS(%edx),%gs
|
||||||
|
|
||||||
|
pushl %edx
|
||||||
|
pushl PCPU(CURTHREAD)
|
||||||
|
call npxswitch
|
||||||
|
popl %edx
|
||||||
|
popl %edx
|
||||||
|
|
||||||
/* Test if debug registers should be restored. */
|
/* Test if debug registers should be restored. */
|
||||||
testl $PCB_DBREGS,PCB_FLAGS(%edx)
|
testl $PCB_DBREGS,PCB_FLAGS(%edx)
|
||||||
jz 1f
|
jz 1f
|
||||||
|
|
Loading…
Reference in New Issue
Block a user