Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3538312imu; Wed, 7 Nov 2018 11:53:22 -0800 (PST) X-Google-Smtp-Source: AJdET5dFXKGgjn0SGUIV1O4wr5YbdLkrJn2nm2yVLU/xZ1iqcD8Q/iXrOe8qDcqBDKxxlpZzk38U X-Received: by 2002:a63:da45:: with SMTP id l5mr1357483pgj.111.1541620402688; Wed, 07 Nov 2018 11:53:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541620402; cv=none; d=google.com; s=arc-20160816; b=cbSwFpKPAOVAcaHWnn5oE/Rz/gJ6HDrHoLtAC9bwpEx/eEtlOItCBx3iiWs8uTrHPR 0u2kjQlVY7i2uMVir2nDMKZF68IW31wrVzkfPPJmzUiuW8KHx+oOKag8hP1BQpZ9o9O+ nUrwBxNAjqGTMqFHePoulBgbVZyyiocJ77AEdTFIWNpnRAJCPNZF4cbpK25nIvlxgtfS JoMX4VdDG+kaIozYSITLeMflJMUeLRt3nI8J60v8wICxGhKAV7xcIso3kiERbkdxcLde yPdBbkbKQG4pxEQ5cdg32HfEwus8hEUxWx12ueguxhzN1J77M+oSoimyjNuni3y2RE2c mM3Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=pibyzDF7teKiRMr+ea2FFhkRsJx6TVOemjPT/rSUH9s=; b=0uSsArS1sQyCLQNcog+iN/jRy7exC0vkBD0/S0sQFrQhhMoI/mJfV0kcU4OOFfQW0I 7Y5NMfa+zq3tsu8vpoeMw1PV8nVrcxnjZ7HK8VkyC/Dok/6Hw5xN1pgUHBQaT9MJX65L Hci+sU0A9hM4lHxrKj23yAJzUSM0HlxbmQLH+y0p2DC/4/q1oOjY5hz/FVoYr7nf66Uk PRY8L9+Io4noiI6j3uhdB3h4QQ06oU8t+kendwOsNFBsQXsXafESwxXOndVhwJSYn0fi D3l4JH3DjB6RNvauflqL0za2Nqlv3erLOii4jf+xgQY7P/gLjFhG591v+REDJbyHf7js /HCA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v189si1398901pgb.398.2018.11.07.11.53.05; Wed, 07 Nov 2018 11:53:22 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727316AbeKHFVH (ORCPT + 99 others); Thu, 8 Nov 2018 00:21:07 -0500 Received: from Galois.linutronix.de ([146.0.238.70]:41874 "EHLO Galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725953AbeKHFVH (ORCPT ); Thu, 8 Nov 2018 00:21:07 -0500 Received: from localhost ([127.0.0.1] helo=bazinga.breakpoint.cc) by Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from ) id 1gKTp5-00070Q-J5; Wed, 07 Nov 2018 20:49:07 +0100 From: Sebastian Andrzej Siewior To: linux-kernel@vger.kernel.org Cc: x86@kernel.org, Andy Lutomirski , Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , kvm@vger.kernel.org, "Jason A. Donenfeld" , Rik van Riel , Dave Hansen , Sebastian Andrzej Siewior Subject: [PATCH 02/23] x86/fpu: Remove fpu->initialized usage in __fpu__restore_sig() Date: Wed, 7 Nov 2018 20:48:37 +0100 Message-Id: <20181107194858.9380-3-bigeasy@linutronix.de> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181107194858.9380-1-bigeasy@linutronix.de> References: <20181107194858.9380-1-bigeasy@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This is a preparation for the removal of the ->initialized member in the fpu struct. __fpu__restore_sig() is deactivating the FPU via fpu__drop() and then setting manually ->initialized followed by fpu__restore(). The result is that it is possible to manipulate fpu->state and the state of registers won't be saved/restore on a context switch which would overwrite state. Don't access the fpu->state while the content is read from user space and examined / sanitized. Use a temporary buffer kmalloc() buffer for the preparation of the FPU registers and once the state is considered okay, load it. Should something go wrong, return with and error and without altering the original FPU registers. The removal of "fpu__initialize()" is a nop because fpu->initialized is already set for the user task. Signed-off-by: Sebastian Andrzej Siewior --- arch/x86/include/asm/fpu/signal.h | 2 +- arch/x86/kernel/fpu/regset.c | 5 ++-- arch/x86/kernel/fpu/signal.c | 41 ++++++++++++------------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h index 44bbc39a57b30..7fb516b6893a8 100644 --- a/arch/x86/include/asm/fpu/signal.h +++ b/arch/x86/include/asm/fpu/signal.h @@ -22,7 +22,7 @@ int ia32_setup_frame(int sig, struct ksignal *ksig, extern void convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk); -extern void convert_to_fxsr(struct task_struct *tsk, +extern void convert_to_fxsr(struct fxregs_state *fxsave, const struct user_i387_ia32_struct *env); unsigned long diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index bc02f5144b958..5dbc099178a88 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -269,11 +269,10 @@ convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) memcpy(&to[i], &from[i], sizeof(to[0])); } -void convert_to_fxsr(struct task_struct *tsk, +void convert_to_fxsr(struct fxregs_state *fxsave, const struct user_i387_ia32_struct *env) { - struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave; struct _fpreg *from = (struct _fpreg *) &env->st_space[0]; struct _fpxreg *to = (struct _fpxreg *) &fxsave->st_space[0]; int i; @@ -350,7 +349,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1); if (!ret) - convert_to_fxsr(target, &env); + convert_to_fxsr(&target->thread.fpu.state.fxsave, &env); /* * update the header bit in the xsave header, indicating the diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 61a949d84dfa5..5777ee0c32fed 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -207,11 +207,11 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) } static inline void -sanitize_restored_xstate(struct task_struct *tsk, +sanitize_restored_xstate(union fpregs_state *state, struct user_i387_ia32_struct *ia32_env, u64 xfeatures, int fx_only) { - struct xregs_state *xsave = &tsk->thread.fpu.state.xsave; + struct xregs_state *xsave = &state->xsave; struct xstate_header *header = &xsave->header; if (use_xsave()) { @@ -238,7 +238,7 @@ sanitize_restored_xstate(struct task_struct *tsk, */ xsave->i387.mxcsr &= mxcsr_feature_mask; - convert_to_fxsr(tsk, ia32_env); + convert_to_fxsr(&state->fxsave, ia32_env); } } @@ -284,8 +284,6 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) if (!access_ok(VERIFY_READ, buf, size)) return -EACCES; - fpu__initialize(fpu); - if (!static_cpu_has(X86_FEATURE_FPU)) return fpregs_soft_set(current, NULL, 0, sizeof(struct user_i387_ia32_struct), @@ -314,41 +312,34 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) * thread's fpu state, reconstruct fxstate from the fsave * header. Validate and sanitize the copied state. */ + union fpregs_state *state; + void *tmp; struct user_i387_ia32_struct env; int err = 0; - /* - * Drop the current fpu which clears fpu->initialized. This ensures - * that any context-switch during the copy of the new state, - * avoids the intermediate state from getting restored/saved. - * Thus avoiding the new restored state from getting corrupted. - * We will be ready to restore/save the state only after - * fpu->initialized is again set. - */ - fpu__drop(fpu); + tmp = kmalloc(sizeof(*state) + fpu_kernel_xstate_size + 64, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + state = PTR_ALIGN(tmp, 64); if (using_compacted_format()) { - err = copy_user_to_xstate(&fpu->state.xsave, buf_fx); + err = copy_user_to_xstate(&state->xsave, buf_fx); } else { - err = __copy_from_user(&fpu->state.xsave, buf_fx, state_size); + err = __copy_from_user(&state->xsave, buf_fx, state_size); if (!err && state_size > offsetof(struct xregs_state, header)) - err = validate_xstate_header(&fpu->state.xsave.header); + err = validate_xstate_header(&state->xsave.header); } if (err || __copy_from_user(&env, buf, sizeof(env))) { - fpstate_init(&fpu->state); - trace_x86_fpu_init_state(fpu); err = -1; } else { - sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); + sanitize_restored_xstate(state, &env, + xfeatures, fx_only); + copy_kernel_to_fpregs(state); } - fpu->initialized = 1; - preempt_disable(); - fpu__restore(fpu); - preempt_enable(); - + kfree(tmp); return err; } else { /* -- 2.19.1