Commit 94ca94bb authored by Linus Torvalds's avatar Linus Torvalds

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()
parents edf54d9d f9dfb5e3
...@@ -204,6 +204,14 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu) ...@@ -204,6 +204,14 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave)); 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. */ /* These macros all use (%edi)/(%rdi) as the single memory argument. */
#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27" #define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27"
#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37" #define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37"
...@@ -268,28 +276,6 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu) ...@@ -268,28 +276,6 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
: "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
: "memory") : "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 * This function is called only during boot time when x86 caps are not set
* up and alternative can not be used yet. * up and alternative can not be used yet.
......
...@@ -221,28 +221,18 @@ sanitize_restored_user_xstate(union fpregs_state *state, ...@@ -221,28 +221,18 @@ sanitize_restored_user_xstate(union fpregs_state *state,
if (use_xsave()) { if (use_xsave()) {
/* /*
* Note: we don't need to zero the reserved bits in the * Clear all feature bits which are not set in
* xstate_header here because we either didn't copy them at all, * user_xfeatures and clear all extended features
* or we checked earlier that they aren't set. * for fx_only mode.
*/ */
u64 mask = fx_only ? XFEATURE_MASK_FPSSE : user_xfeatures;
/* /*
* 'user_xfeatures' might have bits clear which are * Supervisor state has to be preserved. The sigframe
* set in header->xfeatures. This represents features that * restore can only modify user features, i.e. @mask
* were in init state prior to a signal delivery, and need * cannot contain them.
* 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 &= mask | xfeatures_mask_supervisor();
header->xfeatures = XFEATURE_MASK_FPSSE;
else
header->xfeatures &= user_xfeatures |
xfeatures_mask_supervisor();
} }
if (use_fxsr()) { if (use_fxsr()) {
......
...@@ -440,6 +440,25 @@ static void __init print_xstate_offset_size(void) ...@@ -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 * setup the xstate image representing the init state
*/ */
...@@ -447,6 +466,10 @@ static void __init setup_init_fpu_buf(void) ...@@ -447,6 +466,10 @@ static void __init setup_init_fpu_buf(void)
{ {
static int on_boot_cpu __initdata = 1; 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); WARN_ON_FPU(!on_boot_cpu);
on_boot_cpu = 0; on_boot_cpu = 0;
...@@ -466,10 +489,22 @@ static void __init setup_init_fpu_buf(void) ...@@ -466,10 +489,22 @@ static void __init setup_init_fpu_buf(void)
copy_kernel_to_xregs_booting(&init_fpstate.xsave); copy_kernel_to_xregs_booting(&init_fpstate.xsave);
/* /*
* Dump the init state again. This is to identify the init state * All components are now in init state. Read the state back so
* of any feature which is not represented by all zero's. * that init_fpstate contains all non-zero init state. This only
*/ * works with XSAVE, but not with XSAVEOPT and XSAVES because
copy_xregs_to_kernel_booting(&init_fpstate.xsave); * 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.
*/
fxsave(&init_fpstate.fxsave);
} }
static int xfeature_uncompacted_offset(int xfeature_nr) static int xfeature_uncompacted_offset(int xfeature_nr)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment