From: Jakub Jelinek Date: Fri, 17 Jan 2014 16:07:27 +0000 (+0100) Subject: robustify: elflint. X-Git-Tag: elfutils-0.159~52 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=71c1534c9c7a0652fb6c5f9295baa08f32b0b166;p=platform%2Fupstream%2Felfutils.git robustify: elflint. Signed-off-by: Mark Wielaard --- diff --git a/src/ChangeLog b/src/ChangeLog index a3f56fb..9fdc9f9 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2014-01-17 Jakub Jelinek + + * elflint.c (section_name): Return "" instead of + crashing on invalid section name. + (check_symtab, is_rel_dyn, check_rela, check_rel, check_dynamic, + check_symtab_shndx, check_hash, check_versym): Robustify. + (check_hash): Don't check entries beyond end of section. + (check_note): Don't crash if gelf_rawchunk fails. + 2014-01-17 Petr Machata * readelf.c (handle_dynamic, handle_relocs_rel) diff --git a/src/elflint.c b/src/elflint.c index e42072b..5a500b7 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -1,5 +1,5 @@ /* Pedantic checking of ELF files compliance with gABI/psABI spec. - Copyright (C) 2001-2013 Red Hat, Inc. + Copyright (C) 2001-2014 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper , 2001. @@ -123,6 +123,10 @@ static uint32_t shstrndx; /* Array to count references in section groups. */ static int *scnref; +/* Numbers of sections and program headers. */ +static unsigned int shnum; +static unsigned int phnum; + int main (int argc, char *argv[]) @@ -311,10 +315,19 @@ section_name (Ebl *ebl, int idx) { GElf_Shdr shdr_mem; GElf_Shdr *shdr; + const char *ret; + + if ((unsigned int) idx > shnum) + return ""; shdr = gelf_getshdr (elf_getscn (ebl->elf, idx), &shdr_mem); + if (shdr == NULL) + return ""; - return elf_strptr (ebl->elf, shstrndx, shdr->sh_name); + ret = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); + if (ret == NULL) + return ""; + return ret; } @@ -337,11 +350,6 @@ static const int valid_e_machine[] = (sizeof (valid_e_machine) / sizeof (valid_e_machine[0])) -/* Numbers of sections and program headers. */ -static unsigned int shnum; -static unsigned int phnum; - - static void check_elf_header (Ebl *ebl, GElf_Ehdr *ehdr, size_t size) { @@ -625,7 +633,8 @@ section [%2d] '%s': symbol table cannot have more than one extended index sectio } } - if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT)) + size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT); + if (shdr->sh_entsize != sh_entsize) ERROR (gettext ("\ section [%2u] '%s': entry size is does not match ElfXX_Sym\n"), idx, section_name (ebl, idx)); @@ -663,7 +672,7 @@ section [%2d] '%s': XINDEX for zeroth entry not zero\n"), xndxscnidx, section_name (ebl, xndxscnidx)); } - for (size_t cnt = 1; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + for (size_t cnt = 1; cnt < shdr->sh_size / sh_entsize; ++cnt) { sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, &xndx); if (sym == NULL) @@ -683,7 +692,8 @@ section [%2d] '%s': symbol %zu: invalid name value\n"), else { name = elf_strptr (ebl->elf, shdr->sh_link, sym->st_name); - assert (name != NULL); + assert (name != NULL + || strshdr->sh_type != SHT_STRTAB); } if (sym->st_shndx == SHN_XINDEX) @@ -1040,9 +1050,11 @@ is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr, { GElf_Shdr rcshdr_mem; const GElf_Shdr *rcshdr = gelf_getshdr (scn, &rcshdr_mem); - assert (rcshdr != NULL); - if (rcshdr->sh_type == SHT_DYNAMIC) + if (rcshdr == NULL) + break; + + if (rcshdr->sh_type == SHT_DYNAMIC && rcshdr->sh_entsize) { /* Found the dynamic section. Look through it. */ Elf_Data *d = elf_getdata (scn, NULL); @@ -1052,7 +1064,9 @@ is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr, { GElf_Dyn dyn_mem; GElf_Dyn *dyn = gelf_getdyn (d, cnt, &dyn_mem); - assert (dyn != NULL); + + if (dyn == NULL) + break; if (dyn->d_tag == DT_RELCOUNT) { @@ -1066,7 +1080,9 @@ section [%2d] '%s': DT_RELCOUNT used for this RELA section\n"), /* Does the number specified number of relative relocations exceed the total number of relocations? */ - if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize) + if (shdr->sh_entsize != 0 + && dyn->d_un.d_val > (shdr->sh_size + / shdr->sh_entsize)) ERROR (gettext ("\ section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), idx, section_name (ebl, idx), @@ -1226,7 +1242,8 @@ section [%2d] '%s': no relocations for merge-able sections possible\n"), } } - if (shdr->sh_entsize != gelf_fsize (ebl->elf, reltype, 1, EV_CURRENT)) + size_t sh_entsize = gelf_fsize (ebl->elf, reltype, 1, EV_CURRENT); + if (shdr->sh_entsize != sh_entsize) ERROR (gettext (reltype == ELF_T_RELA ? "\ section [%2d] '%s': section entry size does not match ElfXX_Rela\n" : "\ section [%2d] '%s': section entry size does not match ElfXX_Rel\n"), @@ -1449,7 +1466,8 @@ check_rela (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) Elf_Data *symdata = elf_getdata (symscn, NULL); enum load_state state = state_undecided; - for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT); + for (size_t cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt) { GElf_Rela rela_mem; GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem); @@ -1499,7 +1517,8 @@ check_rel (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) Elf_Data *symdata = elf_getdata (symscn, NULL); enum load_state state = state_undecided; - for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT); + for (size_t cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt) { GElf_Rel rel_mem; GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem); @@ -1598,7 +1617,8 @@ section [%2d] '%s': referenced as string table for section [%2d] '%s' but type i shdr->sh_link, section_name (ebl, shdr->sh_link), idx, section_name (ebl, idx)); - if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT)) + size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT); + if (shdr->sh_entsize != sh_entsize) ERROR (gettext ("\ section [%2d] '%s': section entry size does not match ElfXX_Dyn\n"), idx, section_name (ebl, idx)); @@ -1608,7 +1628,7 @@ section [%2d] '%s': section entry size does not match ElfXX_Dyn\n"), idx, section_name (ebl, idx)); bool non_null_warned = false; - for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) + for (cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt) { GElf_Dyn dyn_mem; GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dyn_mem); @@ -1880,6 +1900,8 @@ section [%2d] '%s': entry size does not match Elf32_Word\n"), idx, section_name (ebl, idx)); if (symshdr != NULL + && shdr->sh_entsize + && symshdr->sh_entsize && (shdr->sh_size / shdr->sh_entsize < symshdr->sh_size / symshdr->sh_entsize)) ERROR (gettext ("\ @@ -1906,6 +1928,12 @@ section [%2d] '%s': extended section index in section [%2zu] '%s' refers to same } Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); + if (data == NULL) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } if (*((Elf32_Word *) data->d_buf) != 0) ERROR (gettext ("symbol 0 should have zero extended section index\n")); @@ -1948,7 +1976,7 @@ section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), size_t maxidx = nchain; - if (symshdr != NULL) + if (symshdr != NULL && symshdr->sh_entsize != 0) { size_t symsize = symshdr->sh_size / symshdr->sh_entsize; @@ -1959,18 +1987,28 @@ section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), maxidx = symsize; } + Elf32_Word *buf = (Elf32_Word *) data->d_buf; + Elf32_Word *end = (Elf32_Word *) ((char *) data->d_buf + shdr->sh_size); size_t cnt; for (cnt = 2; cnt < 2 + nbucket; ++cnt) - if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx) + { + if (buf + cnt >= end) + break; + else if (buf[cnt] >= maxidx) ERROR (gettext ("\ section [%2d] '%s': hash bucket reference %zu out of bounds\n"), idx, section_name (ebl, idx), cnt - 2); + } for (; cnt < 2 + nbucket + nchain; ++cnt) - if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx) + { + if (buf + cnt >= end) + break; + else if (buf[cnt] >= maxidx) ERROR (gettext ("\ section [%2d] '%s': hash chain reference %zu out of bounds\n"), idx, section_name (ebl, idx), cnt - 2 - nbucket); + } } @@ -2000,18 +2038,28 @@ section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), maxidx = symsize; } + Elf64_Xword *buf = (Elf64_Xword *) data->d_buf; + Elf64_Xword *end = (Elf64_Xword *) ((char *) data->d_buf + shdr->sh_size); size_t cnt; for (cnt = 2; cnt < 2 + nbucket; ++cnt) - if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx) + { + if (buf + cnt >= end) + break; + else if (buf[cnt] >= maxidx) ERROR (gettext ("\ section [%2d] '%s': hash bucket reference %zu out of bounds\n"), idx, section_name (ebl, idx), cnt - 2); + } for (; cnt < 2 + nbucket + nchain; ++cnt) - if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx) + { + if (buf + cnt >= end) + break; + else if (buf[cnt] >= maxidx) ERROR (gettext ("\ section [%2d] '%s': hash chain reference %" PRIu64 " out of bounds\n"), - idx, section_name (ebl, idx), (uint64_t) (cnt - 2 - nbucket)); + idx, section_name (ebl, idx), (uint64_t) cnt - 2 - nbucket); + } } @@ -2036,7 +2084,7 @@ section [%2d] '%s': bitmask size not power of 2: %u\n"), if (shdr->sh_size < (4 + bitmask_words + nbuckets) * sizeof (Elf32_Word)) { ERROR (gettext ("\ -section [%2d] '%s': hash table section is too small (is %ld, expected at least%ld)\n"), +section [%2d] '%s': hash table section is too small (is %ld, expected at least %ld)\n"), idx, section_name (ebl, idx), (long int) shdr->sh_size, (long int) ((4 + bitmask_words + nbuckets) * sizeof (Elf32_Word))); return; @@ -2708,8 +2756,9 @@ section [%2d] '%s' refers in sh_link to section [%2d] '%s' which is no dynamic s /* The number of elements in the version symbol table must be the same as the number of symbols. */ - if (shdr->sh_size / shdr->sh_entsize - != symshdr->sh_size / symshdr->sh_entsize) + if (shdr->sh_entsize && symshdr->sh_entsize + && (shdr->sh_size / shdr->sh_entsize + != symshdr->sh_size / symshdr->sh_entsize)) ERROR (gettext ("\ section [%2d] '%s' has different number of entries than symbol table [%2d] '%s'\n"), idx, section_name (ebl, idx),