amd64: eliminate td_md.md_fpu_scratch
For signal send, copyout from the user FPU save area directly. For sigreturn, we are in sleepable context and can do temporal allocation of the transient save area. We cannot copying from userspace directly to user save area because XSAVE state needs to be validated, also partial copyins can corrupt it. Requested by: jhb Reviewed by: jhb, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D31954
This commit is contained in:
parent
df8dd6025a
commit
bd9e0f5df6
@ -96,7 +96,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/trap.h>
|
||||
|
||||
static void get_fpcontext(struct thread *td, mcontext_t *mcp,
|
||||
char *xfpusave, size_t xfpusave_len);
|
||||
char **xfpusave, size_t *xfpusave_len);
|
||||
static int set_fpcontext(struct thread *td, mcontext_t *mcp,
|
||||
char *xfpustate, size_t xfpustate_len);
|
||||
|
||||
@ -133,14 +133,6 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
regs = td->td_frame;
|
||||
oonstack = sigonstack(regs->tf_rsp);
|
||||
|
||||
if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) {
|
||||
xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu);
|
||||
xfpusave = (char *)td->td_md.md_fpu_scratch;
|
||||
} else {
|
||||
xfpusave_len = 0;
|
||||
xfpusave = NULL;
|
||||
}
|
||||
|
||||
/* Save user context. */
|
||||
bzero(&sf, sizeof(sf));
|
||||
sf.sf_uc.uc_sigmask = *mask;
|
||||
@ -150,7 +142,7 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0;
|
||||
bcopy(regs, &sf.sf_uc.uc_mcontext.mc_rdi, sizeof(*regs));
|
||||
sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
|
||||
get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
|
||||
get_fpcontext(td, &sf.sf_uc.uc_mcontext, &xfpusave, &xfpusave_len);
|
||||
fpstate_drop(td);
|
||||
update_pcb_bases(pcb);
|
||||
sf.sf_uc.uc_mcontext.mc_fsbase = pcb->pcb_fsbase;
|
||||
@ -301,10 +293,11 @@ sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
|
||||
p->p_pid, td->td_name, xfpustate_len);
|
||||
return (EINVAL);
|
||||
}
|
||||
xfpustate = __builtin_alloca(xfpustate_len);
|
||||
xfpustate = (char *)fpu_save_area_alloc();
|
||||
error = copyin((const void *)uc.uc_mcontext.mc_xfpustate,
|
||||
xfpustate, xfpustate_len);
|
||||
if (error != 0) {
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
uprintf(
|
||||
"pid %d (%s): sigreturn copying xfpustate failed\n",
|
||||
p->p_pid, td->td_name);
|
||||
@ -315,6 +308,7 @@ sys_sigreturn(struct thread *td, struct sigreturn_args *uap)
|
||||
xfpustate_len = 0;
|
||||
}
|
||||
ret = set_fpcontext(td, &ucp->uc_mcontext, xfpustate, xfpustate_len);
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
if (ret != 0) {
|
||||
uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n",
|
||||
p->p_pid, td->td_name, ret);
|
||||
@ -674,14 +668,17 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
|
||||
if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
|
||||
sizeof(struct savefpu))
|
||||
return (EINVAL);
|
||||
xfpustate = (char *)td->td_md.md_fpu_scratch;
|
||||
xfpustate = (char *)fpu_save_area_alloc();
|
||||
ret = copyin((void *)mcp->mc_xfpustate, xfpustate,
|
||||
mcp->mc_xfpustate_len);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
return (ret);
|
||||
}
|
||||
} else
|
||||
xfpustate = NULL;
|
||||
ret = set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
tp->tf_r15 = mcp->mc_r15;
|
||||
@ -719,26 +716,24 @@ set_mcontext(struct thread *td, mcontext_t *mcp)
|
||||
}
|
||||
|
||||
static void
|
||||
get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave,
|
||||
size_t xfpusave_len)
|
||||
get_fpcontext(struct thread *td, mcontext_t *mcp, char **xfpusave,
|
||||
size_t *xfpusave_len)
|
||||
{
|
||||
size_t max_len, len;
|
||||
|
||||
mcp->mc_ownedfp = fpugetregs(td);
|
||||
bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0],
|
||||
sizeof(mcp->mc_fpstate));
|
||||
mcp->mc_fpformat = fpuformat();
|
||||
if (!use_xsave || xfpusave_len == 0)
|
||||
if (xfpusave == NULL)
|
||||
return;
|
||||
max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
|
||||
len = xfpusave_len;
|
||||
if (len > max_len) {
|
||||
len = max_len;
|
||||
bzero(xfpusave + max_len, len - max_len);
|
||||
}
|
||||
if (!use_xsave || cpu_max_ext_state_size <= sizeof(struct savefpu)) {
|
||||
*xfpusave_len = 0;
|
||||
*xfpusave = NULL;
|
||||
} else {
|
||||
mcp->mc_flags |= _MC_HASFPXSTATE;
|
||||
mcp->mc_xfpustate_len = len;
|
||||
bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
|
||||
*xfpusave_len = mcp->mc_xfpustate_len =
|
||||
cpu_max_ext_state_size - sizeof(struct savefpu);
|
||||
*xfpusave = (char *)(get_pcb_user_save_td(td) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -392,7 +392,6 @@ cpu_thread_alloc(struct thread *td)
|
||||
td->td_pcb = pcb = get_pcb_td(td);
|
||||
td->td_frame = (struct trapframe *)td->td_md.md_stack_base - 1;
|
||||
td->td_md.md_usr_fpu_save = fpu_save_area_alloc();
|
||||
td->td_md.md_fpu_scratch = fpu_save_area_alloc();
|
||||
pcb->pcb_save = get_pcb_user_save_pcb(pcb);
|
||||
if (use_xsave) {
|
||||
xhdr = (struct xstate_hdr *)(pcb->pcb_save + 1);
|
||||
@ -408,8 +407,6 @@ cpu_thread_free(struct thread *td)
|
||||
|
||||
fpu_save_area_free(td->td_md.md_usr_fpu_save);
|
||||
td->td_md.md_usr_fpu_save = NULL;
|
||||
fpu_save_area_free(td->td_md.md_fpu_scratch);
|
||||
td->td_md.md_fpu_scratch = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -87,10 +87,8 @@ static void freebsd4_ia32_sendsig(sig_t, ksiginfo_t *, sigset_t *);
|
||||
|
||||
static void
|
||||
ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp,
|
||||
char *xfpusave, size_t xfpusave_len)
|
||||
char **xfpusave, size_t *xfpusave_len)
|
||||
{
|
||||
size_t max_len, len;
|
||||
|
||||
/*
|
||||
* XXX Format of 64bit and 32bit FXSAVE areas differs. FXSAVE
|
||||
* in 32bit mode saves %cs and %ds, while on 64bit it saves
|
||||
@ -101,17 +99,15 @@ ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp,
|
||||
bcopy(get_pcb_user_save_td(td), &mcp->mc_fpstate[0],
|
||||
sizeof(mcp->mc_fpstate));
|
||||
mcp->mc_fpformat = fpuformat();
|
||||
if (!use_xsave || xfpusave_len == 0)
|
||||
return;
|
||||
max_len = cpu_max_ext_state_size - sizeof(struct savefpu);
|
||||
len = xfpusave_len;
|
||||
if (len > max_len) {
|
||||
len = max_len;
|
||||
bzero(xfpusave + max_len, len - max_len);
|
||||
}
|
||||
if (!use_xsave || cpu_max_ext_state_size <= sizeof(struct savefpu)) {
|
||||
*xfpusave_len = 0;
|
||||
*xfpusave = NULL;
|
||||
} else {
|
||||
mcp->mc_flags |= _MC_IA32_HASFPXSTATE;
|
||||
mcp->mc_xfpustate_len = len;
|
||||
bcopy(get_pcb_user_save_td(td) + 1, xfpusave, len);
|
||||
*xfpusave_len = mcp->mc_xfpustate_len =
|
||||
cpu_max_ext_state_size - sizeof(struct savefpu);
|
||||
*xfpusave = (char *)(get_pcb_user_save_td(td) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@ -210,14 +206,17 @@ ia32_set_mcontext(struct thread *td, struct ia32_mcontext *mcp)
|
||||
if (mcp->mc_xfpustate_len > cpu_max_ext_state_size -
|
||||
sizeof(struct savefpu))
|
||||
return (EINVAL);
|
||||
xfpustate = (char *)td->td_md.md_fpu_scratch;
|
||||
xfpustate = (char *)fpu_save_area_alloc();
|
||||
ret = copyin(PTRIN(mcp->mc_xfpustate), xfpustate,
|
||||
mcp->mc_xfpustate_len);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
return (ret);
|
||||
}
|
||||
} else
|
||||
xfpustate = NULL;
|
||||
ret = ia32_set_fpcontext(td, mcp, xfpustate, mcp->mc_xfpustate_len);
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
tp->tf_gs = mcp->mc_gs;
|
||||
@ -577,14 +576,6 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
regs = td->td_frame;
|
||||
oonstack = sigonstack(regs->tf_rsp);
|
||||
|
||||
if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) {
|
||||
xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu);
|
||||
xfpusave = (char *)td->td_md.md_fpu_scratch;
|
||||
} else {
|
||||
xfpusave_len = 0;
|
||||
xfpusave = NULL;
|
||||
}
|
||||
|
||||
/* Save user context. */
|
||||
bzero(&sf, sizeof(sf));
|
||||
sf.sf_uc.uc_sigmask = *mask;
|
||||
@ -613,7 +604,7 @@ ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask)
|
||||
sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs;
|
||||
sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs;
|
||||
sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */
|
||||
ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len);
|
||||
ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext, &xfpusave, &xfpusave_len);
|
||||
fpstate_drop(td);
|
||||
sf.sf_uc.uc_mcontext.mc_fsbase = td->td_pcb->pcb_fsbase;
|
||||
sf.sf_uc.uc_mcontext.mc_gsbase = td->td_pcb->pcb_gsbase;
|
||||
@ -882,10 +873,11 @@ freebsd32_sigreturn(td, uap)
|
||||
td->td_proc->p_pid, td->td_name, xfpustate_len);
|
||||
return (EINVAL);
|
||||
}
|
||||
xfpustate = (char *)td->td_md.md_fpu_scratch;
|
||||
xfpustate = (char *)fpu_save_area_alloc();
|
||||
error = copyin(PTRIN(ucp->uc_mcontext.mc_xfpustate),
|
||||
xfpustate, xfpustate_len);
|
||||
if (error != 0) {
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
uprintf(
|
||||
"pid %d (%s): sigreturn copying xfpustate failed\n",
|
||||
td->td_proc->p_pid, td->td_name);
|
||||
@ -897,6 +889,7 @@ freebsd32_sigreturn(td, uap)
|
||||
}
|
||||
ret = ia32_set_fpcontext(td, &ucp->uc_mcontext, xfpustate,
|
||||
xfpustate_len);
|
||||
fpu_save_area_free((struct savefpu *)xfpustate);
|
||||
if (ret != 0) {
|
||||
uprintf("pid %d (%s): sigreturn set_fpcontext err %d\n",
|
||||
td->td_proc->p_pid, td->td_name, ret);
|
||||
|
@ -76,7 +76,6 @@ struct mdthread {
|
||||
struct pcb md_pcb;
|
||||
vm_offset_t md_stack_base;
|
||||
struct savefpu *md_usr_fpu_save;
|
||||
struct savefpu *md_fpu_scratch;
|
||||
};
|
||||
|
||||
struct mdproc {
|
||||
|
@ -91,7 +91,7 @@ _Static_assert(offsetof(struct thread, td_pflags) == 0x110,
|
||||
"struct thread KBI td_pflags");
|
||||
_Static_assert(offsetof(struct thread, td_frame) == 0x4a8,
|
||||
"struct thread KBI td_frame");
|
||||
_Static_assert(offsetof(struct thread, td_emuldata) == 0x6c0,
|
||||
_Static_assert(offsetof(struct thread, td_emuldata) == 0x6b0,
|
||||
"struct thread KBI td_emuldata");
|
||||
_Static_assert(offsetof(struct proc, p_flag) == 0xb8,
|
||||
"struct proc KBI p_flag");
|
||||
|
Loading…
Reference in New Issue
Block a user