objtool: Add action to check for absence of absolute relocations
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.compull/1354/merge
parent
05ce314ba5
commit
0d6e4563fc
|
|
@ -880,3 +880,15 @@ unsigned int arch_reloc_size(struct reloc *reloc)
|
||||||
return 8;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ static const struct option check_options[] = {
|
||||||
OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
|
OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
|
||||||
OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SMAP"),
|
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 , "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_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_dump),
|
||||||
|
|
||||||
OPT_GROUP("Options:"),
|
OPT_GROUP("Options:"),
|
||||||
|
|
@ -162,6 +163,7 @@ static bool opts_valid(void)
|
||||||
opts.hack_noinstr ||
|
opts.hack_noinstr ||
|
||||||
opts.ibt ||
|
opts.ibt ||
|
||||||
opts.mcount ||
|
opts.mcount ||
|
||||||
|
opts.noabs ||
|
||||||
opts.noinstr ||
|
opts.noinstr ||
|
||||||
opts.orc ||
|
opts.orc ||
|
||||||
opts.retpoline ||
|
opts.retpoline ||
|
||||||
|
|
|
||||||
|
|
@ -4644,6 +4644,47 @@ static void disas_warned_funcs(struct objtool_file *file)
|
||||||
disas_funcs(funcs);
|
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 {
|
struct insn_chunk {
|
||||||
void *addr;
|
void *addr;
|
||||||
struct insn_chunk *next;
|
struct insn_chunk *next;
|
||||||
|
|
@ -4777,6 +4818,9 @@ int check(struct objtool_file *file)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts.noabs)
|
||||||
|
warnings += check_abs_references(file);
|
||||||
|
|
||||||
if (opts.orc && nr_insns) {
|
if (opts.orc && nr_insns) {
|
||||||
ret = orc_create(file);
|
ret = orc_create(file);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,7 @@ bool arch_is_embedded_insn(struct symbol *sym);
|
||||||
int arch_rewrite_retpolines(struct objtool_file *file);
|
int arch_rewrite_retpolines(struct objtool_file *file);
|
||||||
|
|
||||||
bool arch_pc_relative_reloc(struct reloc *reloc);
|
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 int arch_reloc_size(struct reloc *reloc);
|
||||||
unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table);
|
unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ struct opts {
|
||||||
bool uaccess;
|
bool uaccess;
|
||||||
int prefix;
|
int prefix;
|
||||||
bool cfi;
|
bool cfi;
|
||||||
|
bool noabs;
|
||||||
|
|
||||||
/* options: */
|
/* options: */
|
||||||
bool backtrace;
|
bool backtrace;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue