]> www.infradead.org Git - users/hch/misc.git/commitdiff
objtool: Add action to check for absence of absolute relocations
authorArd Biesheuvel <ardb@kernel.org>
Thu, 28 Aug 2025 10:22:18 +0000 (12:22 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Wed, 3 Sep 2025 15:59:51 +0000 (17:59 +0200)
The x86 startup code must not use absolute references to code or data,
as it executes before the kernel virtual mapping is up.

Add an action to objtool to check all allocatable sections (with the
exception of __patchable_function_entries, which uses absolute
references for nebulous reasons) and raise an error if any absolute
references are found.

Note that debug sections typically contain lots of absolute references
too, but those are not allocatable so they will be ignored.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/20250828102202.1849035-39-ardb+git@google.com
tools/objtool/arch/x86/decode.c
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/include/objtool/arch.h
tools/objtool/include/objtool/builtin.h

index 98c4713c1b091b97dbaa9ec36ce94b4b3d19f1e6..0ad5cc70ecbe74e267896962e7d4e65a970c6b0b 100644 (file)
@@ -880,3 +880,15 @@ unsigned int arch_reloc_size(struct reloc *reloc)
                return 8;
        }
 }
+
+bool arch_absolute_reloc(struct elf *elf, struct reloc *reloc)
+{
+       switch (reloc_type(reloc)) {
+       case R_X86_64_32:
+       case R_X86_64_32S:
+       case R_X86_64_64:
+               return true;
+       default:
+               return false;
+       }
+}
index 80239843e9f02c77dcfd2f85a6d2ee6a62d289a1..0f6b197cfcb032c0a7f44e507c7c52cc50da20ec 100644 (file)
@@ -87,6 +87,7 @@ static const struct option check_options[] = {
        OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
        OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
        OPT_BOOLEAN(0  , "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"),
+       OPT_BOOLEAN(0  , "noabs", &opts.noabs, "reject absolute references in allocatable sections"),
        OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),
 
        OPT_GROUP("Options:"),
@@ -162,6 +163,7 @@ static bool opts_valid(void)
            opts.hack_noinstr           ||
            opts.ibt                    ||
            opts.mcount                 ||
+           opts.noabs                  ||
            opts.noinstr                ||
            opts.orc                    ||
            opts.retpoline              ||
index d14f20ef1db13f0d8a9ce711d524bac06b48579e..fb47327075fbaff8fd94feecf472b9278fddc0c4 100644 (file)
@@ -4644,6 +4644,47 @@ static void disas_warned_funcs(struct objtool_file *file)
                disas_funcs(funcs);
 }
 
+__weak bool arch_absolute_reloc(struct elf *elf, struct reloc *reloc)
+{
+       unsigned int type = reloc_type(reloc);
+       size_t sz = elf_addr_size(elf);
+
+       return (sz == 8) ? (type == R_ABS64) : (type == R_ABS32);
+}
+
+static int check_abs_references(struct objtool_file *file)
+{
+       struct section *sec;
+       struct reloc *reloc;
+       int ret = 0;
+
+       for_each_sec(file, sec) {
+               /* absolute references in non-loadable sections are fine */
+               if (!(sec->sh.sh_flags & SHF_ALLOC))
+                       continue;
+
+               /* section must have an associated .rela section */
+               if (!sec->rsec)
+                       continue;
+
+               /*
+                * Special case for compiler generated metadata that is not
+                * consumed until after boot.
+                */
+               if (!strcmp(sec->name, "__patchable_function_entries"))
+                       continue;
+
+               for_each_reloc(sec->rsec, reloc) {
+                       if (arch_absolute_reloc(file->elf, reloc)) {
+                               WARN("section %s has absolute relocation at offset 0x%lx",
+                                    sec->name, reloc_offset(reloc));
+                               ret++;
+                       }
+               }
+       }
+       return ret;
+}
+
 struct insn_chunk {
        void *addr;
        struct insn_chunk *next;
@@ -4777,6 +4818,9 @@ int check(struct objtool_file *file)
                        goto out;
        }
 
+       if (opts.noabs)
+               warnings += check_abs_references(file);
+
        if (opts.orc && nr_insns) {
                ret = orc_create(file);
                if (ret)
index 01ef6f415adf64995dfb6ac48dcc00026a116b18..be33c7b43180aa616a7687a7baee13dbffa15fbb 100644 (file)
@@ -97,6 +97,7 @@ bool arch_is_embedded_insn(struct symbol *sym);
 int arch_rewrite_retpolines(struct objtool_file *file);
 
 bool arch_pc_relative_reloc(struct reloc *reloc);
+bool arch_absolute_reloc(struct elf *elf, struct reloc *reloc);
 
 unsigned int arch_reloc_size(struct reloc *reloc);
 unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table);
index 6b08666fa69d64f6782b57db067c18b8e97cfbe3..ab22673862e1b108e2922e648bb23757ad6afbb2 100644 (file)
@@ -26,6 +26,7 @@ struct opts {
        bool uaccess;
        int prefix;
        bool cfi;
+       bool noabs;
 
        /* options: */
        bool backtrace;