From 1e7c230b277b6eb82577a3bc4b56ca291c28964d Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Fri, 19 Oct 2018 15:01:29 +0200 Subject: Check sh_entsize is not zero. There were some recent bug reports where we trusted the ELF section header to be sane and divided the sh_size by the sh_entsize to get the number of objects in the section. This would cause a divide by zero if the file was corrupt and the sh_entsize was zero. Add checks for any such code. Signed-off-by: Mark Wielaard --- libasm/ChangeLog | 4 ++++ libasm/disasm_cb.c | 2 ++ libdwfl/ChangeLog | 4 ++++ libdwfl/dwfl_module_getdwarf.c | 2 ++ src/ChangeLog | 7 +++++++ src/unstrip.c | 27 ++++++++++++++++++++++++++- 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/libasm/ChangeLog b/libasm/ChangeLog index 2efd85fa..92dfd729 100644 --- a/libasm/ChangeLog +++ b/libasm/ChangeLog @@ -1,3 +1,7 @@ +2018-10-19 Mark Wielaard + + * disasm_cb.c (read_symtab_exec): Check sh_entsize is not zero. + 2018-07-04 Ross Burton * asm_end.c: Remove error.h include. diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c index cf278c71..80f8b25b 100644 --- a/libasm/disasm_cb.c +++ b/libasm/disasm_cb.c @@ -93,6 +93,8 @@ read_symtab_exec (DisasmCtx_t *ctx) xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL); /* Iterate over all symbols. Add all defined symbols. */ + if (shdr->sh_entsize == 0) + continue; int nsyms = shdr->sh_size / shdr->sh_entsize; for (int cnt = 1; cnt < nsyms; ++cnt) { diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 2e7efd45..6c333d83 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,7 @@ +2018-10-19 Mark Wielaard + + * dwfl_module_getdwarf.c (find_aux_sym): Check sh_entsize is not zero. + 2018-10-14 Mark Wielaard * dwfl_segment_report_module.c (read_portion): Check requested diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index af6838a6..56e61054 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1007,6 +1007,8 @@ find_aux_sym (Dwfl_Module *mod __attribute__ ((unused)), switch (shdr->sh_type) { case SHT_SYMTAB: + if (shdr->sh_entsize == 0) + return; minisymtab = true; *aux_symscn = scn; *aux_strshndx = shdr->sh_link; diff --git a/src/ChangeLog b/src/ChangeLog index a6ab0931..0cbcf80c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2018-10-19 Mark Wielaard + + * dwfl_module_getdwarf.c (adjust_relocs): Check sh_entsize is not + zero. + (add_new_section_symbols): Likewise. + (copy_elided_sections): Likewise. + 2018-10-18 Mark Wielaard * size.c (handle_ar): Only close elf if prefix was NULL. diff --git a/src/unstrip.c b/src/unstrip.c index 2cfd3b37..32da89d7 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -446,6 +446,9 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, switch (shdr->sh_type) { case SHT_REL: + if (shdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, "REL section cannot have zero sh_entsize"); + for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i) { GElf_Rel rel_mem; @@ -457,6 +460,9 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, break; case SHT_RELA: + if (shdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, "RELA section cannot have zero sh_entsize"); + for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i) { GElf_Rela rela_mem; @@ -483,6 +489,10 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, case SHT_HASH: /* We must expand the table and rejigger its contents. */ { + if (shdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, "HASH section cannot have zero sh_entsize"); + if (symshdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize"); const size_t nsym = symshdr->sh_size / symshdr->sh_entsize; const size_t onent = shdr->sh_size / shdr->sh_entsize; assert (data->d_size == shdr->sh_size); @@ -538,6 +548,11 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, case SHT_GNU_versym: /* We must expand the table and move its elements around. */ { + if (shdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, + "GNU_versym section cannot have zero sh_entsize"); + if (symshdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize"); const size_t nent = symshdr->sh_size / symshdr->sh_entsize; const size_t onent = shdr->sh_size / shdr->sh_entsize; assert (nent >= onent); @@ -603,6 +618,8 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum, GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem); ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); + if (shdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, "Symbol table section cannot have zero sh_entsize"); const size_t nsym = shdr->sh_size / shdr->sh_entsize; size_t symndx_map[nsym - 1]; @@ -1671,6 +1688,9 @@ more sections in stripped file than debug file -- arguments reversed?")); Elf_Data *shndxdata = NULL; /* XXX */ + if (shdr_mem.sh_entsize == 0) + error (EXIT_FAILURE, 0, + "SYMTAB section cannot have zero sh_entsize"); for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i) { GElf_Sym sym_mem; @@ -1736,11 +1756,16 @@ more sections in stripped file than debug file -- arguments reversed?")); /* Merge the stripped file's symbol table into the unstripped one. */ const size_t stripped_nsym = (stripped_symtab == NULL ? 1 : (stripped_symtab->shdr.sh_size - / stripped_symtab->shdr.sh_entsize)); + / (stripped_symtab->shdr.sh_entsize == 0 + ? 1 + : stripped_symtab->shdr.sh_entsize))); GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem); ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); + if (shdr->sh_entsize == 0) + error (EXIT_FAILURE, 0, + "unstripped SYMTAB section cannot have zero sh_entsize"); const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize; /* First collect all the symbols from both tables. */ -- cgit v1.2.3