mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
objtool/klp: Fix pointer comparisons for rodata objects
klp-diff treats all rodata as uncorrelated, so any reference to it uses a duplicated copy rather than using a KLP reloc. For the contents of the data itself, a duplicated copy is fine. However, pointer comparisons (e.g., f->f_op == &foo_ops) are broken. Fix it by correlating non-anonymous rodata objects. Also, use a new find_symbol_containing_inclusive() helper for matching the end of a symbol so bounds calculations don't get broken, for the case where an array or other symbol's ending address is used as part of a bounds calculation. While these are really two distinct changes, they need to be done in the same patch so as to avoid introducing bisection regressions. Acked-by: Song Liu <song@kernel.org> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
parent
8fdc3585b3
commit
d5b0f02528
|
|
@ -207,6 +207,20 @@ struct symbol *find_symbol_containing(const struct section *sec, unsigned long o
|
|||
return sym ? sym->alias : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Also match the symbol end address which can be used for a bounds comparison.
|
||||
*/
|
||||
struct symbol *find_symbol_containing_inclusive(const struct section *sec,
|
||||
unsigned long offset)
|
||||
{
|
||||
struct symbol *sym = find_symbol_containing(sec, offset);
|
||||
|
||||
if (!sym && offset)
|
||||
sym = find_symbol_containing(sec, offset - 1);
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns size of hole starting at @offset.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
|
|||
struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
|
||||
struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *name);
|
||||
struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
|
||||
struct symbol *find_symbol_containing_inclusive(const struct section *sec, unsigned long offset);
|
||||
int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
|
||||
struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
|
||||
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ static bool dont_correlate(struct symbol *sym)
|
|||
is_uncorrelated_static_local(sym) ||
|
||||
is_local_label(sym) ||
|
||||
is_string_sec(sym->sec) ||
|
||||
(is_rodata_sec(sym->sec) && !is_object_sym(sym)) ||
|
||||
is_initcall_sym(sym) ||
|
||||
is_addressable_sym(sym) ||
|
||||
is_special_section(sym->sec) ||
|
||||
|
|
@ -979,7 +980,7 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
|
|||
goto found_sym;
|
||||
|
||||
/* No dedicated section; find the symbol manually */
|
||||
sym = find_symbol_containing(sec, arch_adjusted_addend(reloc));
|
||||
sym = find_symbol_containing_inclusive(sec, arch_adjusted_addend(reloc));
|
||||
if (!sym) {
|
||||
/*
|
||||
* This is presumably an .altinstr_replacement section which is
|
||||
|
|
@ -988,6 +989,17 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
|
|||
if (!sec_size(sec))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* .rodata is a mixed bag of named objects and anonymous data.
|
||||
*
|
||||
* Convert section symbol references to named object symbols
|
||||
* when possible, to preserve pointer identity for const
|
||||
* structs like file_operations. Otherwise a section symbol is
|
||||
* fine.
|
||||
*/
|
||||
if (is_rodata_sec(sec))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* This can happen for special section references to weak code
|
||||
* whose symbol has been stripped by the linker.
|
||||
|
|
@ -1009,7 +1021,6 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
|
|||
static bool is_uncorrelated_section(struct section *sec)
|
||||
{
|
||||
return is_string_sec(sec) ||
|
||||
strstarts(sec->name, ".rodata") ||
|
||||
strstarts(sec->name, ".data..Lubsan") || /* GCC */
|
||||
strstarts(sec->name, ".data..L__unnamed_"); /* Clang */
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user