| From 521647b4a07fef9cfd433754ad4488e25a56e364 Mon Sep 17 00:00:00 2001 |
| From: Ard Biesheuvel <ardb@kernel.org> |
| Date: Thu, 9 Jul 2020 15:59:53 +0300 |
| Subject: [PATCH] arm64/alternatives: don't patch up internal branches |
| |
| commit 5679b28142193a62f6af93249c0477be9f0c669b upstream. |
| |
| Commit f7b93d42945c ("arm64/alternatives: use subsections for replacement |
| sequences") moved the alternatives replacement sequences into subsections, |
| in order to keep the as close as possible to the code that they replace. |
| |
| Unfortunately, this broke the logic in branch_insn_requires_update, |
| which assumed that any branch into kernel executable code was a branch |
| that required updating, which is no longer the case now that the code |
| sequences that are patched in are in the same section as the patch site |
| itself. |
| |
| So the only way to discriminate branches that require updating and ones |
| that don't is to check whether the branch targets the replacement sequence |
| itself, and so we can drop the call to kernel_text_address() entirely. |
| |
| Fixes: f7b93d42945c ("arm64/alternatives: use subsections for replacement sequences") |
| Reported-by: Alexandru Elisei <alexandru.elisei@arm.com> |
| Signed-off-by: Ard Biesheuvel <ardb@kernel.org> |
| Tested-by: Alexandru Elisei <alexandru.elisei@arm.com> |
| Link: https://lore.kernel.org/r/20200709125953.30918-1-ardb@kernel.org |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c |
| index d1757ef1b1e7..73039949b5ce 100644 |
| --- a/arch/arm64/kernel/alternative.c |
| +++ b/arch/arm64/kernel/alternative.c |
| @@ -43,20 +43,8 @@ bool alternative_is_applied(u16 cpufeature) |
| */ |
| static bool branch_insn_requires_update(struct alt_instr *alt, unsigned long pc) |
| { |
| - unsigned long replptr; |
| - |
| - if (kernel_text_address(pc)) |
| - return true; |
| - |
| - replptr = (unsigned long)ALT_REPL_PTR(alt); |
| - if (pc >= replptr && pc <= (replptr + alt->alt_len)) |
| - return false; |
| - |
| - /* |
| - * Branching into *another* alternate sequence is doomed, and |
| - * we're not even trying to fix it up. |
| - */ |
| - BUG(); |
| + unsigned long replptr = (unsigned long)ALT_REPL_PTR(alt); |
| + return !(pc >= replptr && pc <= (replptr + alt->alt_len)); |
| } |
| |
| #define align_down(x, a) ((unsigned long)(x) & ~(((unsigned long)(a)) - 1)) |
| -- |
| 2.27.0 |
| |