summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2018-07-09 05:13:36 -0400
committerRussell King <rmk+kernel@armlinux.org.uk>2018-08-02 12:41:37 -0400
commit42019fc50dfadb219f9e6ddf4c354f3837057d80 (patch)
tree7c2173ccdbd6aec6c1bf37434df28a408f986384
parentc32cd419d6650e42b9cdebb83c672ec945e6bd7e (diff)
ARM: vfp: use __copy_from_user() when restoring VFP state
__get_user_error() is used as a fast accessor to make copying structure members in the signal handling path as efficient as possible. However, with software PAN and the recent Spectre variant 1, the efficiency is reduced as these are no longer fast accessors. In the case of software PAN, it has to switch the domain register around each access, and with Spectre variant 1, it would have to repeat the access_ok() check for each access. Use __copy_from_user() rather than __get_user_err() for individual members when restoring VFP state. Acked-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--arch/arm/include/asm/thread_info.h4
-rw-r--r--arch/arm/kernel/signal.c20
-rw-r--r--arch/arm/vfp/vfpmodule.c17
3 files changed, 17 insertions, 24 deletions
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index e71cc35de163..9b37b6ab27fe 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -123,8 +123,8 @@ struct user_vfp_exc;
123 123
124extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *, 124extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *,
125 struct user_vfp_exc __user *); 125 struct user_vfp_exc __user *);
126extern int vfp_restore_user_hwstate(struct user_vfp __user *, 126extern int vfp_restore_user_hwstate(struct user_vfp *,
127 struct user_vfp_exc __user *); 127 struct user_vfp_exc *);
128#endif 128#endif
129 129
130/* 130/*
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 0ae74207e43e..db62c51250ad 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -150,22 +150,18 @@ static int preserve_vfp_context(struct vfp_sigframe __user *frame)
150 150
151static int restore_vfp_context(char __user **auxp) 151static int restore_vfp_context(char __user **auxp)
152{ 152{
153 struct vfp_sigframe __user *frame = 153 struct vfp_sigframe frame;
154 (struct vfp_sigframe __user *)*auxp; 154 int err;
155 unsigned long magic;
156 unsigned long size;
157 int err = 0;
158
159 __get_user_error(magic, &frame->magic, err);
160 __get_user_error(size, &frame->size, err);
161 155
156 err = __copy_from_user(&frame, *auxp, sizeof(frame));
162 if (err) 157 if (err)
163 return -EFAULT; 158 return err;
164 if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) 159
160 if (frame.magic != VFP_MAGIC || frame.size != VFP_STORAGE_SIZE)
165 return -EINVAL; 161 return -EINVAL;
166 162
167 *auxp += size; 163 *auxp += sizeof(frame);
168 return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc); 164 return vfp_restore_user_hwstate(&frame.ufp, &frame.ufp_exc);
169} 165}
170 166
171#endif 167#endif
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 4c375e11ae95..859d50ea17d3 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -597,13 +597,11 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
597} 597}
598 598
599/* Sanitise and restore the current VFP state from the provided structures. */ 599/* Sanitise and restore the current VFP state from the provided structures. */
600int vfp_restore_user_hwstate(struct user_vfp __user *ufp, 600int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc)
601 struct user_vfp_exc __user *ufp_exc)
602{ 601{
603 struct thread_info *thread = current_thread_info(); 602 struct thread_info *thread = current_thread_info();
604 struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; 603 struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
605 unsigned long fpexc; 604 unsigned long fpexc;
606 int err = 0;
607 605
608 /* Disable VFP to avoid corrupting the new thread state. */ 606 /* Disable VFP to avoid corrupting the new thread state. */
609 vfp_flush_hwstate(thread); 607 vfp_flush_hwstate(thread);
@@ -612,17 +610,16 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
612 * Copy the floating point registers. There can be unused 610 * Copy the floating point registers. There can be unused
613 * registers see asm/hwcap.h for details. 611 * registers see asm/hwcap.h for details.
614 */ 612 */
615 err |= __copy_from_user(&hwstate->fpregs, &ufp->fpregs, 613 memcpy(&hwstate->fpregs, &ufp->fpregs, sizeof(hwstate->fpregs));
616 sizeof(hwstate->fpregs));
617 /* 614 /*
618 * Copy the status and control register. 615 * Copy the status and control register.
619 */ 616 */
620 __get_user_error(hwstate->fpscr, &ufp->fpscr, err); 617 hwstate->fpscr = ufp->fpscr;
621 618
622 /* 619 /*
623 * Sanitise and restore the exception registers. 620 * Sanitise and restore the exception registers.
624 */ 621 */
625 __get_user_error(fpexc, &ufp_exc->fpexc, err); 622 fpexc = ufp_exc->fpexc;
626 623
627 /* Ensure the VFP is enabled. */ 624 /* Ensure the VFP is enabled. */
628 fpexc |= FPEXC_EN; 625 fpexc |= FPEXC_EN;
@@ -631,10 +628,10 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
631 fpexc &= ~(FPEXC_EX | FPEXC_FP2V); 628 fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
632 hwstate->fpexc = fpexc; 629 hwstate->fpexc = fpexc;
633 630
634 __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); 631 hwstate->fpinst = ufp_exc->fpinst;
635 __get_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err); 632 hwstate->fpinst2 = ufp_exc->fpinst2;
636 633
637 return err ? -EFAULT : 0; 634 return 0;
638} 635}
639 636
640/* 637/*