Two more urgent FPU fixes:
- prevent unprivileged userspace from reinitializing supervisor states - Prepare init_fpstate, which is the buffer used when initializing FPU state, properly in case the skip-writing-state-components XSAVE* variants are used. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmDVltYACgkQEsHwGGHe VUqY9Q//c4MhJP2E15cqTWupxYk41k0UMjqPIwGmt6hRoDNKeFQm0xSgeOwe2mgk bbzGDJOfAi2Hxza2fw6No4wIiaB3sZIqK451aI1SM9HTDB/B/dMGBPXAp9qRlnbT kU/rDqQVqi7wlwunSunFoSLTwmQw0Lispmzwz9yirdQ+jVsnuTLWtPbUZM8RL/j8 XAhVwhDNc+Wuw0OBvRsyP5Mp6k9+2ic6z2ObIgSfgp4GeDG2F/+ZQ5W5ZeHVGQda 5QqKIdWCmAinzdz3N0iksthT3RJwLmYZ0K/qvLMrYNCvZiuUBdgrUn1Yrjo1c3lx W+SUMtgehlylfyBbyGn5zBbJtZJtflx+kYLHLzw58lWC+ekRfxqx2F+e7S4facXr Xn9IpnIAhru1/SAItSvScxXzjVW4DwZKO3tLr+/KsrRsTnS15pD6rx6OK88HHP/y ofjCeS0P8STb7/Gzzqj7c+7bJvSZo/h7jmF+H2y5tRhUXZogSoh1z/QGYpvcFrwP GOZeACREBv+D1PQNp/DN/ZiZHg6+csEg+3abtRaZSbdnfsCSpU/imXcX9GPco5vu XS+Gxle2aqvRmQNuJEbNr7YDfocZWWXmXnkPSKCtvqSgNdxjFjZ2v3TRTAgvHEoS Otpsv5Hk9g0FCep4oHG3zv8cb+Nk7Ycl2ZLZXQwE2Egane6U4K8= =uqQE -----END PGP SIGNATURE----- Merge tag 'x86_urgent_for_v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull x86 fixes from Borislav Petkov: "Two more urgent FPU fixes: - prevent unprivileged userspace from reinitializing supervisor states - prepare init_fpstate, which is the buffer used when initializing FPU state, properly in case the skip-writing-state-components XSAVE* variants are used" * tag 'x86_urgent_for_v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/fpu: Make init_fpstate correct with optimized XSAVE x86/fpu: Preserve supervisor states in sanitize_restored_user_xstate()
This commit is contained in:
commit
94ca94bbbb
@ -204,6 +204,14 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
|
||||
asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
|
||||
}
|
||||
|
||||
static inline void fxsave(struct fxregs_state *fx)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_X86_32))
|
||||
asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
|
||||
else
|
||||
asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
|
||||
}
|
||||
|
||||
/* These macros all use (%edi)/(%rdi) as the single memory argument. */
|
||||
#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27"
|
||||
#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37"
|
||||
@ -268,28 +276,6 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
|
||||
: "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
|
||||
: "memory")
|
||||
|
||||
/*
|
||||
* This function is called only during boot time when x86 caps are not set
|
||||
* up and alternative can not be used yet.
|
||||
*/
|
||||
static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
|
||||
{
|
||||
u64 mask = xfeatures_mask_all;
|
||||
u32 lmask = mask;
|
||||
u32 hmask = mask >> 32;
|
||||
int err;
|
||||
|
||||
WARN_ON(system_state != SYSTEM_BOOTING);
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_XSAVES))
|
||||
XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
|
||||
else
|
||||
XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
|
||||
|
||||
/* We should never fault when copying to a kernel buffer: */
|
||||
WARN_ON_FPU(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called only during boot time when x86 caps are not set
|
||||
* up and alternative can not be used yet.
|
||||
|
@ -221,28 +221,18 @@ sanitize_restored_user_xstate(union fpregs_state *state,
|
||||
|
||||
if (use_xsave()) {
|
||||
/*
|
||||
* Note: we don't need to zero the reserved bits in the
|
||||
* xstate_header here because we either didn't copy them at all,
|
||||
* or we checked earlier that they aren't set.
|
||||
* Clear all feature bits which are not set in
|
||||
* user_xfeatures and clear all extended features
|
||||
* for fx_only mode.
|
||||
*/
|
||||
u64 mask = fx_only ? XFEATURE_MASK_FPSSE : user_xfeatures;
|
||||
|
||||
/*
|
||||
* '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.
|
||||
* Supervisor state has to be preserved. The sigframe
|
||||
* restore can only modify user features, i.e. @mask
|
||||
* cannot contain them.
|
||||
*/
|
||||
if (fx_only)
|
||||
header->xfeatures = XFEATURE_MASK_FPSSE;
|
||||
else
|
||||
header->xfeatures &= user_xfeatures |
|
||||
xfeatures_mask_supervisor();
|
||||
header->xfeatures &= mask | xfeatures_mask_supervisor();
|
||||
}
|
||||
|
||||
if (use_fxsr()) {
|
||||
|
@ -440,6 +440,25 @@ static void __init print_xstate_offset_size(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* All supported features have either init state all zeros or are
|
||||
* handled in setup_init_fpu() individually. This is an explicit
|
||||
* feature list and does not use XFEATURE_MASK*SUPPORTED to catch
|
||||
* newly added supported features at build time and make people
|
||||
* actually look at the init state for the new feature.
|
||||
*/
|
||||
#define XFEATURES_INIT_FPSTATE_HANDLED \
|
||||
(XFEATURE_MASK_FP | \
|
||||
XFEATURE_MASK_SSE | \
|
||||
XFEATURE_MASK_YMM | \
|
||||
XFEATURE_MASK_OPMASK | \
|
||||
XFEATURE_MASK_ZMM_Hi256 | \
|
||||
XFEATURE_MASK_Hi16_ZMM | \
|
||||
XFEATURE_MASK_PKRU | \
|
||||
XFEATURE_MASK_BNDREGS | \
|
||||
XFEATURE_MASK_BNDCSR | \
|
||||
XFEATURE_MASK_PASID)
|
||||
|
||||
/*
|
||||
* setup the xstate image representing the init state
|
||||
*/
|
||||
@ -447,6 +466,10 @@ static void __init setup_init_fpu_buf(void)
|
||||
{
|
||||
static int on_boot_cpu __initdata = 1;
|
||||
|
||||
BUILD_BUG_ON((XFEATURE_MASK_USER_SUPPORTED |
|
||||
XFEATURE_MASK_SUPERVISOR_SUPPORTED) !=
|
||||
XFEATURES_INIT_FPSTATE_HANDLED);
|
||||
|
||||
WARN_ON_FPU(!on_boot_cpu);
|
||||
on_boot_cpu = 0;
|
||||
|
||||
@ -466,10 +489,22 @@ static void __init setup_init_fpu_buf(void)
|
||||
copy_kernel_to_xregs_booting(&init_fpstate.xsave);
|
||||
|
||||
/*
|
||||
* Dump the init state again. This is to identify the init state
|
||||
* of any feature which is not represented by all zero's.
|
||||
* All components are now in init state. Read the state back so
|
||||
* that init_fpstate contains all non-zero init state. This only
|
||||
* works with XSAVE, but not with XSAVEOPT and XSAVES because
|
||||
* those use the init optimization which skips writing data for
|
||||
* components in init state.
|
||||
*
|
||||
* XSAVE could be used, but that would require to reshuffle the
|
||||
* data when XSAVES is available because XSAVES uses xstate
|
||||
* compaction. But doing so is a pointless exercise because most
|
||||
* components have an all zeros init state except for the legacy
|
||||
* ones (FP and SSE). Those can be saved with FXSAVE into the
|
||||
* legacy area. Adding new features requires to ensure that init
|
||||
* state is all zeroes or if not to add the necessary handling
|
||||
* here.
|
||||
*/
|
||||
copy_xregs_to_kernel_booting(&init_fpstate.xsave);
|
||||
fxsave(&init_fpstate.fxsave);
|
||||
}
|
||||
|
||||
static int xfeature_uncompacted_offset(int xfeature_nr)
|
||||
|
Loading…
Reference in New Issue
Block a user