[PATCH] check put_user fail in do_signal when enable OABI_COMPACT

ye janboe janboe.ye at gmail.com
Wed Oct 21 23:35:22 EDT 2009


hi,
No one think that it is possible that put_user could fail in some
situation even if currently kernel subtract 12 from ARM_sp and cross
page bound?

Thanks

Janboe

2009/10/21 Janboe Ye <yuan-bo.ye at motorola.com>:
> Using OABI, do_signal need to copy restart_syscall to user stack.
> It is possible that put_user fail. This triggers flush_icache page
> fault and crash kernel.
>
> Signed-off-by: janboe <janboe.ye at gmail.com>
> ---
>  arch/arm/kernel/signal.c |   21 +++++++++++++--------
>  1 files changed, 13 insertions(+), 8 deletions(-)
>
> diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
> index f6bc5d4..2122d43 100644
> --- a/arch/arm/kernel/signal.c
> +++ b/arch/arm/kernel/signal.c
> @@ -626,6 +626,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
>        struct k_sigaction ka;
>        siginfo_t info;
>        int signr;
> +       int ret = 0;
>
>        /*
>         * We want the common case to go fast, which
> @@ -679,16 +680,20 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
>                                 */
>                                swival = swival - __NR_SYSCALL_BASE + __NR_OABI_SYSCALL_BASE;
>
> -                               put_user(regs->ARM_pc, &usp[0]);
> +                               ret |= put_user(regs->ARM_pc, &usp[0]);
>                                /* swi __NR_restart_syscall */
> -                               put_user(0xef000000 | swival, &usp[1]);
> +                               ret |= put_user(0xef000000 | swival, &usp[1]);
>                                /* ldr  pc, [sp], #12 */
> -                               put_user(0xe49df00c, &usp[2]);
> -
> -                               flush_icache_range((unsigned long)usp,
> -                                                  (unsigned long)(usp + 3));
> -
> -                               regs->ARM_pc = regs->ARM_sp + 4;
> +                               ret |= put_user(0xe49df00c, &usp[2]);
> +                               if (!ret) {
> +                                       flush_icache_range((unsigned long)usp,
> +                                               (unsigned long)(usp + 3));
> +
> +                                       regs->ARM_pc = regs->ARM_sp + 4;
> +                               } else {
> +                                       regs->ARM_sp += 12;
> +                                       force_sigsegv(0, current);
> +                               }
>  #endif
>                        }
>                }
> --
> 1.6.3.3
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>



More information about the linux-arm-kernel mailing list