From e6eef4077acbff6e43e3c3880fb57d64b73e2567 Mon Sep 17 00:00:00 2001 From: liuxiaobo Date: Thu, 27 Jun 2024 14:22:53 +0800 Subject: [PATCH] upatch-diff: fix memory leak Signed-off-by: liuxiaobo --- upatch-diff/create-diff-object.c | 34 +++++--- upatch-diff/elf-correlate.c | 10 +-- upatch-diff/elf-create.c | 83 ++++++++++++-------- upatch-diff/elf-debug.c | 7 +- upatch-diff/running-elf.c | 2 +- upatch-diff/running-elf.h | 2 +- upatch-diff/upatch-elf.c | 128 ++++++++++++++++++++++--------- upatch-diff/upatch-elf.h | 14 +++- 8 files changed, 191 insertions(+), 89 deletions(-) diff --git a/upatch-diff/create-diff-object.c b/upatch-diff/create-diff-object.c index 5ec6f31..8830956 100644 --- a/upatch-diff/create-diff-object.c +++ b/upatch-diff/create-diff-object.c @@ -836,8 +836,10 @@ static void include_debug_sections(struct upatch_elf *uelf) list_for_each_entry_safe(rela, saferela, &sec->relas, list) // The shndex of symbol is SHN_COMMON, there is no related section - if (rela->sym && !rela->sym->include) + if (rela->sym && !rela->sym->include) { list_del(&rela->list); + free(rela); + } } if (eh_sec) @@ -993,15 +995,20 @@ int main(int argc, char*argv[]) mark_ignored_functions_same(); mark_ignored_sections_same(); - upatch_elf_teardown(&uelf_source); - upatch_elf_free(&uelf_source); - include_standard_elements(&uelf_patched); num_changed = include_changed_functions(&uelf_patched); new_globals_exist = include_new_globals(&uelf_patched); if (!num_changed && !new_globals_exist) { log_normal("No functional changes\n"); + upatch_elf_destroy(&uelf_source); + upatch_elf_destroy(&uelf_patched); + + upatch_elf_close(&uelf_source); + upatch_elf_close(&uelf_patched); + + relf_close(&relf); + return 0; } @@ -1019,9 +1026,6 @@ int main(int argc, char*argv[]) migrate_included_elements(&uelf_patched, &uelf_out); - /* since out elf still point to it, we only destroy it, not free it */ - upatch_elf_teardown(&uelf_patched); - upatch_create_strings_elements(&uelf_out); upatch_create_patches_sections(&uelf_out, &relf); @@ -1060,11 +1064,19 @@ int main(int argc, char*argv[]) upatch_write_output_elf(&uelf_out, uelf_patched.elf, arguments.output_obj, 0664); - relf_destroy(&relf); - upatch_elf_free(&uelf_patched); - upatch_elf_teardown(&uelf_out); - upatch_elf_free(&uelf_out); + upatch_elf_destroy(&uelf_source); + upatch_elf_destroy(&uelf_patched); + upatch_elf_destroy(&uelf_out); + + upatch_elf_close(&uelf_source); + upatch_elf_close(&uelf_patched); + upatch_elf_close(&uelf_out); + + relf_close(&relf); log_normal("Done\n"); + fflush(stdout); + fflush(stderr); + return 0; } diff --git a/upatch-diff/elf-correlate.c b/upatch-diff/elf-correlate.c index 3e3a536..cc3b925 100644 --- a/upatch-diff/elf-correlate.c +++ b/upatch-diff/elf-correlate.c @@ -36,9 +36,8 @@ static void correlate_symbol(struct symbol *sym_orig, struct symbol *sym_patched sym_orig->status = sym_patched->status = SAME; if (strcmp(sym_orig->name, sym_patched->name)) { log_debug("renaming symbol %s to %s \n", sym_patched->name, sym_orig->name); - sym_patched->name = strdup(sym_orig->name); - if (!sym_patched->name) - ERROR("strdup"); + sym_patched->name = sym_orig->name; + sym_patched->name_source = DATA_SOURCE_REF; } if (sym_orig->relf_sym && !sym_patched->relf_sym) sym_patched->relf_sym = sym_orig->relf_sym; @@ -98,9 +97,8 @@ static void __correlate_section(struct section *sec_orig, struct section *sec_pa /* Make sure these two sections have the same name */ if (strcmp(sec_orig->name, sec_patched->name)) { log_debug("renaming section %s to %s \n", sec_patched->name, sec_orig->name); - sec_patched->name = strdup(sec_orig->name); - if (!sec_patched->name) - ERROR("strdup"); + sec_patched->name = sec_orig->name; + sec_patched->name_source = DATA_SOURCE_REF; } } diff --git a/upatch-diff/elf-create.c b/upatch-diff/elf-create.c index 8ac212a..bd7edf0 100644 --- a/upatch-diff/elf-create.c +++ b/upatch-diff/elf-create.c @@ -41,10 +41,12 @@ static struct section *create_section_pair(struct upatch_elf *uelf, char *name, { char *relaname; struct section *sec, *relasec; + size_t size = strlen(name) + strlen(".rela") + 1; - relaname = malloc(strlen(name) + strlen(".rela") + 1); - if (!relaname) + relaname = calloc(1, size); + if (!relaname) { ERROR("relaname malloc failed."); + } strcpy(relaname, ".rela"); strcat(relaname, name); @@ -52,13 +54,17 @@ static struct section *create_section_pair(struct upatch_elf *uelf, char *name, /* allocate text section resourcce */ ALLOC_LINK(sec, &uelf->sections); sec->name = name; - sec->data = malloc(sizeof(*sec->data)); - if (!sec->data) + sec->data = calloc(1, sizeof(Elf_Data)); + if (!sec->data) { ERROR("section data malloc failed."); + } + sec->data_source = DATA_SOURCE_ALLOC; sec->data->d_buf = calloc(nr, entsize); - if (!sec->data->d_buf) + if (!sec->data->d_buf) { ERROR("d_buf of section data malloc failed."); + } + sec->dbuf_source = DATA_SOURCE_ALLOC; sec->data->d_size = entsize * nr; sec->data->d_type = ELF_T_BYTE; @@ -73,12 +79,15 @@ static struct section *create_section_pair(struct upatch_elf *uelf, char *name, /* set relocation section */ ALLOC_LINK(relasec, &uelf->sections); relasec->name = relaname; + relasec->name_source = DATA_SOURCE_ALLOC; INIT_LIST_HEAD(&relasec->relas); /* buffers will be generated by upatch_rebuild_rela_section_data */ - relasec->data = malloc(sizeof(*relasec->data)); - if (!relasec->data) + relasec->data = calloc(1, sizeof(Elf_Data)); + if (!relasec->data) { ERROR("relasec data malloc failed."); + } + relasec->data_source = DATA_SOURCE_ALLOC; relasec->data->d_type = ELF_T_RELA; @@ -103,9 +112,12 @@ void upatch_create_strings_elements(struct upatch_elf *uelf) ALLOC_LINK(sec, &uelf->sections); sec->name = ".upatch.strings"; - sec->data = malloc(sizeof(*sec->data)); - if (!sec->data) + sec->data = calloc(1, sizeof(Elf_Data)); + if (!sec->data) { ERROR("section data malloc failed"); + } + sec->data_source = DATA_SOURCE_ALLOC; + sec->data->d_type = ELF_T_BYTE; /* set section header */ @@ -310,12 +322,14 @@ void upatch_build_strings_section_data(struct upatch_elf *uelf) size += strlen(string->name) + 1; /* allocate section resources */ - strtab = malloc(size); - if (!strtab) + strtab = calloc(1, size); + if (!strtab) { ERROR("strtab malloc failed."); + } sec->data->d_buf = strtab; sec->data->d_size = size; + sec->dbuf_source = DATA_SOURCE_ALLOC; /* populate strings section data */ list_for_each_entry(string, &uelf->strings, list) { @@ -407,13 +421,15 @@ static void rebuild_rela_section_data(struct section *sec) nr++; size = nr * sizeof(*relas); - relas = malloc(size); - if (!relas) + relas = calloc(1, size); + if (!relas) { ERROR("relas malloc failed."); + } sec->data->d_buf = relas; sec->data->d_size = size; sec->sh.sh_size = size; + sec->dbuf_source = DATA_SOURCE_ALLOC; list_for_each_entry(rela, &sec->relas, list) { relas[index].r_offset = rela->offset; @@ -469,18 +485,19 @@ void upatch_create_shstrtab(struct upatch_elf *uelf) char *buf; shstrtab = find_section_by_name(&uelf->sections, ".shstrtab"); - if (!shstrtab) + if (!shstrtab) { ERROR("find_section_by_name failed."); + } /* determine size of string table */ size = 1; list_for_each_entry(sec, &uelf->sections, list) size += strlen(sec->name) + 1; - buf = malloc(size); - if (!buf) + buf = calloc(1, size); + if (!buf) { ERROR("malloc shstrtab failed."); - memset(buf, 0, size); + } offset = 1; list_for_each_entry(sec, &uelf->sections, list) { @@ -490,11 +507,14 @@ void upatch_create_shstrtab(struct upatch_elf *uelf) offset += len; } - if (offset != size) + if (offset != size) { + free(buf); ERROR("shstrtab size mismatch."); + } shstrtab->data->d_buf = buf; shstrtab->data->d_size = size; + shstrtab->dbuf_source = DATA_SOURCE_ALLOC; log_debug("shstrtab: "); print_strtab(buf, size); @@ -506,25 +526,24 @@ void upatch_create_shstrtab(struct upatch_elf *uelf) void upatch_create_strtab(struct upatch_elf *uelf) { - struct section *strtab; - struct symbol *sym; size_t size = 0, offset = 0, len = 0; - char *buf; - strtab = find_section_by_name(&uelf->sections, ".strtab"); - if (!strtab) + struct section *strtab = find_section_by_name(&uelf->sections, ".strtab"); + if (!strtab) { ERROR("find section failed in create strtab."); + } + struct symbol *sym = NULL; list_for_each_entry(sym, &uelf->symbols, list) { if (sym->type == STT_SECTION) continue; size += strlen(sym->name) + 1; } - buf = malloc(size); - if (!buf) + char *buf = calloc(1, size); + if (!buf) { ERROR("malloc buf failed in create strtab"); - memset(buf, 0, size); + } list_for_each_entry(sym, &uelf->symbols, list) { if (sym->type == STT_SECTION) { @@ -537,11 +556,14 @@ void upatch_create_strtab(struct upatch_elf *uelf) offset += len; } - if (offset != size) + if (offset != size) { + free(buf); ERROR("shstrtab size mismatch."); + } strtab->data->d_buf = buf; strtab->data->d_size = size; + strtab->dbuf_source = DATA_SOURCE_ALLOC; log_debug("strtab: "); print_strtab(buf, size); @@ -569,10 +591,10 @@ void upatch_create_symtab(struct upatch_elf *uelf) nr++; size = nr * symtab->sh.sh_entsize; - buf = malloc(size); - if (!buf) + buf = calloc(1, size); + if (!buf) { ERROR("malloc buf failed in create symtab."); - memset(buf, 0, size); + } offset = 0; list_for_each_entry(sym, &uelf->symbols, list) { @@ -585,6 +607,7 @@ void upatch_create_symtab(struct upatch_elf *uelf) symtab->data->d_buf = buf; symtab->data->d_size = size; + symtab->dbuf_source = DATA_SOURCE_ALLOC; /* update symtab section header */ strtab = find_section_by_name(&uelf->sections, ".strtab"); diff --git a/upatch-diff/elf-debug.c b/upatch-diff/elf-debug.c index eaabfa1..0490f86 100644 --- a/upatch-diff/elf-debug.c +++ b/upatch-diff/elf-debug.c @@ -129,9 +129,10 @@ void upatch_rebuild_eh_frame(struct section *sec) /* in this time, some relcation entries may have been deleted */ frame_size = 0; - eh_frame = malloc(sec->data->d_size); - if (!eh_frame) + eh_frame = calloc(1, sec->data->d_size); + if (!eh_frame) { ERROR("malloc eh_frame failed \n"); + } /* 8 is the offset of PC begin */ current_offset = 8; @@ -191,5 +192,7 @@ void upatch_rebuild_eh_frame(struct section *sec) sec->data->d_buf = eh_frame; sec->data->d_size = frame_size; + sec->dbuf_source = DATA_SOURCE_ALLOC; + sec->sh.sh_size = frame_size; } diff --git a/upatch-diff/running-elf.c b/upatch-diff/running-elf.c index 18ff095..c99b395 100644 --- a/upatch-diff/running-elf.c +++ b/upatch-diff/running-elf.c @@ -101,7 +101,7 @@ void relf_init(char *elf_name, struct running_elf *relf) } } -int relf_destroy(struct running_elf *relf) +int relf_close(struct running_elf *relf) { free(relf->obj_syms); elf_end(relf->elf); diff --git a/upatch-diff/running-elf.h b/upatch-diff/running-elf.h index 0646780..b02c8e2 100644 --- a/upatch-diff/running-elf.h +++ b/upatch-diff/running-elf.h @@ -58,7 +58,7 @@ struct running_elf { void relf_init(char *, struct running_elf *); -int relf_destroy(struct running_elf *); +int relf_close(struct running_elf *); bool lookup_relf(struct running_elf *, struct symbol *, struct lookup_result *); diff --git a/upatch-diff/upatch-elf.c b/upatch-diff/upatch-elf.c index ee38efc..171e88e 100644 --- a/upatch-diff/upatch-elf.c +++ b/upatch-diff/upatch-elf.c @@ -67,11 +67,14 @@ static void create_section_list(struct upatch_elf *uelf) sec->name = elf_strptr(uelf->elf, shstrndx, sec->sh.sh_name); if (!sec->name) ERROR("elf_strptr with error %s", elf_errmsg(0)); - sec->data = elf_getdata(scn, NULL); if (!sec->data) ERROR("elf_getdata with error %s", elf_errmsg(0)); + sec->name_source = DATA_SOURCE_ELF; + sec->data_source = DATA_SOURCE_ELF; + sec->dbuf_source = DATA_SOURCE_ELF; + sec->index = (unsigned int)elf_ndxscn(scn); /* found extended section header */ if (sec->sh.sh_type == SHT_SYMTAB_SHNDX) @@ -157,6 +160,8 @@ static void create_rela_list(struct upatch_elf *uelf, struct section *relasec) struct rela *rela; int index = 0, skip = 0; + INIT_LIST_HEAD(&relasec->relas); + /* for relocation sections, sh_info is the index which these informations apply */ relasec->base = find_section_by_index(&uelf->sections, relasec->sh.sh_info); if (!relasec->base) @@ -215,10 +220,86 @@ static void create_rela_list(struct upatch_elf *uelf, struct section *relasec) } } +static void destroy_rela_list(struct section *relasec) +{ + struct rela *rela = NULL, *saferela = NULL; + + list_for_each_entry_safe(rela, saferela, &relasec->relas, list) { + list_del(&rela->list); + free(rela); + } + + INIT_LIST_HEAD(&relasec->relas); +} + +static void destroy_section_list(struct upatch_elf *uelf) +{ + struct section *sec = NULL, *safesec = NULL; + + list_for_each_entry_safe(sec, safesec, &uelf->sections, list) { + if (sec->twin) { + sec->twin->twin = NULL; + } + + if ((sec->name != NULL) && (sec->name_source == DATA_SOURCE_ALLOC)) { + free(sec->name); + sec->name = NULL; + } + + if (sec->data != NULL) { + if (sec->dbuf_source == DATA_SOURCE_ALLOC) { + free(sec->data->d_buf); + sec->data->d_buf = NULL; + } + if (sec->data_source == DATA_SOURCE_ALLOC) { + free(sec->data); + sec->data = NULL; + } + } + + if (is_rela_section(sec)) { + destroy_rela_list(sec); + } + + list_del(&sec->list); + free(sec); + } + + INIT_LIST_HEAD(&uelf->sections); +} + +static void destroy_symbol_list(struct upatch_elf *uelf) +{ + struct symbol *sym = NULL, *safesym = NULL; + + list_for_each_entry_safe(sym, safesym, &uelf->symbols, list) { + if (sym->twin) { + sym->twin->twin = NULL; + } + + list_del(&sym->list); + free(sym); + } + + INIT_LIST_HEAD(&uelf->symbols); +} + +static void destroy_string_list(struct upatch_elf *uelf) +{ + struct string *str = NULL, *safestr = NULL; + + list_for_each_entry_safe(str, safestr, &uelf->strings, list) { + list_del(&str->list); + free(str); + } + + INIT_LIST_HEAD(&uelf->strings); +} + void upatch_elf_open(struct upatch_elf *uelf, const char *name) { GElf_Ehdr ehdr; - struct section *relasec; + struct section *sec; Elf *elf = NULL; int fd = 1; @@ -264,46 +345,21 @@ void upatch_elf_open(struct upatch_elf *uelf, const char *name) create_section_list(uelf); create_symbol_list(uelf); - list_for_each_entry(relasec, &uelf->sections, list) { - if (!is_rela_section(relasec)) - continue; - INIT_LIST_HEAD(&relasec->relas); - - create_rela_list(uelf, relasec); - } -} - -void upatch_elf_teardown(struct upatch_elf *uelf) -{ - struct section *sec, *safesec; - struct symbol *sym, *safesym; - struct rela *rela, *saferela; - - list_for_each_entry_safe(sec, safesec, &uelf->sections, list) { - if (sec->twin) - sec->twin->twin = NULL; + list_for_each_entry(sec, &uelf->sections, list) { if (is_rela_section(sec)) { - list_for_each_entry_safe(rela, saferela, &sec->relas, list) { - memset(rela, 0, sizeof(*rela)); - free(rela); - } + create_rela_list(uelf, sec); } - memset(sec, 0, sizeof(*sec)); - free(sec); - } - - list_for_each_entry_safe(sym, safesym, &uelf->symbols, list) { - if (sym->twin) - sym->twin->twin = NULL; - memset(sym, 0, sizeof(*sym)); - free(sym); } +} - INIT_LIST_HEAD(&uelf->sections); - INIT_LIST_HEAD(&uelf->symbols); +void upatch_elf_destroy(struct upatch_elf *uelf) +{ + destroy_section_list(uelf); + destroy_symbol_list(uelf); + destroy_string_list(uelf); } -void upatch_elf_free(struct upatch_elf *uelf) +void upatch_elf_close(struct upatch_elf *uelf) { elf_end(uelf->elf); close(uelf->fd); diff --git a/upatch-diff/upatch-elf.h b/upatch-diff/upatch-elf.h index 3cbb59b..6c62c93 100644 --- a/upatch-diff/upatch-elf.h +++ b/upatch-diff/upatch-elf.h @@ -39,6 +39,12 @@ struct section; struct rela; struct symbol; +enum data_source { + DATA_SOURCE_ELF, + DATA_SOURCE_REF, + DATA_SOURCE_ALLOC, +}; + enum status { NEW, CHANGED, @@ -61,6 +67,9 @@ struct section { struct section *twin; char *name; Elf_Data *data; + enum data_source name_source; + enum data_source data_source; + enum data_source dbuf_source; GElf_Shdr sh; int ignore; int include; @@ -102,6 +111,7 @@ struct symbol { struct section *sec; GElf_Sym sym; char *name; + enum data_source name_source; struct debug_symbol *relf_sym; unsigned int index; unsigned char bind; @@ -132,8 +142,8 @@ struct upatch_elf { void upatch_elf_open(struct upatch_elf *, const char *); // Destory upatch_elf struct -void upatch_elf_teardown(struct upatch_elf *); +void upatch_elf_destroy(struct upatch_elf *); -void upatch_elf_free(struct upatch_elf *); +void upatch_elf_close(struct upatch_elf *); #endif -- 2.34.1