arm64: alternative: patch alternatives in the vDSO
authorJoey Gouly <joey.gouly@arm.com>
Tue, 30 Aug 2022 10:48:32 +0000 (11:48 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 9 Sep 2022 11:27:25 +0000 (12:27 +0100)
Make it possible to use alternatives in the vDSO, so that better
implementations can be used if possible.

Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Link: https://lore.kernel.org/r/20220830104833.34636-3-joey.gouly@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/vdso.h
arch/arm64/kernel/alternative.c
arch/arm64/kernel/vdso.c
arch/arm64/kernel/vdso/vdso.lds.S

index f99dcb94b438d21482bf7938542abf24f9dfdaa3..b4ae3210993273e8fd709b8f4d17a081bf39ff3d 100644 (file)
@@ -26,6 +26,9 @@
        (void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \
 })
 
+extern char vdso_start[], vdso_end[];
+extern char vdso32_start[], vdso32_end[];
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_VDSO_H */
index 9bcaa5eacf16cf1ccf76d64f1886f52c54caef77..a97775963f356a19be7e49d36b77b9fb981b71a5 100644 (file)
 
 #include <linux/init.h>
 #include <linux/cpu.h>
+#include <linux/elf.h>
 #include <asm/cacheflush.h>
 #include <asm/alternative.h>
 #include <asm/cpufeature.h>
 #include <asm/insn.h>
+#include <asm/module.h>
 #include <asm/sections.h>
+#include <asm/vdso.h>
 #include <linux/stop_machine.h>
 
 #define __ALT_PTR(a, f)                ((void *)&(a)->f + (a)->f)
@@ -192,6 +195,30 @@ static void __nocfi __apply_alternatives(struct alt_region *region, bool is_modu
        }
 }
 
+void apply_alternatives_vdso(void)
+{
+       struct alt_region region;
+       const struct elf64_hdr *hdr;
+       const struct elf64_shdr *shdr;
+       const struct elf64_shdr *alt;
+       DECLARE_BITMAP(all_capabilities, ARM64_NPATCHABLE);
+
+       bitmap_fill(all_capabilities, ARM64_NPATCHABLE);
+
+       hdr = (struct elf64_hdr *)vdso_start;
+       shdr = (void *)hdr + hdr->e_shoff;
+       alt = find_section(hdr, shdr, ".altinstructions");
+       if (!alt)
+               return;
+
+       region = (struct alt_region){
+               .begin  = (void *)hdr + alt->sh_offset,
+               .end    = (void *)hdr + alt->sh_offset + alt->sh_size,
+       };
+
+       __apply_alternatives(&region, false, &all_capabilities[0]);
+}
+
 /*
  * We might be patching the stop_machine state machine, so implement a
  * really simple polling protocol here.
@@ -225,6 +252,7 @@ static int __apply_alternatives_multi_stop(void *unused)
 
 void __init apply_alternatives_all(void)
 {
+       apply_alternatives_vdso();
        /* better not try code patching on a live SMP system */
        stop_machine(__apply_alternatives_multi_stop, NULL, cpu_online_mask);
 }
index a61fc4f989b37bfe57f05931926edb03146ab89e..ac93a2ee9c075e7c993011ef52edcc85e340ffbe 100644 (file)
@@ -29,9 +29,6 @@
 #include <asm/signal32.h>
 #include <asm/vdso.h>
 
-extern char vdso_start[], vdso_end[];
-extern char vdso32_start[], vdso32_end[];
-
 enum vdso_abi {
        VDSO_ABI_AA64,
        VDSO_ABI_AA32,
index e69fb4aaaf3ece102ba619cd2c6c403dc6f1b3cb..6028f1fe2d1cbf593af2e3b0973aff64c940a83d 100644 (file)
@@ -48,6 +48,13 @@ SECTIONS
        PROVIDE (_etext = .);
        PROVIDE (etext = .);
 
+       . = ALIGN(4);
+       .altinstructions : {
+               __alt_instructions = .;
+               *(.altinstructions)
+               __alt_instructions_end = .;
+       }
+
        .dynamic        : { *(.dynamic) }               :text   :dynamic
 
        .rela.dyn       : ALIGN(8) { *(.rela .rela*) }