| From 5a3ae7b314a2259b1188b22b392f5eba01e443ee Mon Sep 17 00:00:00 2001 |
| From: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| Date: Sun, 7 Apr 2019 21:06:16 +0200 |
| Subject: arm64/ftrace: fix inadvertent BUG() in trampoline check |
| |
| From: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| |
| commit 5a3ae7b314a2259b1188b22b392f5eba01e443ee upstream. |
| |
| The ftrace trampoline code (which deals with modules loaded out of |
| BL range of the core kernel) uses plt_entries_equal() to check whether |
| the per-module trampoline equals a zero buffer, to decide whether the |
| trampoline has already been initialized. |
| |
| This triggers a BUG() in the opcode manipulation code, since we end |
| up checking the ADRP offset of a 0x0 opcode, which is not an ADRP |
| instruction. |
| |
| So instead, add a helper to check whether a PLT is initialized, and |
| call that from the frace code. |
| |
| Cc: <stable@vger.kernel.org> # v5.0 |
| Fixes: bdb85cd1d206 ("arm64/module: switch to ADRP/ADD sequences for PLT entries") |
| Acked-by: Mark Rutland <mark.rutland@arm.com> |
| Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> |
| Signed-off-by: Will Deacon <will.deacon@arm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/arm64/include/asm/module.h | 5 +++++ |
| arch/arm64/kernel/ftrace.c | 3 +-- |
| 2 files changed, 6 insertions(+), 2 deletions(-) |
| |
| --- a/arch/arm64/include/asm/module.h |
| +++ b/arch/arm64/include/asm/module.h |
| @@ -73,4 +73,9 @@ static inline bool is_forbidden_offset_f |
| struct plt_entry get_plt_entry(u64 dst, void *pc); |
| bool plt_entries_equal(const struct plt_entry *a, const struct plt_entry *b); |
| |
| +static inline bool plt_entry_is_initialized(const struct plt_entry *e) |
| +{ |
| + return e->adrp || e->add || e->br; |
| +} |
| + |
| #endif /* __ASM_MODULE_H */ |
| --- a/arch/arm64/kernel/ftrace.c |
| +++ b/arch/arm64/kernel/ftrace.c |
| @@ -107,8 +107,7 @@ int ftrace_make_call(struct dyn_ftrace * |
| trampoline = get_plt_entry(addr, mod->arch.ftrace_trampoline); |
| if (!plt_entries_equal(mod->arch.ftrace_trampoline, |
| &trampoline)) { |
| - if (!plt_entries_equal(mod->arch.ftrace_trampoline, |
| - &(struct plt_entry){})) { |
| + if (plt_entry_is_initialized(mod->arch.ftrace_trampoline)) { |
| pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n"); |
| return -EINVAL; |
| } |