| From foo@baz Wed Nov 21 19:20:53 CET 2018 |
| From: David Long <dave.long@linaro.org> |
| Date: Wed, 7 Nov 2018 11:43:57 -0500 |
| Subject: ARM: signal: copy registers using __copy_from_user() |
| To: stable@vger.kernel.org, Russell King - ARM Linux <linux@armlinux.org.uk>, Florian Fainelli <f.fainelli@gmail.com>, Tony Lindgren <tony@atomide.com>, Marc Zyngier <marc.zyngier@arm.com>, Mark Rutland <mark.rutland@arm.com> |
| Cc: Greg KH <gregkh@linuxfoundation.org>, Mark Brown <broonie@kernel.org> |
| Message-ID: <20181107164402.9380-20-dave.long@linaro.org> |
| |
| From: Russell King <rmk+kernel@armlinux.org.uk> |
| |
| Commit c32cd419d6650e42b9cdebb83c672ec945e6bd7e upstream. |
| |
| __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. |
| |
| It becomes much more efficient to use __copy_from_user() instead, so |
| let's use this for the ARM integer registers. |
| |
| Acked-by: Mark Rutland <mark.rutland@arm.com> |
| Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| Signed-off-by: David A. Long <dave.long@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/arm/kernel/signal.c | 38 +++++++++++++++++++++----------------- |
| 1 file changed, 21 insertions(+), 17 deletions(-) |
| |
| --- a/arch/arm/kernel/signal.c |
| +++ b/arch/arm/kernel/signal.c |
| @@ -141,6 +141,7 @@ struct rt_sigframe { |
| |
| static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) |
| { |
| + struct sigcontext context; |
| struct aux_sigframe __user *aux; |
| sigset_t set; |
| int err; |
| @@ -149,23 +150,26 @@ static int restore_sigframe(struct pt_re |
| if (err == 0) |
| set_current_blocked(&set); |
| |
| - __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); |
| - __get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); |
| - __get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); |
| - __get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); |
| - __get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); |
| - __get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); |
| - __get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); |
| - __get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); |
| - __get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); |
| - __get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); |
| - __get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); |
| - __get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); |
| - __get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); |
| - __get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); |
| - __get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); |
| - __get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); |
| - __get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); |
| + err |= __copy_from_user(&context, &sf->uc.uc_mcontext, sizeof(context)); |
| + if (err == 0) { |
| + regs->ARM_r0 = context.arm_r0; |
| + regs->ARM_r1 = context.arm_r1; |
| + regs->ARM_r2 = context.arm_r2; |
| + regs->ARM_r3 = context.arm_r3; |
| + regs->ARM_r4 = context.arm_r4; |
| + regs->ARM_r5 = context.arm_r5; |
| + regs->ARM_r6 = context.arm_r6; |
| + regs->ARM_r7 = context.arm_r7; |
| + regs->ARM_r8 = context.arm_r8; |
| + regs->ARM_r9 = context.arm_r9; |
| + regs->ARM_r10 = context.arm_r10; |
| + regs->ARM_fp = context.arm_fp; |
| + regs->ARM_ip = context.arm_ip; |
| + regs->ARM_sp = context.arm_sp; |
| + regs->ARM_lr = context.arm_lr; |
| + regs->ARM_pc = context.arm_pc; |
| + regs->ARM_cpsr = context.arm_cpsr; |
| + } |
| |
| err |= !valid_user_regs(regs); |
| |