diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index 8d6e954db2a7..9c9f4c0b0106 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c @@ -388,11 +388,22 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, xsave_hdr = &target->thread.fpu.state->xsave.xsave_hdr; xsave_hdr->xstate_bv &= pcntxt_mask; + + /* xcomp_bv must be 0 when using uncompacted format */ + if (!ret && xsave_hdr->xcomp_bv) + ret = -EINVAL; + /* * These bits must be zero. */ memset(xsave_hdr->reserved, 0, 48); + /* + * In case of failure, mark all states as init: + */ + if (ret) + fpu_finit(&target->thread.fpu); + return ret; } diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index cdc6cf903078..460e72155f51 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -394,7 +394,9 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size) drop_fpu(tsk); if (__copy_from_user(&fpu->state->xsave, buf_fx, state_size) || - __copy_from_user(&env, buf, sizeof(env))) { + __copy_from_user(&env, buf, sizeof(env)) || + (state_size > offsetof(struct xsave_struct, xsave_hdr) && + fpu->state->xsave.xsave_hdr.xcomp_bv)) { fpu_finit(fpu); err = -1; } else {