mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-14 14:34:28 +08:00
0fdb64c2a3
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>
48 lines
1.3 KiB
C
48 lines
1.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __ASM_EXTABLE_H
|
|
#define __ASM_EXTABLE_H
|
|
|
|
/*
|
|
* The exception table consists of pairs of relative offsets: the first
|
|
* is the relative offset to an instruction that is allowed to fault,
|
|
* and the second is the relative offset at which the program should
|
|
* continue. No registers are modified, so it is entirely up to the
|
|
* continuation code to figure out what to do.
|
|
*
|
|
* All the routines below use bits of fixup code that are out of line
|
|
* with the main instruction path. This means when everything is well,
|
|
* we don't even have to jump over them. Further, they do not intrude
|
|
* on our cache or tlb entries.
|
|
*/
|
|
|
|
struct exception_table_entry
|
|
{
|
|
int insn, fixup;
|
|
};
|
|
|
|
#define ARCH_HAS_RELATIVE_EXTABLE
|
|
|
|
static inline bool in_bpf_jit(struct pt_regs *regs)
|
|
{
|
|
if (!IS_ENABLED(CONFIG_BPF_JIT))
|
|
return false;
|
|
|
|
return regs->pc >= BPF_JIT_REGION_START &&
|
|
regs->pc < BPF_JIT_REGION_END;
|
|
}
|
|
|
|
#ifdef CONFIG_BPF_JIT
|
|
int arm64_bpf_fixup_exception(const struct exception_table_entry *ex,
|
|
struct pt_regs *regs);
|
|
#else /* !CONFIG_BPF_JIT */
|
|
static inline
|
|
int arm64_bpf_fixup_exception(const struct exception_table_entry *ex,
|
|
struct pt_regs *regs)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* !CONFIG_BPF_JIT */
|
|
|
|
extern int fixup_exception(struct pt_regs *regs);
|
|
#endif
|