Benjamin Gray <bg...@linux.ibm.com> writes:
> To determine if a trap was caused by a HASHCHK instruction, we inspect
> the user instruction that triggered the trap. However this may sleep
> if the page needs to be faulted in.

It would be good to include the output from the might_sleep() check that
failed.

And I think this was found by syzkaller? If so we should say so.

cheers

> Move the HASHCHK handler logic to after we allow IRQs, which is fine
> because we are only interested in HASHCHK if it's a user space trap.
>
> Fixes: 5bcba4e6c13f ("powerpc/dexcr: Handle hashchk exception")
> Signed-off-by: Benjamin Gray <bg...@linux.ibm.com>
> ---
>  arch/powerpc/kernel/traps.c | 56 ++++++++++++++++++++++++-------------
>  1 file changed, 36 insertions(+), 20 deletions(-)
>
> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> index f5ce282dc4b8..32b5e841ea97 100644
> --- a/arch/powerpc/kernel/traps.c
> +++ b/arch/powerpc/kernel/traps.c
> @@ -1512,23 +1512,11 @@ static void do_program_check(struct pt_regs *regs)
>                       return;
>               }
>  
> -             if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE) && user_mode(regs)) {
> -                     ppc_inst_t insn;
> -
> -                     if (get_user_instr(insn, (void __user *)regs->nip)) {
> -                             _exception(SIGSEGV, regs, SEGV_MAPERR, 
> regs->nip);
> -                             return;
> -                     }
> -
> -                     if (ppc_inst_primary_opcode(insn) == 31 &&
> -                         get_xop(ppc_inst_val(insn)) == OP_31_XOP_HASHCHK) {
> -                             _exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
> -                             return;
> -                     }
> +             /* User mode considers other cases after enabling IRQs */
> +             if (!user_mode(regs)) {
> +                     _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
> +                     return;
>               }
> -
> -             _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
> -             return;
>       }
>  #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
>       if (reason & REASON_TM) {
> @@ -1561,16 +1549,44 @@ static void do_program_check(struct pt_regs *regs)
>  
>       /*
>        * If we took the program check in the kernel skip down to sending a
> -      * SIGILL. The subsequent cases all relate to emulating instructions
> -      * which we should only do for userspace. We also do not want to enable
> -      * interrupts for kernel faults because that might lead to further
> -      * faults, and loose the context of the original exception.
> +      * SIGILL. The subsequent cases all relate to user space, such as
> +      * emulating instructions which we should only do for user space. We
> +      * also do not want to enable interrupts for kernel faults because that
> +      * might lead to further faults, and loose the context of the original
> +      * exception.
>        */
>       if (!user_mode(regs))
>               goto sigill;
>  
>       interrupt_cond_local_irq_enable(regs);
>  
> +     /*
> +      * (reason & REASON_TRAP) is mostly handled before enabling IRQs,
> +      * except get_user_instr() can sleep so we cannot reliably inspect the
> +      * current instruction in that context. Now that we know we are
> +      * handling a user space trap and can sleep, we can check if the trap
> +      * was a hashchk failure.
> +      */
> +     if (reason & REASON_TRAP) {
> +             if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE)) {
> +                     ppc_inst_t insn;
> +
> +                     if (get_user_instr(insn, (void __user *)regs->nip)) {
> +                             _exception(SIGSEGV, regs, SEGV_MAPERR, 
> regs->nip);
> +                             return;
> +                     }
> +
> +                     if (ppc_inst_primary_opcode(insn) == 31 &&
> +                         get_xop(ppc_inst_val(insn)) == OP_31_XOP_HASHCHK) {
> +                             _exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
> +                             return;
> +                     }
> +             }
> +
> +             _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
> +             return;
> +     }
> +
>       /* (reason & REASON_ILLEGAL) would be the obvious thing here,
>        * but there seems to be a hardware bug on the 405GP (RevD)
>        * that means ESR is sometimes set incorrectly - either to
> -- 
> 2.41.0

Reply via email to