On Wed, Dec 23, 2020 at 07:57:02AM -0800, Chang S. Bae wrote: > The xstate buffer is currently in-line with static size. To accommodatea "in-line" doesn't fit in this context, especially since "inline" is a keyword with another meaning. Please replace it with a better formulation in this patch. > dynamic user xstates, introduce variables to represent the maximum and > minimum buffer sizes. > > do_extra_xstate_size_checks() calculates the maximum xstate size and sanity > checks it with CPUID. It calculates the static in-line buffer size by > excluding the dynamic user states from the maximum xstate size. > > No functional change, until the kernel enables dynamic buffer support. > > Signed-off-by: Chang S. Bae <chang.seok.bae@xxxxxxxxx> > Reviewed-by: Len Brown <len.brown@xxxxxxxxx> > Cc: x86@xxxxxxxxxx > Cc: linux-kernel@xxxxxxxxxxxxxxx > Cc: kvm@xxxxxxxxxxxxxxx > --- > Changes from v2: > * Updated the changelog with task->fpu removed. (Boris Petkov) > * Renamed the in-line size variable. > * Updated some code comments. > --- > arch/x86/include/asm/processor.h | 10 +++---- > arch/x86/kernel/fpu/core.c | 6 ++--- > arch/x86/kernel/fpu/init.c | 36 ++++++++++++++++--------- > arch/x86/kernel/fpu/signal.c | 2 +- > arch/x86/kernel/fpu/xstate.c | 46 +++++++++++++++++++++----------- > arch/x86/kernel/process.c | 6 +++++ > arch/x86/kvm/x86.c | 2 +- > 7 files changed, 67 insertions(+), 41 deletions(-) > > diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h > index 82a08b585818..c9c608f8af91 100644 > --- a/arch/x86/include/asm/processor.h > +++ b/arch/x86/include/asm/processor.h > @@ -477,7 +477,8 @@ DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); > DECLARE_PER_CPU(struct irq_stack *, softirq_stack_ptr); > #endif /* X86_64 */ > > -extern unsigned int fpu_kernel_xstate_size; > +extern unsigned int fpu_kernel_xstate_min_size; > +extern unsigned int fpu_kernel_xstate_max_size; Is it time to group this into a struct so that all those settings go together instead in single variables? struct fpu_xstate { unsigned int min_size, max_size; unsigned int user_size; ... }; etc. > extern unsigned int fpu_user_xstate_size; > > struct perf_event; > @@ -545,12 +546,7 @@ struct thread_struct { > }; > > /* Whitelist the FPU state from the task_struct for hardened usercopy. */ > -static inline void arch_thread_struct_whitelist(unsigned long *offset, > - unsigned long *size) > -{ > - *offset = offsetof(struct thread_struct, fpu.state); > - *size = fpu_kernel_xstate_size; > -} > +extern void arch_thread_struct_whitelist(unsigned long *offset, unsigned long *size); What's that move for? > diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c > index 74e03e3bc20f..5dac97158030 100644 > --- a/arch/x86/kernel/fpu/init.c > +++ b/arch/x86/kernel/fpu/init.c > @@ -130,13 +130,20 @@ static void __init fpu__init_system_generic(void) > } > > /* > - * Size of the FPU context state. All tasks in the system use the > - * same context size, regardless of what portion they use. > - * This is inherent to the XSAVE architecture which puts all state > - * components into a single, continuous memory block: > + * Size of the minimally allocated FPU context state. All threads have this amount > + * of xstate buffer at minimum. > + * > + * This buffer is inherent to the XSAVE architecture which puts all state components > + * into a single, continuous memory block: > + */ > +unsigned int fpu_kernel_xstate_min_size; > +EXPORT_SYMBOL_GPL(fpu_kernel_xstate_min_size); > + > +/* > + * Size of the maximum FPU context state. When using the compacted format, the buffer > + * can be dynamically expanded to include some states up to this size. > */ > -unsigned int fpu_kernel_xstate_size; > -EXPORT_SYMBOL_GPL(fpu_kernel_xstate_size); > +unsigned int fpu_kernel_xstate_max_size; And since we're probably going to start querying different aspects about the buffer, instead of exporting all kinds of variables in the future, maybe this should be a single exported function called get_xstate_buffer_attr(typedef buffer_attr) which gives you what you wanna know about it... For example: get_xstate_buffer_attr(MIN_SIZE); get_xstate_buffer_attr(MAX_SIZE); ... > diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c > index 414a13427934..b6d2706b6886 100644 > --- a/arch/x86/kernel/fpu/signal.c > +++ b/arch/x86/kernel/fpu/signal.c > @@ -289,8 +289,8 @@ static int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only) > > static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) > { > + int state_size = fpu_kernel_xstate_min_size; > struct user_i387_ia32_struct *envp = NULL; > - int state_size = fpu_kernel_xstate_size; > int ia32_fxstate = (buf != buf_fx); > struct task_struct *tsk = current; > struct fpu *fpu = &tsk->thread.fpu; > diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c > index 6620d0a3caff..2012b17b1793 100644 > --- a/arch/x86/kernel/fpu/xstate.c > +++ b/arch/x86/kernel/fpu/xstate.c > @@ -627,13 +627,18 @@ static void check_xstate_against_struct(int nr) > */ <-- There's a comment over this function that might need adjustment. > static void do_extra_xstate_size_checks(void) > { > - int paranoid_xstate_size = FXSAVE_SIZE + XSAVE_HDR_SIZE; > + int paranoid_min_size = FXSAVE_SIZE + XSAVE_HDR_SIZE; > + int paranoid_max_size = FXSAVE_SIZE + XSAVE_HDR_SIZE; > int i; ... > @@ -744,27 +758,27 @@ static bool is_supported_xstate_size(unsigned int test_xstate_size) > static int __init init_xstate_size(void) > { > /* Recompute the context size for enabled features: */ > - unsigned int possible_xstate_size; > + unsigned int possible_max_xstate_size; > unsigned int xsave_size; > > xsave_size = get_xsave_size(); > > if (boot_cpu_has(X86_FEATURE_XSAVES)) using_compacted_format() FPU code needs to agree on one helper and not use both. :-\ > - possible_xstate_size = get_xsaves_size_no_dynamic(); > + possible_max_xstate_size = get_xsaves_size_no_dynamic(); > else > - possible_xstate_size = xsave_size; > - > - /* Ensure we have the space to store all enabled: */ > - if (!is_supported_xstate_size(possible_xstate_size)) > - return -EINVAL; > + possible_max_xstate_size = xsave_size; > > /* > * The size is OK, we are definitely going to use xsave, > * make it known to the world that we need more space. > */ > - fpu_kernel_xstate_size = possible_xstate_size; > + fpu_kernel_xstate_max_size = possible_max_xstate_size; > do_extra_xstate_size_checks(); > > + /* Ensure we have the supported in-line space: */ Who's "we"? > + if (!is_supported_xstate_size(fpu_kernel_xstate_min_size)) > + return -EINVAL; > + > /* > * User space is always in standard format. > */ -- Regards/Gruss, Boris. SUSE Software Solutions Germany GmbH, GF: Felix Imendörffer, HRB 36809, AG Nürnberg