Skip to content

Commit 94ca94b

Browse files
committed
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()
2 parents edf54d9 + f9dfb5e commit 94ca94b

File tree

3 files changed

+54
-43
lines changed

3 files changed

+54
-43
lines changed

arch/x86/include/asm/fpu/internal.h

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
204204
asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave));
205205
}
206206

207+
static inline void fxsave(struct fxregs_state *fx)
208+
{
209+
if (IS_ENABLED(CONFIG_X86_32))
210+
asm volatile( "fxsave %[fx]" : [fx] "=m" (*fx));
211+
else
212+
asm volatile("fxsaveq %[fx]" : [fx] "=m" (*fx));
213+
}
214+
207215
/* These macros all use (%edi)/(%rdi) as the single memory argument. */
208216
#define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27"
209217
#define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37"
@@ -268,28 +276,6 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
268276
: "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
269277
: "memory")
270278

271-
/*
272-
* This function is called only during boot time when x86 caps are not set
273-
* up and alternative can not be used yet.
274-
*/
275-
static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
276-
{
277-
u64 mask = xfeatures_mask_all;
278-
u32 lmask = mask;
279-
u32 hmask = mask >> 32;
280-
int err;
281-
282-
WARN_ON(system_state != SYSTEM_BOOTING);
283-
284-
if (boot_cpu_has(X86_FEATURE_XSAVES))
285-
XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
286-
else
287-
XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
288-
289-
/* We should never fault when copying to a kernel buffer: */
290-
WARN_ON_FPU(err);
291-
}
292-
293279
/*
294280
* This function is called only during boot time when x86 caps are not set
295281
* up and alternative can not be used yet.

arch/x86/kernel/fpu/signal.c

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -221,28 +221,18 @@ sanitize_restored_user_xstate(union fpregs_state *state,
221221

222222
if (use_xsave()) {
223223
/*
224-
* Note: we don't need to zero the reserved bits in the
225-
* xstate_header here because we either didn't copy them at all,
226-
* or we checked earlier that they aren't set.
224+
* Clear all feature bits which are not set in
225+
* user_xfeatures and clear all extended features
226+
* for fx_only mode.
227227
*/
228+
u64 mask = fx_only ? XFEATURE_MASK_FPSSE : user_xfeatures;
228229

229230
/*
230-
* 'user_xfeatures' might have bits clear which are
231-
* set in header->xfeatures. This represents features that
232-
* were in init state prior to a signal delivery, and need
233-
* to be reset back to the init state. Clear any user
234-
* feature bits which are set in the kernel buffer to get
235-
* them back to the init state.
236-
*
237-
* Supervisor state is unchanged by input from userspace.
238-
* Ensure supervisor state bits stay set and supervisor
239-
* state is not modified.
231+
* Supervisor state has to be preserved. The sigframe
232+
* restore can only modify user features, i.e. @mask
233+
* cannot contain them.
240234
*/
241-
if (fx_only)
242-
header->xfeatures = XFEATURE_MASK_FPSSE;
243-
else
244-
header->xfeatures &= user_xfeatures |
245-
xfeatures_mask_supervisor();
235+
header->xfeatures &= mask | xfeatures_mask_supervisor();
246236
}
247237

248238
if (use_fxsr()) {

arch/x86/kernel/fpu/xstate.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,13 +440,36 @@ static void __init print_xstate_offset_size(void)
440440
}
441441
}
442442

443+
/*
444+
* All supported features have either init state all zeros or are
445+
* handled in setup_init_fpu() individually. This is an explicit
446+
* feature list and does not use XFEATURE_MASK*SUPPORTED to catch
447+
* newly added supported features at build time and make people
448+
* actually look at the init state for the new feature.
449+
*/
450+
#define XFEATURES_INIT_FPSTATE_HANDLED \
451+
(XFEATURE_MASK_FP | \
452+
XFEATURE_MASK_SSE | \
453+
XFEATURE_MASK_YMM | \
454+
XFEATURE_MASK_OPMASK | \
455+
XFEATURE_MASK_ZMM_Hi256 | \
456+
XFEATURE_MASK_Hi16_ZMM | \
457+
XFEATURE_MASK_PKRU | \
458+
XFEATURE_MASK_BNDREGS | \
459+
XFEATURE_MASK_BNDCSR | \
460+
XFEATURE_MASK_PASID)
461+
443462
/*
444463
* setup the xstate image representing the init state
445464
*/
446465
static void __init setup_init_fpu_buf(void)
447466
{
448467
static int on_boot_cpu __initdata = 1;
449468

469+
BUILD_BUG_ON((XFEATURE_MASK_USER_SUPPORTED |
470+
XFEATURE_MASK_SUPERVISOR_SUPPORTED) !=
471+
XFEATURES_INIT_FPSTATE_HANDLED);
472+
450473
WARN_ON_FPU(!on_boot_cpu);
451474
on_boot_cpu = 0;
452475

@@ -466,10 +489,22 @@ static void __init setup_init_fpu_buf(void)
466489
copy_kernel_to_xregs_booting(&init_fpstate.xsave);
467490

468491
/*
469-
* Dump the init state again. This is to identify the init state
470-
* of any feature which is not represented by all zero's.
492+
* All components are now in init state. Read the state back so
493+
* that init_fpstate contains all non-zero init state. This only
494+
* works with XSAVE, but not with XSAVEOPT and XSAVES because
495+
* those use the init optimization which skips writing data for
496+
* components in init state.
497+
*
498+
* XSAVE could be used, but that would require to reshuffle the
499+
* data when XSAVES is available because XSAVES uses xstate
500+
* compaction. But doing so is a pointless exercise because most
501+
* components have an all zeros init state except for the legacy
502+
* ones (FP and SSE). Those can be saved with FXSAVE into the
503+
* legacy area. Adding new features requires to ensure that init
504+
* state is all zeroes or if not to add the necessary handling
505+
* here.
471506
*/
472-
copy_xregs_to_kernel_booting(&init_fpstate.xsave);
507+
fxsave(&init_fpstate.fxsave);
473508
}
474509

475510
static int xfeature_uncompacted_offset(int xfeature_nr)

0 commit comments

Comments
 (0)