>From 112e170de62569d35c5f18bf64a052a396978a6a Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Mon, 29 Dec 2014 00:53:27 +0100 Subject: [PATCH] elflint: Add various low-level checks. elflint could crash or hang because it didn't check some low level issues. https://bugzilla.redhat.com/show_bug.cgi?id=1170810 Reported-by: Alexander Cherepanov Signed-off-by: Mark Wielaard --- src/ChangeLog | 25 ++++++ src/elflint.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 236 insertions(+), 52 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 66d6270..5adf07d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,28 @@ +2014-12-30 Mark Wielaard + + * elflint.c (check_scn_group): Check d_buf and name are not NULL. + (is_rel_dyn): Check d is not NULL. Check shdr->sh_entsize is not + zero. + (check_dynamic): Check strshdr is not NULL. Check d_tag is positive. + (check_symtab_shndx): Check symshdr and data->d_buf are not NULL. + Check shdr and symshdr sh_entsize are not zero. + (check_gnu_hash): Make sure maskidx is smaller than bitmask_words. + Check symshdr->sh_entsize is not zero. Check data->d_buf is not + NULL. + (compare_hash_gnu_hash): Check sections d_buf are not NULL. + Check section data is large enough. Use gnu_symbias. + (check_group): Check section val is valid. + (has_copy_reloc): Check sh_entsize is not zero. + (check_versym): Likewise. + (unknown_dependency_p): Likewise. + (check_verneed): Break on invalid ref or offset. Don't assert. + Report error when next offset is zero, but more vers expected. + (check_verdef): Likewise. + (check_attributes): Make sure d_buf is not NULL. + (check_note): Likewise. + (check_note_section): Likewise. + (check_program_header): Make sure section name is not NULL. + 2014-12-26 Mark Wielaard * strings.c (read_elf): Produce error when section data falls outside diff --git a/src/elflint.c b/src/elflint.c index 7e73253..143424c 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -554,7 +554,8 @@ check_scn_group (Ebl *ebl, int idx) continue; Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL || data->d_size < sizeof (Elf32_Word)) + if (data == NULL || data->d_buf == NULL + || data->d_size < sizeof (Elf32_Word)) /* Cannot check the section. */ continue; @@ -692,8 +693,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 - || strshdr->sh_type != SHT_STRTAB); + if (name == NULL) + name = ""; } if (sym->st_shndx == SHN_XINDEX) @@ -1061,12 +1062,17 @@ is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr, if (rcshdr == NULL) break; - if (rcshdr->sh_type == SHT_DYNAMIC && rcshdr->sh_entsize) + if (rcshdr->sh_type == SHT_DYNAMIC && rcshdr->sh_entsize != 0) { /* Found the dynamic section. Look through it. */ Elf_Data *d = elf_getdata (scn, NULL); size_t cnt; + if (d == NULL) + ERROR (gettext ("\ +section [%2d] '%s': cannot get section data.\n"), + idx, section_name (ebl, idx)); + for (cnt = 1; cnt < rcshdr->sh_size / rcshdr->sh_entsize; ++cnt) { GElf_Dyn dyn_mem; @@ -1099,7 +1105,7 @@ section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), relative. */ Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf, idx), NULL); - if (reldata != NULL) + if (reldata != NULL && shdr->sh_entsize != 0) for (size_t inner = 0; inner < shdr->sh_size / shdr->sh_entsize; ++inner) @@ -1141,7 +1147,8 @@ section [%2d] '%s': DT_RELACOUNT used for this REL 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), @@ -1151,7 +1158,7 @@ section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), relative. */ Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf, idx), NULL); - if (reldata != NULL) + if (reldata != NULL && shdr->sh_entsize != 0) for (size_t inner = 0; inner < shdr->sh_size / shdr->sh_entsize; ++inner) @@ -1284,7 +1291,7 @@ section [%2d] '%s': section entry size does not match ElfXX_Rel\n"), GElf_Shdr *dynshdr = gelf_getshdr (dynscn, &dynshdr_mem); Elf_Data *dyndata = elf_getdata (dynscn, NULL); if (dynshdr != NULL && dynshdr->sh_type == SHT_DYNAMIC - && dyndata != NULL) + && dyndata != NULL && dynshdr->sh_entsize != 0) for (size_t j = 0; j < dynshdr->sh_size / dynshdr->sh_entsize; ++j) { GElf_Dyn dyn_mem; @@ -1622,6 +1629,13 @@ check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"), shdr->sh_link, section_name (ebl, shdr->sh_link), idx, section_name (ebl, idx)); + else if (strshdr == NULL) + { + ERROR (gettext ("\ +section [%2d]: referenced as string table for section [%2d] '%s' but section link value is invalid\n"), + shdr->sh_link, idx, section_name (ebl, idx)); + return; + } size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT); if (shdr->sh_entsize != sh_entsize) @@ -1685,10 +1699,10 @@ section [%2d] '%s': entry %zu: level 2 tag %s used\n"), has_dt[dyn->d_tag] = true; } - else if (dyn->d_tag <= DT_VALRNGHI + else if (dyn->d_tag >= 0 && dyn->d_tag <= DT_VALRNGHI && DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM) has_val_dt[DT_VALTAGIDX (dyn->d_tag)] = true; - else if (dyn->d_tag <= DT_ADDRRNGHI + else if (dyn->d_tag >= 0 && dyn->d_tag <= DT_ADDRRNGHI && DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM) has_addr_dt[DT_ADDRTAGIDX (dyn->d_tag)] = true; @@ -1896,6 +1910,10 @@ section [%2d] '%s': only relocatable files can have extended section index\n"), ERROR (gettext ("\ section [%2d] '%s': extended section index section not for symbol table\n"), idx, section_name (ebl, idx)); + else if (symshdr == NULL) + ERROR (gettext ("\ +section [%2d] '%s': sh_link extended section index [%2d] is invalid\n"), + idx, section_name (ebl, idx), shdr->sh_link); Elf_Data *symdata = elf_getdata (symscn, NULL); if (symdata == NULL) ERROR (gettext ("cannot get data for symbol section\n")); @@ -1906,8 +1924,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_entsize != 0 + && symshdr->sh_entsize != 0 && (shdr->sh_size / shdr->sh_entsize < symshdr->sh_size / symshdr->sh_entsize)) ERROR (gettext ("\ @@ -1934,7 +1952,7 @@ 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) + if (data == NULL || data->d_buf == NULL) { ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), idx, section_name (ebl, idx)); @@ -2033,7 +2051,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; @@ -2104,7 +2122,7 @@ section [%2d] '%s': 2nd hash function shift too big: %u\n"), size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (4 + bitmask_words + nbuckets); - if (symshdr != NULL) + if (symshdr != NULL && symshdr->sh_entsize != 0) maxidx = MIN (maxidx, symshdr->sh_size / symshdr->sh_entsize); /* We need the symbol section data. */ @@ -2155,8 +2173,10 @@ section [%2d] '%s': symbol %u referenced in chain for bucket %zu is undefined\n" idx, section_name (ebl, idx), symidx, cnt - (4 + bitmask_words)); - const char *symname = elf_strptr (ebl->elf, symshdr->sh_link, - sym->st_name); + const char *symname = (sym != NULL + ? elf_strptr (ebl->elf, symshdr->sh_link, + sym->st_name) + : NULL); if (symname != NULL) { Elf32_Word hval = elf_gnu_hash (symname); @@ -2168,6 +2188,14 @@ section [%2d] '%s': hash value for symbol %u in chain for bucket %zu wrong\n"), /* Set the bits in the bitmask. */ size_t maskidx = (hval / classbits) & bitmask_idxmask; + if (maskidx >= bitmask_words) + { + ERROR (gettext ("\ +section [%2d] '%s': mask index for symbol %u in chain for bucket %zu wrong\n"), + idx, section_name (ebl, idx), symidx, + cnt - (4 + bitmask_words)); + return; + } if (classbits == 32) { collected.p32[maskidx] @@ -2195,7 +2223,7 @@ section [%2d] '%s': hash value for symbol %u in chain for bucket %zu wrong\n"), ERROR (gettext ("\ section [%2d] '%s': hash chain for bucket %zu out of bounds\n"), idx, section_name (ebl, idx), cnt - (4 + bitmask_words)); - else if (symshdr != NULL + else if (symshdr != NULL && symshdr->sh_entsize != 0 && symidx > symshdr->sh_size / symshdr->sh_entsize) ERROR (gettext ("\ section [%2d] '%s': symbol reference in chain for bucket %zu out of bounds\n"), @@ -2223,7 +2251,7 @@ section [%2d] '%s': relocatable files cannot have hash tables\n"), } Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); - if (data == NULL) + if (data == NULL || data->d_buf == NULL) { ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), idx, section_name (ebl, idx)); @@ -2237,6 +2265,10 @@ section [%2d] '%s': relocatable files cannot have hash tables\n"), ERROR (gettext ("\ section [%2d] '%s': hash table not for dynamic symbol table\n"), idx, section_name (ebl, idx)); + else if (symshdr == NULL) + ERROR (gettext ("\ +section [%2d] '%s': invalid sh_link symbol table section index [%2d]\n"), + idx, section_name (ebl, idx), shdr->sh_link); if (shdr->sh_entsize != (tag == SHT_GNU_HASH ? (gelf_getclass (ebl->elf) == ELFCLASS32 @@ -2292,7 +2324,8 @@ compare_hash_gnu_hash (Ebl *ebl, GElf_Ehdr *ehdr, size_t hash_idx, GElf_Shdr *gnu_hash_shdr = gelf_getshdr (gnu_hash_scn, &gnu_hash_shdr_mem); if (hash_shdr == NULL || gnu_hash_shdr == NULL - || hash_data == NULL || gnu_hash_data == NULL) + || hash_data == NULL || hash_data->d_buf == NULL + || gnu_hash_data == NULL || gnu_hash_data->d_buf == NULL) /* None of these pointers should be NULL since we used the sections already. We are careful nonetheless. */ return; @@ -2313,27 +2346,70 @@ sh_link in hash sections [%2zu] '%s' and [%2zu] '%s' not identical\n"), GElf_Shdr sym_shdr_mem; GElf_Shdr *sym_shdr = gelf_getshdr (sym_scn, &sym_shdr_mem); - if (sym_data == NULL || sym_shdr == NULL) + if (sym_data == NULL || sym_data->d_buf == NULL + || sym_shdr == NULL || sym_shdr->sh_entsize == 0) return; - int nentries = sym_shdr->sh_size / sym_shdr->sh_entsize; + const char *hash_name; + const char *gnu_hash_name; + hash_name = elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name); + gnu_hash_name = elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name); + + if (gnu_hash_data->d_size < 4 * sizeof (Elf32_Word)) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' does not contain enough data\n"), + gnu_hash_idx, gnu_hash_name); + return; + } + + uint32_t nentries = sym_shdr->sh_size / sym_shdr->sh_entsize; char *used = alloca (nentries); memset (used, '\0', nentries); /* First go over the GNU_HASH table and mark the entries as used. */ const Elf32_Word *gnu_hasharr = (Elf32_Word *) gnu_hash_data->d_buf; Elf32_Word gnu_nbucket = gnu_hasharr[0]; + Elf32_Word gnu_symbias = gnu_hasharr[1]; const int bitmap_factor = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 1 : 2; const Elf32_Word *gnu_bucket = (gnu_hasharr + (4 + gnu_hasharr[2] * bitmap_factor)); - const Elf32_Word *gnu_chain = gnu_bucket + gnu_hasharr[0] - gnu_hasharr[1]; + const Elf32_Word *gnu_chain = gnu_bucket + gnu_hasharr[0]; + + if (gnu_hasharr[2] == 0) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' has zero bit mask words\n"), + gnu_hash_idx, gnu_hash_name); + return; + } + + uint64_t used_buf = ((4ULL + gnu_hasharr[2] * bitmap_factor + gnu_nbucket) + * sizeof (Elf32_Word)); + uint32_t max_nsyms = (gnu_hash_data->d_size - used_buf) / sizeof (Elf32_Word); + if (used_buf > gnu_hash_data->d_size) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' uses too much data\n"), + gnu_hash_idx, gnu_hash_name); + return; + } for (Elf32_Word cnt = 0; cnt < gnu_nbucket; ++cnt) { - Elf32_Word symidx = gnu_bucket[cnt]; + Elf32_Word symidx = gnu_bucket[cnt] - gnu_symbias;; if (symidx != STN_UNDEF) do - used[symidx] |= 1; + { + if (symidx >= max_nsyms || symidx >= nentries) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' invalid symbol index\n"), + gnu_hash_idx, gnu_hash_name); + return; + } + used[symidx] |= 1; + } while ((gnu_chain[symidx++] & 1u) == 0); } @@ -2342,37 +2418,82 @@ sh_link in hash sections [%2zu] '%s' and [%2zu] '%s' not identical\n"), if (hash_shdr->sh_entsize == sizeof (Elf32_Word)) { const Elf32_Word *hasharr = (Elf32_Word *) hash_data->d_buf; + if (hash_data->d_size < 2 * sizeof (Elf32_Word)) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' does not contain enough data\n"), + hash_idx, hash_name); + return; + } + Elf32_Word nbucket = hasharr[0]; + Elf32_Word nchain = hasharr[1]; + uint64_t hash_used = (2ULL + nchain + nbucket) * sizeof (Elf32_Word); + if (hash_used > hash_data->d_size) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' uses too much data\n"), + hash_idx, hash_name); + return; + } + const Elf32_Word *bucket = &hasharr[2]; const Elf32_Word *chain = &hasharr[2 + nbucket]; for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt) { Elf32_Word symidx = bucket[cnt]; - while (symidx != STN_UNDEF) + while (symidx != STN_UNDEF && symidx < nentries && symidx < nchain) { used[symidx] |= 2; symidx = chain[symidx]; } } } - else + else if (hash_shdr->sh_entsize == sizeof (Elf64_Word)) { const Elf64_Xword *hasharr = (Elf64_Xword *) hash_data->d_buf; + if (hash_data->d_size < 2 * sizeof (Elf32_Word)) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' does not contain enough data\n"), + hash_idx, hash_name); + return; + } + Elf64_Xword nbucket = hasharr[0]; + Elf64_Xword nchain = hasharr[1]; + uint64_t maxwords = hash_data->d_size / sizeof (Elf64_Xword); + if (maxwords < 2 + || maxwords - 2 < nbucket + || maxwords - 2 - nbucket < nchain) + { + ERROR (gettext ("\ +hash section [%2zu] '%s' uses too much data\n"), + hash_idx, hash_name); + return; + } + const Elf64_Xword *bucket = &hasharr[2]; const Elf64_Xword *chain = &hasharr[2 + nbucket]; for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt) { Elf64_Xword symidx = bucket[cnt]; - while (symidx != STN_UNDEF) + while (symidx != STN_UNDEF && symidx < nentries && symidx < nchain) { used[symidx] |= 2; symidx = chain[symidx]; } } } + else + { + ERROR (gettext ("\ +hash section [%2zu] '%s' invalid sh_entsize\n"), + gnu_hash_idx, gnu_hash_name); + return; + } /* Now see which entries are not set in one or both hash tables (unless the symbol is undefined in which case it can be omitted @@ -2385,7 +2506,7 @@ sh_link in hash sections [%2zu] '%s' and [%2zu] '%s' not identical\n"), ERROR (gettext ("section [%2zu] '%s': reference to symbol index 0\n"), hash_idx, elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name)); - for (int cnt = 1; cnt < nentries; ++cnt) + for (uint32_t cnt = 1; cnt < nentries; ++cnt) if (used[cnt] != 0 && used[cnt] != 3) { if (used[cnt] == 1) @@ -2474,6 +2595,10 @@ section [%2d] '%s': invalid symbol index in sh_info\n"), ERROR (gettext ("\ section [%2d] '%s': cannot get symbol for signature\n"), idx, section_name (ebl, idx)); + else if (elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name) == NULL) + ERROR (gettext ("\ +section [%2d] '%s': cannot get symbol name for signature\n"), + idx, section_name (ebl, idx)); else if (strcmp (elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name), "") == 0) ERROR (gettext ("\ @@ -2487,7 +2612,7 @@ section [%2d] '%s': signature symbol cannot be empty string\n"), } Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); - if (data == NULL) + if (data == NULL || data->d_buf == NULL) ERROR (gettext ("section [%2d] '%s': cannot get data: %s\n"), idx, section_name (ebl, idx), elf_errmsg (-1)); else @@ -2563,7 +2688,7 @@ section [%2d] '%s': element %Zu references section [%2d] '%s' without SHF_GROUP val, section_name (ebl, val)); } - if (++scnref[val] == 2) + if (val < shnum && ++scnref[val] == 2) ERROR (gettext ("\ section [%2d] '%s' is contained in more than one section group\n"), val, section_name (ebl, val)); @@ -2648,7 +2773,7 @@ has_copy_reloc (Ebl *ebl, unsigned int symscnndx, unsigned int symndx) return 0; Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL) + if (data == NULL || shdr->sh_entsize == 0) return 0; if (shdr->sh_type == SHT_REL) @@ -2762,7 +2887,7 @@ 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_entsize && symshdr->sh_entsize + if (shdr->sh_entsize != 0 && symshdr->sh_entsize != 0 && (shdr->sh_size / shdr->sh_entsize != symshdr->sh_size / symshdr->sh_entsize)) ERROR (gettext ("\ @@ -2771,7 +2896,7 @@ section [%2d] '%s' has different number of entries than symbol table [%2d] '%s'\ shdr->sh_link, section_name (ebl, shdr->sh_link)); Elf_Data *symdata = elf_getdata (symscn, NULL); - if (symdata == NULL) + if (symdata == NULL || shdr->sh_entsize == 0) /* The error has already been reported. */ return; @@ -2862,7 +2987,8 @@ unknown_dependency_p (Elf *elf, const char *fname) GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); Elf_Data *data = elf_getdata (scn, NULL); - if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC && data != NULL) + if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC + && data != NULL && shdr->sh_entsize != 0) for (size_t j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j) { GElf_Dyn dyn_mem; @@ -2923,9 +3049,12 @@ section [%2d] '%s': entry %d has wrong version %d\n"), if (need->vn_cnt > 0 && need->vn_aux < gelf_fsize (ebl->elf, ELF_T_VNEED, 1, EV_CURRENT)) - ERROR (gettext ("\ + { + ERROR (gettext ("\ section [%2d] '%s': entry %d has wrong offset of auxiliary data\n"), - idx, section_name (ebl, idx), cnt); + idx, section_name (ebl, idx), cnt); + break; + } const char *libname = elf_strptr (ebl->elf, shdr->sh_link, need->vn_file); @@ -2958,9 +3087,12 @@ section [%2d] '%s': auxiliary entry %d of entry %d has unknown flag\n"), const char *verstr = elf_strptr (ebl->elf, shdr->sh_link, aux->vna_name); if (verstr == NULL) - ERROR (gettext ("\ + { + ERROR (gettext ("\ section [%2d] '%s': auxiliary entry %d of entry %d has invalid name reference\n"), - idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt); + idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt); + break; + } else { GElf_Word hashval = elf_hash (verstr); @@ -2974,7 +3106,6 @@ section [%2d] '%s': auxiliary entry %d of entry %d has wrong hash value: %#x, ex ver_need); if (unlikely (res !=0)) { - assert (res > 0); ERROR (gettext ("\ section [%2d] '%s': auxiliary entry %d of entry %d has duplicate version name '%s'\n"), idx, section_name (ebl, idx), need->vn_cnt - cnt2, @@ -3002,9 +3133,20 @@ section [%2d] '%s': auxiliary entry %d of entry %d has wrong next field\n"), if ((need->vn_next != 0 || cnt > 0) && offset < auxoffset) - ERROR (gettext ("\ + { + ERROR (gettext ("\ section [%2d] '%s': entry %d has invalid offset to next entry\n"), - idx, section_name (ebl, idx), cnt); + idx, section_name (ebl, idx), cnt); + break; + } + + if (need->vn_next == 0 && cnt > 0) + { + ERROR (gettext ("\ +section [%2d] '%s': entry %d has zero offset to next entry, but sh_info says there are more entries\n"), + idx, section_name (ebl, idx), cnt); + break; + } } } @@ -3081,9 +3223,12 @@ section [%2d] '%s': entry %d has wrong version %d\n"), if (def->vd_cnt > 0 && def->vd_aux < gelf_fsize (ebl->elf, ELF_T_VDEF, 1, EV_CURRENT)) - ERROR (gettext ("\ + { + ERROR (gettext ("\ section [%2d] '%s': entry %d has wrong offset of auxiliary data\n"), - idx, section_name (ebl, idx), cnt); + idx, section_name (ebl, idx), cnt); + break; + } unsigned int auxoffset = offset + def->vd_aux; GElf_Verdaux auxmem; @@ -3109,7 +3254,6 @@ section [%2d] '%s': entry %d has wrong hash value: %#x, expected %#x\n"), int res = add_version (NULL, name, def->vd_ndx, ver_def); if (unlikely (res !=0)) { - assert (res > 0); ERROR (gettext ("\ section [%2d] '%s': entry %d has duplicate version name '%s'\n"), idx, section_name (ebl, idx), cnt, name); @@ -3129,9 +3273,12 @@ section [%2d] '%s': entry %d has duplicate version name '%s'\n"), name = elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name); if (name == NULL) - ERROR (gettext ("\ + { + ERROR (gettext ("\ section [%2d] '%s': entry %d has invalid name reference in auxiliary data\n"), - idx, section_name (ebl, idx), cnt); + idx, section_name (ebl, idx), cnt); + break; + } else { newname = alloca (sizeof (*newname)); @@ -3160,9 +3307,20 @@ section [%2d] '%s': entry %d has wrong next field in auxiliary data\n"), if ((def->vd_next != 0 || cnt > 0) && offset < auxoffset) - ERROR (gettext ("\ + { + ERROR (gettext ("\ section [%2d] '%s': entry %d has invalid offset to next entry\n"), - idx, section_name (ebl, idx), cnt); + idx, section_name (ebl, idx), cnt); + break; + } + + if (def->vd_next == 0 && cnt > 0) + { + ERROR (gettext ("\ +section [%2d] '%s': entry %d has zero offset to next entry, but sh_info says there are more entries\n"), + idx, section_name (ebl, idx), cnt); + break; + } } if (!has_base) @@ -3201,7 +3359,7 @@ check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) } Elf_Data *data = elf_rawdata (elf_getscn (ebl->elf, idx), NULL); - if (data == NULL || data->d_size == 0) + if (data == NULL || data->d_size == 0 || data->d_buf == NULL) { ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), idx, section_name (ebl, idx)); @@ -4084,7 +4242,7 @@ phdr[%d]: no note entries defined for the type of file\n"), Elf_Data *data = elf_getdata_rawchunk (ebl->elf, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR); - if (data != NULL) + if (data != NULL && data->d_buf != NULL) notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset); if (notes_size == 0) @@ -4103,7 +4261,7 @@ check_note_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) return; Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); - if (data == NULL) + if (data == NULL || data->d_buf == NULL) { ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), idx, section_name (ebl, idx)); @@ -4296,6 +4454,7 @@ program header offset in ELF header and PHDR entry do not match")); if (shdr != NULL && shdr->sh_type == (is_debuginfo ? SHT_NOBITS : SHT_PROGBITS) + && elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL && ! strcmp (".eh_frame_hdr", elf_strptr (ebl->elf, shstrndx, shdr->sh_name))) { -- 2.1.0