arm64: module: mandate MODULE_PLTS
authorMark Rutland <mark.rutland@arm.com>
Tue, 30 May 2023 11:03:27 +0000 (12:03 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Tue, 6 Jun 2023 16:39:05 +0000 (17:39 +0100)
Contemporary kernels and modules can be relatively large, especially
when common debug options are enabled. Using GCC 12.1.0, a v6.3-rc7
defconfig kernel is ~38M, and with PROVE_LOCKING + KASAN_INLINE enabled
this expands to ~117M. Shanker reports [1] that the NVIDIA GPU driver
alone can consume 110M of module space in some configurations.

Both KASLR and ARM64_ERRATUM_843419 select MODULE_PLTS, so anyone
wanting a kernel to have KASLR or run on Cortex-A53 will have
MODULE_PLTS selected. This is the case in defconfig and distribution
kernels (e.g. Debian, Android, etc).

Practically speaking, this means we're very likely to need MODULE_PLTS
and while it's almost guaranteed that MODULE_PLTS will be selected, it
is possible to disable support, and we have to maintain some awkward
special cases for such unusual configurations.

This patch removes the MODULE_PLTS config option, with the support code
always enabled if MODULES is selected. This results in a slight
simplification, and will allow for further improvement in subsequent
patches.

For any config which currently selects MODULE_PLTS, there will be no
functional change as a result of this patch.

[1] https://lore.kernel.org/linux-arm-kernel/159ceeab-09af-3174-5058-445bc8dcf85b@nvidia.com/

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Shanker Donthineni <sdonthineni@nvidia.com>
Cc: Will Deacon <will@kernel.org>
Tested-by: Shanker Donthineni <sdonthineni@nvidia.com>
Link: https://lore.kernel.org/r/20230530110328.2213762-6-mark.rutland@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/Kconfig
arch/arm64/include/asm/module.h
arch/arm64/include/asm/module.lds.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/module.c

index b1201d2..a600208 100644 (file)
@@ -207,6 +207,7 @@ config ARM64
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_KVM
+       select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
        select HAVE_PERF_EVENTS
        select HAVE_PERF_REGS
@@ -577,7 +578,6 @@ config ARM64_ERRATUM_845719
 config ARM64_ERRATUM_843419
        bool "Cortex-A53: 843419: A load or store might access an incorrect address"
        default y
-       select ARM64_MODULE_PLTS if MODULES
        help
          This option links the kernel with '--fix-cortex-a53-843419' and
          enables PLT support to replace certain ADRP instructions, which can
@@ -2107,26 +2107,6 @@ config ARM64_SME
          register state capable of holding two dimensional matrix tiles to
          enable various matrix operations.
 
-config ARM64_MODULE_PLTS
-       bool "Use PLTs to allow module memory to spill over into vmalloc area"
-       depends on MODULES
-       select HAVE_MOD_ARCH_SPECIFIC
-       help
-         Allocate PLTs when loading modules so that jumps and calls whose
-         targets are too far away for their relative offsets to be encoded
-         in the instructions themselves can be bounced via veneers in the
-         module's PLT. This allows modules to be allocated in the generic
-         vmalloc area after the dedicated module memory area has been
-         exhausted.
-
-         When running with address space randomization (KASLR), the module
-         region itself may be too far away for ordinary relative jumps and
-         calls, and so in that case, module PLTs are required and cannot be
-         disabled.
-
-         Specific errata workaround(s) might also force module PLTs to be
-         enabled (ARM64_ERRATUM_843419).
-
 config ARM64_PSEUDO_NMI
        bool "Support for NMI-like interrupts"
        select ARM_GIC_V3
@@ -2167,7 +2147,6 @@ config RELOCATABLE
 
 config RANDOMIZE_BASE
        bool "Randomize the address of the kernel image"
-       select ARM64_MODULE_PLTS if MODULES
        select RELOCATABLE
        help
          Randomizes the virtual address at which the kernel image is
@@ -2198,9 +2177,8 @@ config RANDOMIZE_MODULE_REGION_FULL
          When this option is not set, the module region will be randomized over
          a limited range that contains the [_stext, _etext] interval of the
          core kernel, so branch relocations are almost always in range unless
-         ARM64_MODULE_PLTS is enabled and the region is exhausted. In this
-         particular case of region exhaustion, modules might be able to fall
-         back to a larger 2GB area.
+         the region is exhausted. In this particular case of region
+         exhaustion, modules might be able to fall back to a larger 2GB area.
 
 config CC_HAVE_STACKPROTECTOR_SYSREG
        def_bool $(cc-option,-mstack-protector-guard=sysreg -mstack-protector-guard-reg=sp_el0 -mstack-protector-guard-offset=0)
index 3e7dcc5..bfa6638 100644 (file)
@@ -7,7 +7,6 @@
 
 #include <asm-generic/module.h>
 
-#ifdef CONFIG_ARM64_MODULE_PLTS
 struct mod_plt_sec {
        int                     plt_shndx;
        int                     plt_num_entries;
@@ -21,7 +20,6 @@ struct mod_arch_specific {
        /* for CONFIG_DYNAMIC_FTRACE */
        struct plt_entry        *ftrace_trampolines;
 };
-#endif
 
 u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs,
                          void *loc, const Elf64_Rela *rela,
index dbba4b7..b9ae834 100644 (file)
@@ -1,9 +1,7 @@
 SECTIONS {
-#ifdef CONFIG_ARM64_MODULE_PLTS
        .plt 0 : { BYTE(0) }
        .init.plt 0 : { BYTE(0) }
        .text.ftrace_trampoline 0 : { BYTE(0) }
-#endif
 
 #ifdef CONFIG_KASAN_SW_TAGS
        /*
index 7c2bb4e..3864a64 100644 (file)
@@ -42,8 +42,7 @@ obj-$(CONFIG_COMPAT)                  += sigreturn32.o
 obj-$(CONFIG_COMPAT_ALIGNMENT_FIXUPS)  += compat_alignment.o
 obj-$(CONFIG_KUSER_HELPERS)            += kuser32.o
 obj-$(CONFIG_FUNCTION_TRACER)          += ftrace.o entry-ftrace.o
-obj-$(CONFIG_MODULES)                  += module.o
-obj-$(CONFIG_ARM64_MODULE_PLTS)                += module-plts.o
+obj-$(CONFIG_MODULES)                  += module.o module-plts.o
 obj-$(CONFIG_PERF_EVENTS)              += perf_regs.o perf_callchain.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 obj-$(CONFIG_CPU_PM)                   += sleep.o suspend.o
index 432626c..a650f5e 100644 (file)
@@ -197,7 +197,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
 
 static struct plt_entry *get_ftrace_plt(struct module *mod)
 {
-#ifdef CONFIG_ARM64_MODULE_PLTS
+#ifdef CONFIG_MODULES
        struct plt_entry *plt = mod->arch.ftrace_trampolines;
 
        return &plt[FTRACE_PLT_IDX];
@@ -249,7 +249,7 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
         * must use a PLT to reach it. We can only place PLTs for modules, and
         * only when module PLT support is built-in.
         */
-       if (!IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
+       if (!IS_ENABLED(CONFIG_MODULES))
                return false;
 
        /*
@@ -431,10 +431,8 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
         *
         * Note: 'mod' is only set at module load time.
         */
-       if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS) &&
-           IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) && mod) {
+       if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS) && mod)
                return aarch64_insn_patch_text_nosync((void *)pc, new);
