mirror of https://github.com/dynup/kpatch
create-diff-object: fix use after free in kpatch-check-relocations()
Building data-read-mostly.patch on rhel-9.0-beta for ppc64le leads to a segmentation fault: Program received signal SIGSEGV, Segmentation fault. kpatch_check_relocations (kelf=0x10040490) at create-diff-object.c:2571 2571 sdata = rela->sym->sec->data; (gdb) bt (gdb) p rela->sym->sec->data Cannot access memory at address 0x160000007e Valgrind narrows the problem down to invalid reads through rela->sym in kpatch-check-relocations(). The culprits are kpatch_create_intermediate_sections(), which marks symbols referenced by rela sections that are now dynrelas to be stripped, and kpatch_strip_unneeded_syms(), which removes and frees them. The problem with the symbol stripping is that multiple relas may reference the same ELF symbol. If any remaining relocation references a shared symbol, we must keep it. Replace the symbol->strip boolean with an enumeration: SYMBOL_DEFAULT - initial value, symbol usage unknown SYMBOL_USED - symbol is definitely used by a rela SYMBOL_STRIP - symbol was only referenced by dynrela(s) Allow transitions from SYMBOL_DEFAULT to SYMBOL_* and SYMBOL_STRIP to SYMBOL_USED, but _not_ SYMBOL_USED to SYMBOL_*. Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
This commit is contained in:
parent
6de60e79b7
commit
ef0ce9715a
|
@ -1940,7 +1940,7 @@ static void kpatch_migrate_included_elements(struct kpatch_elf *kelf, struct kpa
|
|||
list_del(&sym->list);
|
||||
list_add_tail(&sym->list, &out->symbols);
|
||||
sym->index = 0;
|
||||
sym->strip = 0;
|
||||
sym->strip = SYMBOL_DEFAULT;
|
||||
if (sym->sec && !sym->sec->include)
|
||||
/* break link to non-included section */
|
||||
sym->sec = NULL;
|
||||
|
@ -3234,8 +3234,10 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf,
|
|||
special = true;
|
||||
|
||||
list_for_each_entry_safe(rela, safe, &sec->relas, list) {
|
||||
if (!rela->need_dynrela)
|
||||
if (!rela->need_dynrela) {
|
||||
rela->sym->strip = SYMBOL_USED;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting with Linux 5.8, .klp.arch sections are no
|
||||
|
@ -3332,8 +3334,8 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf,
|
|||
* later (for example, they may have relocations
|
||||
* of their own which should be processed).
|
||||
*/
|
||||
if (!rela->sym->sec)
|
||||
rela->sym->strip = 1;
|
||||
if (!rela->sym->sec && rela->sym->strip != SYMBOL_USED)
|
||||
rela->sym->strip = SYMBOL_STRIP;
|
||||
list_del(&rela->list);
|
||||
free(rela);
|
||||
|
||||
|
@ -3519,7 +3521,7 @@ static void kpatch_strip_unneeded_syms(struct kpatch_elf *kelf,
|
|||
struct symbol *sym, *safe;
|
||||
|
||||
list_for_each_entry_safe(sym, safe, &kelf->symbols, list) {
|
||||
if (sym->strip) {
|
||||
if (sym->strip == SYMBOL_STRIP) {
|
||||
list_del(&sym->list);
|
||||
free(sym);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,12 @@ struct section {
|
|||
};
|
||||
};
|
||||
|
||||
enum symbol_strip {
|
||||
SYMBOL_DEFAULT,
|
||||
SYMBOL_USED,
|
||||
SYMBOL_STRIP,
|
||||
};
|
||||
|
||||
struct symbol {
|
||||
struct list_head list;
|
||||
struct symbol *twin;
|
||||
|
@ -82,7 +88,7 @@ struct symbol {
|
|||
enum status status;
|
||||
union {
|
||||
int include; /* used in the patched elf */
|
||||
int strip; /* used in the output elf */
|
||||
enum symbol_strip strip; /* used in the output elf */
|
||||
};
|
||||
int has_func_profiling;
|
||||
};
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0d75b8137a08d62d89acf3358df8f44b1b86ff7a
|
||||
Subproject commit 365ce3af2ba7258d43982028b22d148f5c4686ac
|
Loading…
Reference in New Issue