]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
arm64: Fail module loading if dynamic SCS patching fails
authorAdrian Barnaś <abarnas@google.com>
Mon, 22 Sep 2025 13:04:26 +0000 (13:04 +0000)
committerWill Deacon <will@kernel.org>
Fri, 7 Nov 2025 15:00:09 +0000 (15:00 +0000)
Disallow a module to load if SCS dynamic patching fails for its code. For
module loading, instead of running a dry-run to check for patching errors,
try to run patching in the first run and propagate any errors so module
loading will fail.

Signed-off-by: Adrian Barnaś <abarnas@google.com>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/include/asm/scs.h
arch/arm64/kernel/module.c
arch/arm64/kernel/pi/map_kernel.c
arch/arm64/kernel/pi/patch-scs.c
arch/arm64/kernel/pi/pi.h

index a76f9b387a269e52b242d444f50b6ee291993fa8..c59f6324f2bbdb0578c56c1cd71fe383c8e14950 100644 (file)
@@ -53,7 +53,7 @@ enum {
        EDYNSCS_INVALID_CFA_OPCODE              = 4,
 };
 
-int __pi_scs_patch(const u8 eh_frame[], int size);
+int __pi_scs_patch(const u8 eh_frame[], int size, bool skip_dry_run);
 
 #endif /* __ASSEMBLY __ */
 
index d6d443c4a01aca6bcd2b8aa96594f964c6a4e840..01acbff8a1ae8e6e3844ff9ed7b77a2a4b556afc 100644 (file)
@@ -495,10 +495,18 @@ int module_finalize(const Elf_Ehdr *hdr,
        if (scs_is_dynamic()) {
                s = find_section(hdr, sechdrs, ".init.eh_frame");
                if (s) {
-                       ret = __pi_scs_patch((void *)s->sh_addr, s->sh_size);
-                       if (ret)
+                       /*
+                        * Because we can reject modules that are malformed
+                        * so SCS patching fails, skip dry run and try to patch
+                        * it in place. If patching fails, the module would not
+                        * be loaded anyway.
+                        */
+                       ret = __pi_scs_patch((void *)s->sh_addr, s->sh_size, true);
+                       if (ret) {
                                pr_err("module %s: error occurred during dynamic SCS patching (%d)\n",
                                       me->name, ret);
+                               return -ENOEXEC;
+                       }
                }
        }
 
index e8ddbde31a833d9735863e64db3490e97bafdcf8..659297f87cfa6e5ec2f8cf99b006c1889a215ab9 100644 (file)
@@ -104,7 +104,7 @@ static void __init map_kernel(u64 kaslr_offset, u64 va_offset, int root_level)
 
                if (enable_scs) {
                        scs_patch(__eh_frame_start + va_offset,
-                                 __eh_frame_end - __eh_frame_start);
+                                 __eh_frame_end - __eh_frame_start, false);
                        asm("ic ialluis");
 
                        dynamic_scs_is_enabled = true;
index 55d0cd64ef71e692ee7acd41f03937570023cf90..bbe7d30ed12b32737be7998592a5c9fe28b71aae 100644 (file)
@@ -225,7 +225,7 @@ static int scs_handle_fde_frame(const struct eh_frame *frame,
        return 0;
 }
 
-int scs_patch(const u8 eh_frame[], int size)
+int scs_patch(const u8 eh_frame[], int size, bool skip_dry_run)
 {
        int code_alignment_factor = 1;
        bool fde_use_sdata8 = false;
@@ -277,11 +277,13 @@ int scs_patch(const u8 eh_frame[], int size)
                        }
                } else {
                        ret = scs_handle_fde_frame(frame, code_alignment_factor,
-                                                  fde_use_sdata8, true);
+                                                  fde_use_sdata8, !skip_dry_run);
                        if (ret)
                                return ret;
-                       scs_handle_fde_frame(frame, code_alignment_factor,
-                                            fde_use_sdata8, false);
+
+                       if (!skip_dry_run)
+                               scs_handle_fde_frame(frame, code_alignment_factor,
+                                                    fde_use_sdata8, false);
                }
 
                p += sizeof(frame->size) + frame->size;
index 08ef9f80456bccc6233be164fd9ce51d71355c46..aec3172d400332a705c619f6e12c8112c4f632c0 100644 (file)
@@ -27,7 +27,7 @@ extern pgd_t init_pg_dir[], init_pg_end[];
 void init_feature_override(u64 boot_status, const void *fdt, int chosen);
 u64 kaslr_early_init(void *fdt, int chosen);
 void relocate_kernel(u64 offset);
-int scs_patch(const u8 eh_frame[], int size);
+int scs_patch(const u8 eh_frame[], int size, bool skip_dry_run);
 
 void map_range(phys_addr_t *pte, u64 start, u64 end, phys_addr_t pa,
               pgprot_t prot, int level, pte_t *tbl, bool may_use_cont,