Commit 5509cc78 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Borislav Petkov

x86/fpu/signal: Use fpstate for size and features

For dynamically enabled features it's required to get the features which
are enabled for that context when restoring from sigframe.

The same applies for all signal frame size calculations.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/87ilxz5iew.ffs@tglx
parent 49e4eb41
...@@ -41,7 +41,7 @@ static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf, ...@@ -41,7 +41,7 @@ static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
/* Check for the first magic field and other error scenarios. */ /* Check for the first magic field and other error scenarios. */
if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
fx_sw->xstate_size < min_xstate_size || fx_sw->xstate_size < min_xstate_size ||
fx_sw->xstate_size > fpu_user_xstate_size || fx_sw->xstate_size > current->thread.fpu.fpstate->user_size ||
fx_sw->xstate_size > fx_sw->extended_size) fx_sw->xstate_size > fx_sw->extended_size)
goto setfx; goto setfx;
...@@ -98,7 +98,8 @@ static inline bool save_fsave_header(struct task_struct *tsk, void __user *buf) ...@@ -98,7 +98,8 @@ static inline bool save_fsave_header(struct task_struct *tsk, void __user *buf)
return true; return true;
} }
static inline bool save_xstate_epilog(void __user *buf, int ia32_frame) static inline bool save_xstate_epilog(void __user *buf, int ia32_frame,
unsigned int usize)
{ {
struct xregs_state __user *x = buf; struct xregs_state __user *x = buf;
struct _fpx_sw_bytes *sw_bytes; struct _fpx_sw_bytes *sw_bytes;
...@@ -113,7 +114,7 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame) ...@@ -113,7 +114,7 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame)
return !err; return !err;
err |= __put_user(FP_XSTATE_MAGIC2, err |= __put_user(FP_XSTATE_MAGIC2,
(__u32 __user *)(buf + fpu_user_xstate_size)); (__u32 __user *)(buf + usize));
/* /*
* Read the xfeatures which we copied (directly from the cpu or * Read the xfeatures which we copied (directly from the cpu or
...@@ -171,6 +172,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) ...@@ -171,6 +172,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct fpstate *fpstate = tsk->thread.fpu.fpstate;
int ia32_fxstate = (buf != buf_fx); int ia32_fxstate = (buf != buf_fx);
int ret; int ret;
...@@ -215,7 +217,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) ...@@ -215,7 +217,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
fpregs_unlock(); fpregs_unlock();
if (ret) { if (ret) {
if (!__clear_user(buf_fx, fpu_user_xstate_size)) if (!__clear_user(buf_fx, fpstate->user_size))
goto retry; goto retry;
return false; return false;
} }
...@@ -224,17 +226,18 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) ...@@ -224,17 +226,18 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
if ((ia32_fxstate || !use_fxsr()) && !save_fsave_header(tsk, buf)) if ((ia32_fxstate || !use_fxsr()) && !save_fsave_header(tsk, buf))
return false; return false;
if (use_fxsr() && !save_xstate_epilog(buf_fx, ia32_fxstate)) if (use_fxsr() &&
!save_xstate_epilog(buf_fx, ia32_fxstate, fpstate->user_size))
return false; return false;
return true; return true;
} }
static int __restore_fpregs_from_user(void __user *buf, u64 xrestore, static int __restore_fpregs_from_user(void __user *buf, u64 ufeatures,
bool fx_only) u64 xrestore, bool fx_only)
{ {
if (use_xsave()) { if (use_xsave()) {
u64 init_bv = xfeatures_mask_uabi() & ~xrestore; u64 init_bv = ufeatures & ~xrestore;
int ret; int ret;
if (likely(!fx_only)) if (likely(!fx_only))
...@@ -265,7 +268,8 @@ static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, ...@@ -265,7 +268,8 @@ static bool restore_fpregs_from_user(void __user *buf, u64 xrestore,
retry: retry:
fpregs_lock(); fpregs_lock();
pagefault_disable(); pagefault_disable();
ret = __restore_fpregs_from_user(buf, xrestore, fx_only); ret = __restore_fpregs_from_user(buf, fpu->fpstate->user_xfeatures,
xrestore, fx_only);
pagefault_enable(); pagefault_enable();
if (unlikely(ret)) { if (unlikely(ret)) {
...@@ -332,7 +336,7 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, ...@@ -332,7 +336,7 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx,
user_xfeatures = fx_sw_user.xfeatures; user_xfeatures = fx_sw_user.xfeatures;
} else { } else {
user_xfeatures = XFEATURE_MASK_FPSSE; user_xfeatures = XFEATURE_MASK_FPSSE;
state_size = fpu->fpstate->size; state_size = fpu->fpstate->user_size;
} }
if (likely(!ia32_fxstate)) { if (likely(!ia32_fxstate)) {
...@@ -425,10 +429,11 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, ...@@ -425,10 +429,11 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx,
return success; return success;
} }
static inline int xstate_sigframe_size(void) static inline unsigned int xstate_sigframe_size(struct fpstate *fpstate)
{ {
return use_xsave() ? fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE : unsigned int size = fpstate->user_size;
fpu_user_xstate_size;
return use_xsave() ? size + FP_XSTATE_MAGIC2_SIZE : size;
} }
/* /*
...@@ -436,17 +441,19 @@ static inline int xstate_sigframe_size(void) ...@@ -436,17 +441,19 @@ static inline int xstate_sigframe_size(void)
*/ */
bool fpu__restore_sig(void __user *buf, int ia32_frame) bool fpu__restore_sig(void __user *buf, int ia32_frame)
{ {
unsigned int size = xstate_sigframe_size();
struct fpu *fpu = &current->thread.fpu; struct fpu *fpu = &current->thread.fpu;
void __user *buf_fx = buf; void __user *buf_fx = buf;
bool ia32_fxstate = false; bool ia32_fxstate = false;
bool success = false; bool success = false;
unsigned int size;
if (unlikely(!buf)) { if (unlikely(!buf)) {
fpu__clear_user_states(fpu); fpu__clear_user_states(fpu);
return true; return true;
} }
size = xstate_sigframe_size(fpu->fpstate);
ia32_frame &= (IS_ENABLED(CONFIG_X86_32) || ia32_frame &= (IS_ENABLED(CONFIG_X86_32) ||
IS_ENABLED(CONFIG_IA32_EMULATION)); IS_ENABLED(CONFIG_IA32_EMULATION));
...@@ -481,7 +488,7 @@ unsigned long ...@@ -481,7 +488,7 @@ unsigned long
fpu__alloc_mathframe(unsigned long sp, int ia32_frame, fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
unsigned long *buf_fx, unsigned long *size) unsigned long *buf_fx, unsigned long *size)
{ {
unsigned long frame_size = xstate_sigframe_size(); unsigned long frame_size = xstate_sigframe_size(current->thread.fpu.fpstate);
*buf_fx = sp = round_down(sp - frame_size, 64); *buf_fx = sp = round_down(sp - frame_size, 64);
if (ia32_frame && use_fxsr()) { if (ia32_frame && use_fxsr()) {
...@@ -494,9 +501,12 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, ...@@ -494,9 +501,12 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
return sp; return sp;
} }
unsigned long fpu__get_fpstate_size(void) unsigned long __init fpu__get_fpstate_size(void)
{ {
unsigned long ret = xstate_sigframe_size(); unsigned long ret = fpu_user_xstate_size;
if (use_xsave())
ret += FP_XSTATE_MAGIC2_SIZE;
/* /*
* This space is needed on (most) 32-bit kernels, or when a 32-bit * This space is needed on (most) 32-bit kernels, or when a 32-bit
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment