Skip to content

Commit 0fdb64c

Browse files
committed
arm64: Improve diagnostics when trapping BRK with FAULT_BRK_IMM
When generating instructions at runtime, for example due to kernel text patching or the BPF JIT, we can emit a trapping BRK instruction if we are asked to encode an invalid instruction such as an out-of-range] branch. This is indicative of a bug in the caller, and will result in a crash on executing the generated code. Unfortunately, the message from the crash is really unhelpful, and mumbles something about ptrace: | Unexpected kernel BRK exception at EL1 | Internal error: ptrace BRK handler: f2000100 [#1] SMP We can do better than this. Install a break handler for FAULT_BRK_IMM, which is the immediate used to encode the "I've been asked to generate an invalid instruction" error, and triage the faulting PC to determine whether or not the failure occurred in the BPF JIT. Link: https://lore.kernel.org/r/20200915141707.GB26439@willie-the-truck Reported-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Signed-off-by: Will Deacon <will@kernel.org>
1 parent f75aef3 commit 0fdb64c

4 files changed

Lines changed: 28 additions & 4 deletions

File tree

arch/arm64/include/asm/extable.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ struct exception_table_entry
2222

2323
#define ARCH_HAS_RELATIVE_EXTABLE
2424

25+
static inline bool in_bpf_jit(struct pt_regs *regs)
26+
{
27+
if (!IS_ENABLED(CONFIG_BPF_JIT))
28+
return false;
29+
30+
return regs->pc >= BPF_JIT_REGION_START &&
31+
regs->pc < BPF_JIT_REGION_END;
32+
}
33+
2534
#ifdef CONFIG_BPF_JIT
2635
int arm64_bpf_fixup_exception(const struct exception_table_entry *ex,
2736
struct pt_regs *regs);

arch/arm64/kernel/debug-monitors.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ void __init debug_traps_init(void)
384384
hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
385385
TRAP_TRACE, "single-step handler");
386386
hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,
387-
TRAP_BRKPT, "ptrace BRK handler");
387+
TRAP_BRKPT, "BRK handler");
388388
}
389389

390390
/* Re-enable single step for syscall restarting. */

arch/arm64/kernel/traps.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <asm/daifflags.h>
3535
#include <asm/debug-monitors.h>
3636
#include <asm/esr.h>
37+
#include <asm/extable.h>
3738
#include <asm/insn.h>
3839
#include <asm/kprobes.h>
3940
#include <asm/traps.h>
@@ -994,6 +995,21 @@ static struct break_hook bug_break_hook = {
994995
.imm = BUG_BRK_IMM,
995996
};
996997

998+
static int reserved_fault_handler(struct pt_regs *regs, unsigned int esr)
999+
{
1000+
pr_err("%s generated an invalid instruction at %pS!\n",
1001+
in_bpf_jit(regs) ? "BPF JIT" : "Kernel text patching",
1002+
(void *)instruction_pointer(regs));
1003+
1004+
/* We cannot handle this */
1005+
return DBG_HOOK_ERROR;
1006+
}
1007+
1008+
static struct break_hook fault_break_hook = {
1009+
.fn = reserved_fault_handler,
1010+
.imm = FAULT_BRK_IMM,
1011+
};
1012+
9971013
#ifdef CONFIG_KASAN_SW_TAGS
9981014

9991015
#define KASAN_ESR_RECOVER 0x20
@@ -1059,6 +1075,7 @@ int __init early_brk64(unsigned long addr, unsigned int esr,
10591075
void __init trap_init(void)
10601076
{
10611077
register_kernel_break_hook(&bug_break_hook);
1078+
register_kernel_break_hook(&fault_break_hook);
10621079
#ifdef CONFIG_KASAN_SW_TAGS
10631080
register_kernel_break_hook(&kasan_break_hook);
10641081
#endif

arch/arm64/mm/extable.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ int fixup_exception(struct pt_regs *regs)
1414
if (!fixup)
1515
return 0;
1616

17-
if (IS_ENABLED(CONFIG_BPF_JIT) &&
18-
regs->pc >= BPF_JIT_REGION_START &&
19-
regs->pc < BPF_JIT_REGION_END)
17+
if (in_bpf_jit(regs))
2018
return arm64_bpf_fixup_exception(fixup, regs);
2119

2220
regs->pc = (unsigned long)&fixup->fixup + fixup->fixup;

0 commit comments

Comments
 (0)