• Mark Rutland's avatar
    arm64: entry: avoid kprobe recursion · 024f4b2e
    Mark Rutland authored
    The cortex_a76_erratum_1463225_debug_handler() function is called when
    handling debug exceptions (and synchronous exceptions from BRK
    instructions), and so is called when a probed function executes. If the
    compiler does not inline cortex_a76_erratum_1463225_debug_handler(), it
    can be probed.
    
    If cortex_a76_erratum_1463225_debug_handler() is probed, any debug
    exception or software breakpoint exception will result in recursive
    exceptions leading to a stack overflow. This can be triggered with the
    ftrace multiple_probes selftest, and as per the example splat below.
    
    This is a regression caused by commit:
    
      6459b846 ("arm64: entry: consolidate Cortex-A76 erratum 1463225 workaround")
    
    ... which removed the NOKPROBE_SYMBOL() annotation associated with the
    function.
    
    My intent was that cortex_a76_erratum_1463225_debug_handler() would be
    inlined into its caller, el1_dbg(), which is marked noinstr and cannot
    be probed. Mark cortex_a76_erratum_1463225_debug_handler() as
    __always_inline to ensure this.
    
    Example splat prior to this patch (with recursive entries elided):
    
    | # echo p cortex_a76_erratum_1463225_debug_handler > /sys/kernel/debug/tracing/kprobe_events
    | # echo p do_el0_svc >> /sys/kernel/debug/tracing/kprobe_events
    | # echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable
    | Insufficient stack space to handle exception!
    | ESR: 0x0000000096000047 -- DABT (current EL)
    | FAR: 0xffff800009cefff0
    | Task stack:     [0xffff800009cf0000..0xffff800009cf4000]
    | IRQ stack:      [0xffff800008000000..0xffff800008004000]
    | Overflow stack: [0xffff00007fbc00f0..0xffff00007fbc10f0]
    | CPU: 0 PID: 145 Comm: sh Not tainted 6.0.0 #2
    | Hardware name: linux,dummy-virt (DT)
    | pstate: 604003c5 (nZCv DAIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
    | pc : arm64_enter_el1_dbg+0x4/0x20
    | lr : el1_dbg+0x24/0x5c
    | sp : ffff800009cf0000
    | x29: ffff800009cf0000 x28: ffff000002c74740 x27: 0000000000000000
    | x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000000
    | x23: 00000000604003c5 x22: ffff80000801745c x21: 0000aaaac95ac068
    | x20: 00000000f2000004 x19: ffff800009cf0040 x18: 0000000000000000
    | x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
    | x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000
    | x11: 0000000000000010 x10: ffff800008c87190 x9 : ffff800008ca00d0
    | x8 : 000000000000003c x7 : 0000000000000000 x6 : 0000000000000000
    | x5 : 0000000000000000 x4 : 0000000000000000 x3 : 00000000000043a4
    | x2 : 00000000f2000004 x1 : 00000000f2000004 x0 : ffff800009cf0040
    | Kernel panic - not syncing: kernel stack overflow
    | CPU: 0 PID: 145 Comm: sh Not tainted 6.0.0 #2
    | Hardware name: linux,dummy-virt (DT)
    | Call trace:
    |  dump_backtrace+0xe4/0x104
    |  show_stack+0x18/0x4c
    |  dump_stack_lvl+0x64/0x7c
    |  dump_stack+0x18/0x38
    |  panic+0x14c/0x338
    |  test_taint+0x0/0x2c
    |  panic_bad_stack+0x104/0x118
    |  handle_bad_stack+0x34/0x48
    |  __bad_stack+0x78/0x7c
    |  arm64_enter_el1_dbg+0x4/0x20
    |  el1h_64_sync_handler+0x40/0x98
    |  el1h_64_sync+0x64/0x68
    |  cortex_a76_erratum_1463225_debug_handler+0x0/0x34
    ...
    |  el1h_64_sync_handler+0x40/0x98
    |  el1h_64_sync+0x64/0x68
    |  cortex_a76_erratum_1463225_debug_handler+0x0/0x34
    ...
    |  el1h_64_sync_handler+0x40/0x98
    |  el1h_64_sync+0x64/0x68
    |  cortex_a76_erratum_1463225_debug_handler+0x0/0x34
    |  el1h_64_sync_handler+0x40/0x98
    |  el1h_64_sync+0x64/0x68
    |  do_el0_svc+0x0/0x28
    |  el0t_64_sync_handler+0x84/0xf0
    |  el0t_64_sync+0x18c/0x190
    | Kernel Offset: disabled
    | CPU features: 0x0080,00005021,19001080
    | Memory Limit: none
    | ---[ end Kernel panic - not syncing: kernel stack overflow ]---
    
    With this patch, cortex_a76_erratum_1463225_debug_handler() is inlined
    into el1_dbg(), and el1_dbg() cannot be probed:
    
    | # echo p cortex_a76_erratum_1463225_debug_handler > /sys/kernel/debug/tracing/kprobe_events
    | sh: write error: No such file or directory
    | # grep -w cortex_a76_erratum_1463225_debug_handler /proc/kallsyms | wc -l
    | 0
    | # echo p el1_dbg > /sys/kernel/debug/tracing/kprobe_events
    | sh: write error: Invalid argument
    | # grep -w el1_dbg /proc/kallsyms | wc -l
    | 1
    
    Fixes: 6459b846 ("arm64: entry: consolidate Cortex-A76 erratum 1463225 workaround")
    Cc: <stable@vger.kernel.org> # 5.12.x
    Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
    Cc: Will Deacon <will@kernel.org>
    Link: https://lore.kernel.org/r/20221017090157.2881408-1-mark.rutland@arm.comSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
    024f4b2e
entry-common.c 21.4 KB