@@ -277,38 +277,18 @@ static int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only)
277277 return frstor_from_user_sigframe (buf );
278278}
279279
280- static int __fpu__restore_sig (void __user * buf , void __user * buf_fx , int size )
280+ static int __fpu_restore_sig (void __user * buf , void __user * buf_fx ,
281+ bool ia32_fxstate )
281282{
282283 struct user_i387_ia32_struct * envp = NULL ;
283284 int state_size = fpu_kernel_xstate_size ;
284- int ia32_fxstate = (buf != buf_fx );
285285 struct task_struct * tsk = current ;
286286 struct fpu * fpu = & tsk -> thread .fpu ;
287287 struct user_i387_ia32_struct env ;
288288 u64 user_xfeatures = 0 ;
289289 int fx_only = 0 ;
290290 int ret = 0 ;
291291
292- ia32_fxstate &= (IS_ENABLED (CONFIG_X86_32 ) ||
293- IS_ENABLED (CONFIG_IA32_EMULATION ));
294-
295- if (!buf ) {
296- fpu__clear_user_states (fpu );
297- return 0 ;
298- }
299-
300- if (!access_ok (buf , size )) {
301- ret = - EACCES ;
302- goto out ;
303- }
304-
305- if (!static_cpu_has (X86_FEATURE_FPU )) {
306- ret = fpregs_soft_set (current , NULL , 0 ,
307- sizeof (struct user_i387_ia32_struct ),
308- NULL , buf );
309- goto out ;
310- }
311-
312292 if (use_xsave ()) {
313293 struct _fpx_sw_bytes fx_sw_user ;
314294 if (unlikely (check_for_xstate (buf_fx , buf_fx , & fx_sw_user ))) {
@@ -391,7 +371,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
391371 */
392372 ret = __copy_from_user (& env , buf , sizeof (env ));
393373 if (ret )
394- goto out ;
374+ return ret ;
395375 envp = & env ;
396376 }
397377
@@ -424,7 +404,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
424404
425405 ret = copy_sigframe_from_user_to_xstate (& fpu -> state .xsave , buf_fx );
426406 if (ret )
427- goto out ;
407+ return ret ;
428408
429409 sanitize_restored_user_xstate (& fpu -> state , envp , user_xfeatures ,
430410 fx_only );
@@ -442,10 +422,8 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
442422
443423 } else if (use_fxsr ()) {
444424 ret = __copy_from_user (& fpu -> state .fxsave , buf_fx , state_size );
445- if (ret ) {
446- ret = - EFAULT ;
447- goto out ;
448- }
425+ if (ret )
426+ return - EFAULT ;
449427
450428 sanitize_restored_user_xstate (& fpu -> state , envp , user_xfeatures ,
451429 fx_only );
@@ -462,7 +440,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
462440 } else {
463441 ret = __copy_from_user (& fpu -> state .fsave , buf_fx , state_size );
464442 if (ret )
465- goto out ;
443+ return ret ;
466444
467445 fpregs_lock ();
468446 ret = frstor_safe (& fpu -> state .fsave );
@@ -472,10 +450,6 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size)
472450 else
473451 fpregs_deactivate (fpu );
474452 fpregs_unlock ();
475-
476- out :
477- if (ret )
478- fpu__clear_user_states (fpu );
479453 return ret ;
480454}
481455
@@ -490,15 +464,47 @@ static inline int xstate_sigframe_size(void)
490464 */
491465int fpu__restore_sig (void __user * buf , int ia32_frame )
492466{
467+ unsigned int size = xstate_sigframe_size ();
468+ struct fpu * fpu = & current -> thread .fpu ;
493469 void __user * buf_fx = buf ;
494- int size = xstate_sigframe_size ();
470+ bool ia32_fxstate = false;
471+ int ret ;
472+
473+ if (unlikely (!buf )) {
474+ fpu__clear_user_states (fpu );
475+ return 0 ;
476+ }
495477
478+ ia32_frame &= (IS_ENABLED (CONFIG_X86_32 ) ||
479+ IS_ENABLED (CONFIG_IA32_EMULATION ));
480+
481+ /*
482+ * Only FXSR enabled systems need the FX state quirk.
483+ * FRSTOR does not need it and can use the fast path.
484+ */
496485 if (ia32_frame && use_fxsr ()) {
497486 buf_fx = buf + sizeof (struct fregs_state );
498487 size += sizeof (struct fregs_state );
488+ ia32_fxstate = true;
499489 }
500490
501- return __fpu__restore_sig (buf , buf_fx , size );
491+ if (!access_ok (buf , size )) {
492+ ret = - EACCES ;
493+ goto out ;
494+ }
495+
496+ if (!IS_ENABLED (CONFIG_X86_64 ) && !cpu_feature_enabled (X86_FEATURE_FPU )) {
497+ ret = fpregs_soft_set (current , NULL , 0 ,
498+ sizeof (struct user_i387_ia32_struct ),
499+ NULL , buf );
500+ } else {
501+ ret = __fpu_restore_sig (buf , buf_fx , ia32_fxstate );
502+ }
503+
504+ out :
505+ if (unlikely (ret ))
506+ fpu__clear_user_states (fpu );
507+ return ret ;
502508}
503509
504510unsigned long
0 commit comments