Commit 5d6b6a6f authored by Yu-cheng Yu's avatar Yu-cheng Yu Committed by Borislav Petkov
Browse files

x86/fpu/xstate: Update sanitize_restored_xstate() for supervisor xstates



The function sanitize_restored_xstate() sanitizes user xstates of an XSAVE
buffer by clearing bits not in the input 'xfeatures' from the buffer's
header->xfeatures, effectively resetting those features back to the init
state.

When supervisor xstates are introduced, it is necessary to make sure only
user xstates are sanitized.  Ensure supervisor bits in header->xfeatures
stay set and supervisor states are not modified.

To make names clear, also:

- Rename the function to sanitize_restored_user_xstate().
- Rename input parameter 'xfeatures' to 'user_xfeatures'.
- In __fpu__restore_sig(), rename 'xfeatures' to 'user_xfeatures'.

Signed-off-by: default avatarYu-cheng Yu <yu-cheng.yu@intel.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Link: https://lkml.kernel.org/r/20200512145444.15483-7-yu-cheng.yu@intel.com
parent b860eb8d
Loading
Loading
Loading
Loading
+24 −13
Original line number Diff line number Diff line
@@ -211,9 +211,9 @@ retry:
}

static inline void
sanitize_restored_xstate(union fpregs_state *state,
sanitize_restored_user_xstate(union fpregs_state *state,
			      struct user_i387_ia32_struct *ia32_env,
			 u64 xfeatures, int fx_only)
			      u64 user_xfeatures, int fx_only)
{
	struct xregs_state *xsave = &state->xsave;
	struct xstate_header *header = &xsave->header;
@@ -226,13 +226,22 @@ sanitize_restored_xstate(union fpregs_state *state,
		 */

		/*
		 * Init the state that is not present in the memory
		 * layout and not enabled by the OS.
		 * 'user_xfeatures' might have bits clear which are
		 * set in header->xfeatures. This represents features that
		 * were in init state prior to a signal delivery, and need
		 * to be reset back to the init state.  Clear any user
		 * feature bits which are set in the kernel buffer to get
		 * them back to the init state.
		 *
		 * Supervisor state is unchanged by input from userspace.
		 * Ensure supervisor state bits stay set and supervisor
		 * state is not modified.
		 */
		if (fx_only)
			header->xfeatures = XFEATURE_MASK_FPSSE;
		else
			header->xfeatures &= xfeatures;
			header->xfeatures &= user_xfeatures |
					     xfeatures_mask_supervisor();
	}

	if (use_fxsr()) {
@@ -281,7 +290,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
	struct task_struct *tsk = current;
	struct fpu *fpu = &tsk->thread.fpu;
	struct user_i387_ia32_struct env;
	u64 xfeatures = 0;
	u64 user_xfeatures = 0;
	int fx_only = 0;
	int ret = 0;

@@ -314,7 +323,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
			trace_x86_fpu_xstate_check_failed(fpu);
		} else {
			state_size = fx_sw_user.xstate_size;
			xfeatures = fx_sw_user.xfeatures;
			user_xfeatures = fx_sw_user.xfeatures;
		}
	}

@@ -349,7 +358,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
		 */
		fpregs_lock();
		pagefault_disable();
		ret = copy_user_to_fpregs_zeroing(buf_fx, xfeatures, fx_only);
		ret = copy_user_to_fpregs_zeroing(buf_fx, user_xfeatures, fx_only);
		pagefault_enable();
		if (!ret) {
			fpregs_mark_activate();
@@ -362,7 +371,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)


	if (use_xsave() && !fx_only) {
		u64 init_bv = xfeatures_mask_user() & ~xfeatures;
		u64 init_bv = xfeatures_mask_user() & ~user_xfeatures;

		if (using_compacted_format()) {
			ret = copy_user_to_xstate(&fpu->state.xsave, buf_fx);
@@ -375,12 +384,13 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
		if (ret)
			goto err_out;

		sanitize_restored_xstate(&fpu->state, envp, xfeatures, fx_only);
		sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures,
					      fx_only);

		fpregs_lock();
		if (unlikely(init_bv))
			copy_kernel_to_xregs(&init_fpstate.xsave, init_bv);
		ret = copy_kernel_to_xregs_err(&fpu->state.xsave, xfeatures);
		ret = copy_kernel_to_xregs_err(&fpu->state.xsave, user_xfeatures);

	} else if (use_fxsr()) {
		ret = __copy_from_user(&fpu->state.fxsave, buf_fx, state_size);
@@ -389,7 +399,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
			goto err_out;
		}

		sanitize_restored_xstate(&fpu->state, envp, xfeatures, fx_only);
		sanitize_restored_user_xstate(&fpu->state, envp, user_xfeatures,
					      fx_only);

		fpregs_lock();
		if (use_xsave()) {