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_del(&sym->list);
|
||||||
list_add_tail(&sym->list, &out->symbols);
|
list_add_tail(&sym->list, &out->symbols);
|
||||||
sym->index = 0;
|
sym->index = 0;
|
||||||
sym->strip = 0;
|
sym->strip = SYMBOL_DEFAULT;
|
||||||
if (sym->sec && !sym->sec->include)
|
if (sym->sec && !sym->sec->include)
|
||||||
/* break link to non-included section */
|
/* break link to non-included section */
|
||||||
sym->sec = NULL;
|
sym->sec = NULL;
|
||||||
|
@ -3234,8 +3234,10 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf,
|
||||||
special = true;
|
special = true;
|
||||||
|
|
||||||
list_for_each_entry_safe(rela, safe, &sec->relas, list) {
|
list_for_each_entry_safe(rela, safe, &sec->relas, list) {
|
||||||
if (!rela->need_dynrela)
|
if (!rela->need_dynrela) {
|
||||||
|
rela->sym->strip = SYMBOL_USED;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Starting with Linux 5.8, .klp.arch sections are no
|
* 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
|
* later (for example, they may have relocations
|
||||||
* of their own which should be processed).
|
* of their own which should be processed).
|
||||||
*/
|
*/
|
||||||
if (!rela->sym->sec)
|
if (!rela->sym->sec && rela->sym->strip != SYMBOL_USED)
|
||||||
rela->sym->strip = 1;
|
rela->sym->strip = SYMBOL_STRIP;
|
||||||
list_del(&rela->list);
|
list_del(&rela->list);
|
||||||
free(rela);
|
free(rela);
|
||||||
|
|
||||||
|
@ -3519,7 +3521,7 @@ static void kpatch_strip_unneeded_syms(struct kpatch_elf *kelf,
|
||||||
struct symbol *sym, *safe;
|
struct symbol *sym, *safe;
|
||||||
|
|
||||||
list_for_each_entry_safe(sym, safe, &kelf->symbols, list) {
|
list_for_each_entry_safe(sym, safe, &kelf->symbols, list) {
|
||||||
if (sym->strip) {
|
if (sym->strip == SYMBOL_STRIP) {
|
||||||
list_del(&sym->list);
|
list_del(&sym->list);
|
||||||
free(sym);
|
free(sym);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,12 @@ struct section {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum symbol_strip {
|
||||||
|
SYMBOL_DEFAULT,
|
||||||
|
SYMBOL_USED,
|
||||||
|
SYMBOL_STRIP,
|
||||||
|
};
|
||||||
|
|
||||||
struct symbol {
|
struct symbol {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct symbol *twin;
|
struct symbol *twin;
|
||||||
|
@ -82,7 +88,7 @@ struct symbol {
|
||||||
enum status status;
|
enum status status;
|
||||||
union {
|
union {
|
||||||
int include; /* used in the patched elf */
|
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;
|
int has_func_profiling;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0d75b8137a08d62d89acf3358df8f44b1b86ff7a
|
Subproject commit 365ce3af2ba7258d43982028b22d148f5c4686ac
|
Loading…
Reference in New Issue