aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGordon Tetlow <gordon@FreeBSD.org>2018-09-12 05:08:49 +0000
committerGordon Tetlow <gordon@FreeBSD.org>2018-09-12 05:08:49 +0000
commitcf9763771d54a69970ce309ff6b658dc094e25be (patch)
tree57528b6d2552d8ede8fda96d75615820d110dd15
parentbd3035529c3c9257a04f4b2acffd0945246d68ec (diff)
downloadsrc-cf9763771d54a69970ce309ff6b658dc094e25be.tar.gz
src-cf9763771d54a69970ce309ff6b658dc094e25be.zip
Fix regression in Lazy FPU remediation. [EN-18:08.lazyfpu]
Approved by: so Security: FreeBSD-EN-18:08.lazyfpu
Notes
Notes: svn path=/releng/11.1/; revision=338607
-rw-r--r--sys/amd64/amd64/fpu.c36
-rw-r--r--sys/amd64/amd64/machdep.c2
-rw-r--r--sys/i386/i386/machdep.c2
-rw-r--r--sys/i386/isa/npx.c38
4 files changed, 43 insertions, 35 deletions
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
index 503a4e52904f..41366ac52432 100644
--- a/sys/amd64/amd64/fpu.c
+++ b/sys/amd64/amd64/fpu.c
@@ -743,22 +743,22 @@ fpugetregs(struct thread *td)
int max_ext_n, i, owned;
pcb = td->td_pcb;
+ critical_enter();
if ((pcb->pcb_flags & PCB_USERFPUINITDONE) == 0) {
bcopy(fpu_initialstate, get_pcb_user_save_pcb(pcb),
cpu_max_ext_state_size);
get_pcb_user_save_pcb(pcb)->sv_env.en_cw =
pcb->pcb_initial_fpucw;
fpuuserinited(td);
+ critical_exit();
return (_MC_FPOWNED_PCB);
}
- critical_enter();
if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
fpusave(get_pcb_user_save_pcb(pcb));
owned = _MC_FPOWNED_FPU;
} else {
owned = _MC_FPOWNED_PCB;
}
- critical_exit();
if (use_xsave) {
/*
* Handle partially saved state.
@@ -778,6 +778,7 @@ fpugetregs(struct thread *td)
*xstate_bv |= bit;
}
}
+ critical_exit();
return (owned);
}
@@ -786,6 +787,7 @@ fpuuserinited(struct thread *td)
{
struct pcb *pcb;
+ CRITICAL_ASSERT(td);
pcb = td->td_pcb;
if (PCB_USER_FPU(pcb))
set_pcb_flags(pcb,
@@ -843,26 +845,25 @@ fpusetregs(struct thread *td, struct savefpu *addr, char *xfpustate,
int error;
pcb = td->td_pcb;
+ error = 0;
critical_enter();
if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
error = fpusetxstate(td, xfpustate, xfpustate_size);
- if (error != 0) {
- critical_exit();
- return (error);
+ if (error == 0) {
+ bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+ fpurestore(get_pcb_user_save_td(td));
+ set_pcb_flags(pcb, PCB_FPUINITDONE |
+ PCB_USERFPUINITDONE);
}
- bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
- fpurestore(get_pcb_user_save_td(td));
- critical_exit();
- set_pcb_flags(pcb, PCB_FPUINITDONE | PCB_USERFPUINITDONE);
} else {
- critical_exit();
error = fpusetxstate(td, xfpustate, xfpustate_size);
- if (error != 0)
- return (error);
- bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
- fpuuserinited(td);
+ if (error == 0) {
+ bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+ fpuuserinited(td);
+ }
}
- return (0);
+ critical_exit();
+ return (error);
}
/*
@@ -1035,6 +1036,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
ctx->flags = FPU_KERN_CTX_DUMMY | FPU_KERN_CTX_INUSE;
return (0);
}
+ critical_enter();
KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save ==
get_pcb_user_save_pcb(pcb), ("mangled pcb_save"));
ctx->flags = FPU_KERN_CTX_INUSE;
@@ -1045,6 +1047,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
pcb->pcb_save = fpu_kern_ctx_savefpu(ctx);
set_pcb_flags(pcb, PCB_KERNFPU);
clear_pcb_flags(pcb, PCB_FPUINITDONE);
+ critical_exit();
return (0);
}
@@ -1063,7 +1066,6 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
clear_pcb_flags(pcb, PCB_FPUNOSAVE | PCB_FPUINITDONE);
start_emulating();
- critical_exit();
} else {
KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0,
("leaving not inuse ctx"));
@@ -1077,7 +1079,6 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
critical_enter();
if (curthread == PCPU_GET(fpcurthread))
fpudrop();
- critical_exit();
pcb->pcb_save = ctx->prev;
}
@@ -1094,6 +1095,7 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
clear_pcb_flags(pcb, PCB_FPUINITDONE);
KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
}
+ critical_exit();
return (0);
}
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 3419dea04354..3dc0de2a1968 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -2148,8 +2148,10 @@ int
set_fpregs(struct thread *td, struct fpreg *fpregs)
{
+ critical_enter();
set_fpregs_xmm(fpregs, get_pcb_user_save_td(td));
fpuuserinited(td);
+ critical_exit();
return (0);
}
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 24c1fe80383c..ed279237b2f5 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -2998,6 +2998,7 @@ int
set_fpregs(struct thread *td, struct fpreg *fpregs)
{
+ critical_enter();
if (cpu_fxsr)
npx_set_fpregs_xmm((struct save87 *)fpregs,
&get_pcb_user_save_td(td)->sv_xmm);
@@ -3005,6 +3006,7 @@ set_fpregs(struct thread *td, struct fpreg *fpregs)
bcopy(fpregs, &get_pcb_user_save_td(td)->sv_87,
sizeof(*fpregs));
npxuserinited(td);
+ critical_exit();
return (0);
}
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index f0f2fb74a0f0..9a46e8554526 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -974,14 +974,15 @@ npxgetregs(struct thread *td)
return (_MC_FPOWNED_NONE);
pcb = td->td_pcb;
+ critical_enter();
if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
bcopy(npx_initialstate, get_pcb_user_save_pcb(pcb),
cpu_max_ext_state_size);
SET_FPU_CW(get_pcb_user_save_pcb(pcb), pcb->pcb_initial_npxcw);
npxuserinited(td);
+ critical_exit();
return (_MC_FPOWNED_PCB);
}
- critical_enter();
if (td == PCPU_GET(fpcurthread)) {
fpusave(get_pcb_user_save_pcb(pcb));
if (!cpu_fxsr)
@@ -995,7 +996,6 @@ npxgetregs(struct thread *td)
} else {
owned = _MC_FPOWNED_PCB;
}
- critical_exit();
if (use_xsave) {
/*
* Handle partially saved state.
@@ -1018,6 +1018,7 @@ npxgetregs(struct thread *td)
*xstate_bv |= bit;
}
}
+ critical_exit();
return (owned);
}
@@ -1026,6 +1027,7 @@ npxuserinited(struct thread *td)
{
struct pcb *pcb;
+ CRITICAL_ASSERT(td);
pcb = td->td_pcb;
if (PCB_USER_FPU(pcb))
pcb->pcb_flags |= PCB_NPXINITDONE;
@@ -1081,28 +1083,26 @@ npxsetregs(struct thread *td, union savefpu *addr, char *xfpustate,
return (ENXIO);
pcb = td->td_pcb;
+ error = 0;
critical_enter();
if (td == PCPU_GET(fpcurthread) && PCB_USER_FPU(pcb)) {
error = npxsetxstate(td, xfpustate, xfpustate_size);
- if (error != 0) {
- critical_exit();
- return (error);
+ if (error == 0) {
+ if (!cpu_fxsr)
+ fnclex(); /* As in npxdrop(). */
+ bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+ fpurstor(get_pcb_user_save_td(td));
+ pcb->pcb_flags |= PCB_NPXUSERINITDONE | PCB_NPXINITDONE;
}
- if (!cpu_fxsr)
- fnclex(); /* As in npxdrop(). */
- bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
- fpurstor(get_pcb_user_save_td(td));
- critical_exit();
- pcb->pcb_flags |= PCB_NPXUSERINITDONE | PCB_NPXINITDONE;
} else {
- critical_exit();
error = npxsetxstate(td, xfpustate, xfpustate_size);
- if (error != 0)
- return (error);
- bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
- npxuserinited(td);
+ if (error == 0) {
+ bcopy(addr, get_pcb_user_save_td(td), sizeof(*addr));
+ npxuserinited(td);
+ }
}
- return (0);
+ critical_exit();
+ return (error);
}
static void
@@ -1371,6 +1371,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
return (0);
}
pcb = td->td_pcb;
+ critical_enter();
KASSERT(!PCB_USER_FPU(pcb) || pcb->pcb_save ==
get_pcb_user_save_pcb(pcb), ("mangled pcb_save"));
ctx->flags = FPU_KERN_CTX_INUSE;
@@ -1381,6 +1382,7 @@ fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags)
pcb->pcb_save = fpu_kern_ctx_savefpu(ctx);
pcb->pcb_flags |= PCB_KERNNPX;
pcb->pcb_flags &= ~PCB_NPXINITDONE;
+ critical_exit();
return (0);
}
@@ -1399,7 +1401,6 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
critical_enter();
if (curthread == PCPU_GET(fpcurthread))
npxdrop();
- critical_exit();
pcb->pcb_save = ctx->prev;
if (pcb->pcb_save == get_pcb_user_save_pcb(pcb)) {
if ((pcb->pcb_flags & PCB_NPXUSERINITDONE) != 0)
@@ -1414,6 +1415,7 @@ fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx)
pcb->pcb_flags &= ~PCB_NPXINITDONE;
KASSERT(!PCB_USER_FPU(pcb), ("unpaired fpu_kern_leave"));
}
+ critical_exit();
return (0);
}