-       }
 
        if (!ftrace_find_callable_addr(rec, mod, &addr))
                return -EINVAL;
index 51fd8ab..f64636c 100644 (file)
@@ -73,25 +73,26 @@ subsys_initcall(kaslr_module_init)
 void *module_alloc(unsigned long size)
 {
        u64 module_alloc_end = module_alloc_base + MODULES_VSIZE;
-       gfp_t gfp_mask = GFP_KERNEL;
        void *p;
 
-       /* Silence the initial allocation */
-       if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS))
-               gfp_mask |= __GFP_NOWARN;
-
+       /*
+        * Where possible, prefer to allocate within direct branch range of the
+        * kernel such that no PLTs are necessary. This may fail, so we pass
+        * __GFP_NOWARN to silence the resulting warning.
+        */
        p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
-                               module_alloc_end, gfp_mask, PAGE_KERNEL, 0,
-                               NUMA_NO_NODE, __builtin_return_address(0));
+                               module_alloc_end, GFP_KERNEL | __GFP_NOWARN,
+                               PAGE_KERNEL, 0, NUMA_NO_NODE,
+                               __builtin_return_address(0));
 
-       if (!p && IS_ENABLED(CONFIG_ARM64_MODULE_PLTS)) {
+       if (!p) {
                p = __vmalloc_node_range(size, MODULE_ALIGN, module_alloc_base,
                                module_alloc_base + SZ_2G, GFP_KERNEL,
                                PAGE_KERNEL, 0, NUMA_NO_NODE,
                                __builtin_return_address(0));
        }
 
-       if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) {
+       if (p && (kasan_alloc_module_shadow(p, size, GFP_KERNEL) < 0)) {
                vfree(p);
                return NULL;
        }
@@ -479,9 +480,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_AARCH64_CALL26:
                        ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26,
                                             AARCH64_INSN_IMM_26);
-
-                       if (IS_ENABLED(CONFIG_ARM64_MODULE_PLTS) &&
-                           ovf == -ERANGE) {
+                       if (ovf == -ERANGE) {
                                val = module_emit_plt_entry(me, sechdrs, loc, &rel[i], sym);
                                if (!val)
                                        return -ENOEXEC;
@@ -518,7 +517,7 @@ static int module_init_ftrace_plt(const Elf_Ehdr *hdr,
                                  const Elf_Shdr *sechdrs,
                                  struct module *mod)
 {
-#if defined(CONFIG_ARM64_MODULE_PLTS) && defined(CONFIG_DYNAMIC_FTRACE)
+#if defined(CONFIG_DYNAMIC_FTRACE)
        const Elf_Shdr *s;
        struct plt_entry *plts;