Commit 40deb5e4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull x86 fpu updates from Dave Hansen:
 "There are two little fixes in here, one to give better XSAVE warnings
  and another to address some undefined behavior in offsetof().

  There is also a collection of patches to fix some issues with ptrace
  and the protection keys register (PKRU). PKRU is a real oddity because
  it is exposed in the XSAVE-related ABIs, but it is generally managed
  without using XSAVE in the kernel. This fix thankfully came with a
  selftest to ward off future regressions.

  Summary:

   - Clarify XSAVE consistency warnings

   - Fix up ptrace interface to protection keys register (PKRU)

   - Avoid undefined compiler behavior with TYPE_ALIGN"

* tag 'x86_fpu_for_6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/fpu: Use _Alignof to avoid undefined behavior in TYPE_ALIGN
  selftests/vm/pkeys: Add a regression test for setting PKRU through ptrace
  x86/fpu: Emulate XRSTOR's behavior if the xfeatures PKRU bit is not set
  x86/fpu: Allow PKRU to be (once again) written by ptrace.
  x86/fpu: Add a pkru argument to copy_uabi_to_xstate()
  x86/fpu: Add a pkru argument to copy_uabi_from_kernel_to_xstate().
  x86/fpu: Take task_struct* in copy_sigframe_from_user_to_xstate()
  x86/fpu/xstate: Fix XSTATE_WARN_ON() to emit relevant diagnostics
parents 1cab145a 55228db2
Loading
Loading
Loading
Loading
+8 −11
Original line number Diff line number Diff line
@@ -391,8 +391,6 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
{
	struct fpstate *kstate = gfpu->fpstate;
	const union fpregs_state *ustate = buf;
	struct pkru_state *xpkru;
	int ret;

	if (!cpu_feature_enabled(X86_FEATURE_XSAVE)) {
		if (ustate->xsave.header.xfeatures & ~XFEATURE_MASK_FPSSE)
@@ -406,16 +404,15 @@ int fpu_copy_uabi_to_guest_fpstate(struct fpu_guest *gfpu, const void *buf,
	if (ustate->xsave.header.xfeatures & ~xcr0)
		return -EINVAL;

	ret = copy_uabi_from_kernel_to_xstate(kstate, ustate);
	if (ret)
		return ret;
	/*
	 * Nullify @vpkru to preserve its current value if PKRU's bit isn't set
	 * in the header.  KVM's odd ABI is to leave PKRU untouched in this
	 * case (all other components are eventually re-initialized).
	 */
	if (!(ustate->xsave.header.xfeatures & XFEATURE_MASK_PKRU))
		vpkru = NULL;

	/* Retrieve PKRU if not in init state */
	if (kstate->regs.xsave.header.xfeatures & XFEATURE_MASK_PKRU) {
		xpkru = get_xsave_addr(&kstate->regs.xsave, XFEATURE_PKRU);
		*vpkru = xpkru->pkru;
	}
	return 0;
	return copy_uabi_from_kernel_to_xstate(kstate, ustate, vpkru);
}
EXPORT_SYMBOL_GPL(fpu_copy_uabi_to_guest_fpstate);
#endif /* CONFIG_KVM */
+2 −5
Original line number Diff line number Diff line
@@ -133,9 +133,6 @@ static void __init fpu__init_system_generic(void)
	fpu__init_system_mxcsr();
}

/* Get alignment of the TYPE. */
#define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test)

/*
 * Enforce that 'MEMBER' is the last field of 'TYPE'.
 *
@@ -143,8 +140,8 @@ static void __init fpu__init_system_generic(void)
 * because that's how C aligns structs.
 */
#define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
	BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \
					   TYPE_ALIGN(TYPE)))
	BUILD_BUG_ON(sizeof(TYPE) !=         \
		     ALIGN(offsetofend(TYPE, MEMBER), _Alignof(TYPE)))

