Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/dexcr: Move HASHCHK trap handler

Syzkaller reported a sleep in atomic context bug relating to the HASHCHK
handler logic:

BUG: sleeping function called from invalid context at arch/powerpc/kernel/traps.c:1518
in_atomic(): 0, irqs_disabled(): 1, non_block: 0, pid: 25040, name: syz-executor
preempt_count: 0, expected: 0
RCU nest depth: 0, expected: 0
no locks held by syz-executor/25040.
irq event stamp: 34
hardirqs last enabled at (33): [<c000000000048b38>] prep_irq_for_enabled_exit arch/powerpc/kernel/interrupt.c:56 [inline]
hardirqs last enabled at (33): [<c000000000048b38>] interrupt_exit_user_prepare_main+0x148/0x600 arch/powerpc/kernel/interrupt.c:230
hardirqs last disabled at (34): [<c00000000003e6a4>] interrupt_enter_prepare+0x144/0x4f0 arch/powerpc/include/asm/interrupt.h:176
softirqs last enabled at (0): [<c000000000281954>] copy_process+0x16e4/0x4750 kernel/fork.c:2436
softirqs last disabled at (0): [<0000000000000000>] 0x0
CPU: 15 PID: 25040 Comm: syz-executor Not tainted 6.5.0-rc5-00001-g3ccdff6bb06d #3
Hardware name: IBM,9105-22A POWER10 (raw) 0x800200 0xf000006 of:IBM,FW1040.00 (NL1040_021) hv:phyp pSeries
Call Trace:
[c0000000a8247ce0] [c00000000032b0e4] __might_resched+0x3b4/0x400 kernel/sched/core.c:10189
[c0000000a8247d80] [c0000000008c7dc8] __might_fault+0xa8/0x170 mm/memory.c:5853
[c0000000a8247dc0] [c00000000004160c] do_program_check+0x32c/0xb20 arch/powerpc/kernel/traps.c:1518
[c0000000a8247e50] [c000000000009b2c] program_check_common_virt+0x3bc/0x3c0

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 (get_user_instr() reaches
__get_user(), which calls might_fault() and triggers the bug message).

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 <bgray@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230915034604.45393-1-bgray@linux.ibm.com

authored by

Benjamin Gray and committed by
Michael Ellerman
c3f43096 6901a9f9

+36 -20
+36 -20
arch/powerpc/kernel/traps.c
··· 1512 1512 return; 1513 1513 } 1514 1514 1515 - if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE) && user_mode(regs)) { 1516 - ppc_inst_t insn; 1517 - 1518 - if (get_user_instr(insn, (void __user *)regs->nip)) { 1519 - _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); 1520 - return; 1521 - } 1522 - 1523 - if (ppc_inst_primary_opcode(insn) == 31 && 1524 - get_xop(ppc_inst_val(insn)) == OP_31_XOP_HASHCHK) { 1525 - _exception(SIGILL, regs, ILL_ILLOPN, regs->nip); 1526 - return; 1527 - } 1515 + /* User mode considers other cases after enabling IRQs */ 1516 + if (!user_mode(regs)) { 1517 + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); 1518 + return; 1528 1519 } 1529 - 1530 - _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); 1531 - return; 1532 1520 } 1533 1521 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM 1534 1522 if (reason & REASON_TM) { ··· 1549 1561 1550 1562 /* 1551 1563 * If we took the program check in the kernel skip down to sending a 1552 - * SIGILL. The subsequent cases all relate to emulating instructions 1553 - * which we should only do for userspace. We also do not want to enable 1554 - * interrupts for kernel faults because that might lead to further 1555 - * faults, and loose the context of the original exception. 1564 + * SIGILL. The subsequent cases all relate to user space, such as 1565 + * emulating instructions which we should only do for user space. We 1566 + * also do not want to enable interrupts for kernel faults because that 1567 + * might lead to further faults, and loose the context of the original 1568 + * exception. 1556 1569 */ 1557 1570 if (!user_mode(regs)) 1558 1571 goto sigill; 1559 1572 1560 1573 interrupt_cond_local_irq_enable(regs); 1574 + 1575 + /* 1576 + * (reason & REASON_TRAP) is mostly handled before enabling IRQs, 1577 + * except get_user_instr() can sleep so we cannot reliably inspect the 1578 + * current instruction in that context. Now that we know we are 1579 + * handling a user space trap and can sleep, we can check if the trap 1580 + * was a hashchk failure. 1581 + */ 1582 + if (reason & REASON_TRAP) { 1583 + if (cpu_has_feature(CPU_FTR_DEXCR_NPHIE)) { 1584 + ppc_inst_t insn; 1585 + 1586 + if (get_user_instr(insn, (void __user *)regs->nip)) { 1587 + _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); 1588 + return; 1589 + } 1590 + 1591 + if (ppc_inst_primary_opcode(insn) == 31 && 1592 + get_xop(ppc_inst_val(insn)) == OP_31_XOP_HASHCHK) { 1593 + _exception(SIGILL, regs, ILL_ILLOPN, regs->nip); 1594 + return; 1595 + } 1596 + } 1597 + 1598 + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); 1599 + return; 1600 + } 1561 1601 1562 1602 /* (reason & REASON_ILLEGAL) would be the obvious thing here, 1563 1603 * but there seems to be a hardware bug on the 405GP (RevD)