/*
 * We append the 'struct fpu' to the task_struct:
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
	}

	fpu_force_restore(fpu);
	ret = copy_uabi_from_kernel_to_xstate(fpu->fpstate, kbuf ?: tmpbuf);
	ret = copy_uabi_from_kernel_to_xstate(fpu->fpstate, kbuf ?: tmpbuf, &target->thread.pkru);

out:
	vfree(tmpbuf);
+1 −1
Original line number Diff line number Diff line
@@ -396,7 +396,7 @@ static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx,

	fpregs = &fpu->fpstate->regs;
	if (use_xsave() && !fx_only) {
		if (copy_sigframe_from_user_to_xstate(fpu->fpstate, buf_fx))
		if (copy_sigframe_from_user_to_xstate(tsk, buf_fx))
			return false;
	} else {
		if (__copy_from_user(&fpregs->fxsave, buf_fx,
+53 −11
Original line number Diff line number Diff line
@@ -440,8 +440,8 @@ static void __init __xstate_dump_leaves(void)
	}
}

#define XSTATE_WARN_ON(x) do {							\
	if (WARN_ONCE(x, "XSAVE consistency problem, dumping leaves")) {	\
#define XSTATE_WARN_ON(x, fmt, ...) do {					\
	if (WARN_ONCE(x, "XSAVE consistency problem: " fmt, ##__VA_ARGS__)) {	\
		__xstate_dump_leaves();						\
	}									\
} while (0)
@@ -554,8 +554,7 @@ static bool __init check_xstate_against_struct(int nr)
	    (nr >= XFEATURE_MAX) ||
	    (nr == XFEATURE_PT_UNIMPLEMENTED_SO_FAR) ||
	    ((nr >= XFEATURE_RSRVD_COMP_11) && (nr <= XFEATURE_RSRVD_COMP_16))) {
		WARN_ONCE(1, "no structure for xstate: %d\n", nr);
		XSTATE_WARN_ON(1);
		XSTATE_WARN_ON(1, "No structure for xstate: %d\n", nr);
		return false;
	}
	return true;
@@ -598,12 +597,13 @@ static bool __init paranoid_xstate_size_valid(unsigned int kernel_size)
		 * XSAVES.
		 */
		if (!xsaves && xfeature_is_supervisor(i)) {
			XSTATE_WARN_ON(1);
			XSTATE_WARN_ON(1, "Got supervisor feature %d, but XSAVES not advertised\n", i);
			return false;
		}
	}
	size = xstate_calculate_size(fpu_kernel_cfg.max_features, compacted);
	XSTATE_WARN_ON(size != kernel_size);
	XSTATE_WARN_ON(size != kernel_size,
		       "size %u != kernel_size %u\n", size, kernel_size);
	return size == kernel_size;
}

@@ -1200,8 +1200,36 @@ static int copy_from_buffer(void *dst, unsigned int offset, unsigned int size,
}


/**
 * copy_uabi_to_xstate - Copy a UABI format buffer to the kernel xstate
 * @fpstate:	The fpstate buffer to copy to
 * @kbuf:	The UABI format buffer, if it comes from the kernel
 * @ubuf:	The UABI format buffer, if it comes from userspace
 * @pkru:	The location to write the PKRU value to
 *
 * Converts from the UABI format into the kernel internal hardware
 * dependent format.
 *
 * This function ultimately has three different callers with distinct PKRU
 * behavior.
 * 1.	When called from sigreturn the PKRU register will be restored from
 *	@fpstate via an XRSTOR. Correctly copying the UABI format buffer to
 *	@fpstate is sufficient to cover this case, but the caller will also
 *	pass a pointer to the thread_struct's pkru field in @pkru and updating
 *	it is harmless.
 * 2.	When called from ptrace the PKRU register will be restored from the
 *	thread_struct's pkru field. A pointer to that is passed in @pkru.
 *	The kernel will restore it manually, so the XRSTOR behavior that resets
 *	the PKRU register to the hardware init value (0) if the corresponding
 *	xfeatures bit is not set is emulated here.
 * 3.	When called from KVM the PKRU register will be restored from the vcpu's
 *	pkru field. A pointer to that is passed in @pkru. KVM hasn't used
 *	XRSTOR and hasn't had the PKRU resetting behavior described above. To
 *	preserve that KVM behavior, it passes NULL for @pkru if the xfeatures
 *	bit is not set.
 */
static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
			       const void __user *ubuf)
			       const void __user *ubuf, u32 *pkru)
{
	struct xregs_state *xsave = &fpstate->regs.xsave;
	unsigned int offset, size;
@@ -1250,6 +1278,20 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
		}
	}

	if (hdr.xfeatures & XFEATURE_MASK_PKRU) {
		struct pkru_state *xpkru;

		xpkru = __raw_xsave_addr(xsave, XFEATURE_PKRU);
		*pkru = xpkru->pkru;
	} else {
		/*
		 * KVM may pass NULL here to indicate that it does not need
		 * PKRU updated.
		 */
		if (pkru)
			*pkru = 0;
	}

	/*
	 * The state that came in from userspace was user-state only.
	 * Mask all the user states out of 'xfeatures':
@@ -1268,9 +1310,9 @@ static int copy_uabi_to_xstate(struct fpstate *fpstate, const void *kbuf,
 * Convert from a ptrace standard-format kernel buffer to kernel XSAVE[S]
 * format and copy to the target thread. Used by ptrace and KVM.
 */
int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf)
int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf, u32 *pkru)
{
	return copy_uabi_to_xstate(fpstate, kbuf, NULL);
	return copy_uabi_to_xstate(fpstate, kbuf, NULL, pkru);
}

/*
@@ -1278,10 +1320,10 @@ int copy_uabi_from_kernel_to_xstate(struct fpstate *fpstate, const void *kbuf)
 * XSAVE[S] format and copy to the target thread. This is called from the
 * sigreturn() and rt_sigreturn() system calls.
 */
int copy_sigframe_from_user_to_xstate(struct fpstate *fpstate,
int copy_sigframe_from_user_to_xstate(struct task_struct *tsk,
				      const void __user *ubuf)
{
	return copy_uabi_to_xstate(fpstate, NULL, ubuf);
	return copy_uabi_to_xstate(tsk->thread.fpu.fpstate, NULL, ubuf, &tsk->thread.pkru);
}

static bool validate_independent_components(u64 mask)
Loading