diff options
Diffstat (limited to 'src/elflint.c')
-rw-r--r-- | src/elflint.c | 348 |
1 files changed, 40 insertions, 308 deletions
diff --git a/src/elflint.c b/src/elflint.c index a679acc4..cd335fe6 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -951,14 +951,14 @@ section [%2d] '%s': _DYNAMIC symbol size %" PRIu64 " does not match dynamic segm static bool is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr, - bool is_rela) + bool rela) { /* If this is no executable or DSO it cannot be a .rel.dyn section. */ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) return false; /* Check the section name. Unfortunately necessary. */ - if (strcmp (section_name (ebl, idx), is_rela ? ".rela.dyn" : ".rel.dyn")) + if (strcmp (section_name (ebl, idx), rela ? ".rela.dyn" : ".rel.dyn")) return false; /* When a .rel.dyn section is used a DT_RELCOUNT dynamic section @@ -984,106 +984,14 @@ is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr, if (dyn->d_tag == DT_RELCOUNT) { - /* Found it. Does the type match. */ - if (is_rela) + /* Found it. One last check: 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) ERROR (gettext ("\ -section [%2d] '%s': DT_RELCOUNT used for this RELA section\n"), - idx, section_name (ebl, idx)); - else - { - /* 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) - ERROR (gettext ("\ section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), - idx, section_name (ebl, idx), - (int) dyn->d_un.d_val); - - /* Make sure the specified number of relocations are - relative. */ - Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf, - idx), NULL); - if (reldata != NULL) - for (size_t inner = 0; - inner < shdr->sh_size / shdr->sh_entsize; - ++inner) - { - GElf_Rel rel_mem; - GElf_Rel *rel = gelf_getrel (reldata, inner, - &rel_mem); - if (rel == NULL) - /* The problem will be reported elsewhere. */ - break; - - if (ebl_relative_reloc_p (ebl, - GELF_R_TYPE (rel->r_info))) - { - if (inner >= dyn->d_un.d_val) - ERROR (gettext ("\ -section [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"), - idx, section_name (ebl, idx), - (int) dyn->d_un.d_val); - } - else if (inner < dyn->d_un.d_val) - ERROR (gettext ("\ -section [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"), - idx, section_name (ebl, idx), - inner, (int) dyn->d_un.d_val); - } - } - } - - if (dyn->d_tag == DT_RELACOUNT) - { - /* Found it. Does the type match. */ - if (!is_rela) - ERROR (gettext ("\ -section [%2d] '%s': DT_RELACOUNT used for this REL section\n"), - idx, section_name (ebl, idx)); - else - { - /* 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) - ERROR (gettext ("\ -section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), - idx, section_name (ebl, idx), - (int) dyn->d_un.d_val); - - /* Make sure the specified number of relocations are - relative. */ - Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf, - idx), NULL); - if (reldata != NULL) - for (size_t inner = 0; - inner < shdr->sh_size / shdr->sh_entsize; - ++inner) - { - GElf_Rela rela_mem; - GElf_Rela *rela = gelf_getrela (reldata, inner, - &rela_mem); - if (rela == NULL) - /* The problem will be reported elsewhere. */ - break; - - if (ebl_relative_reloc_p (ebl, - GELF_R_TYPE (rela->r_info))) - { - if (inner >= dyn->d_un.d_val) - ERROR (gettext ("\ -section [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"), - idx, section_name (ebl, idx), - (int) dyn->d_un.d_val); - } - else if (inner < dyn->d_un.d_val) - ERROR (gettext ("\ -section [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"), - idx, section_name (ebl, idx), - inner, (int) dyn->d_un.d_val); - } - } + idx, section_name (ebl, idx), + (int) dyn->d_un.d_val); } } @@ -1810,194 +1718,7 @@ extended section index is %" PRIu32 " but symbol index is not XINDEX\n"), static void -check_sysv_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, - GElf_Shdr *symshdr) -{ - Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0]; - Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1]; - - if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize) - ERROR (gettext ("\ -section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), - idx, section_name (ebl, idx), (long int) shdr->sh_size, - (long int) ((2 + nbucket + nchain) * shdr->sh_entsize)); - - size_t maxidx = nchain; - - if (symshdr != NULL) - { - size_t symsize = symshdr->sh_size / symshdr->sh_entsize; - - if (nchain > symshdr->sh_size / symshdr->sh_entsize) - ERROR (gettext ("section [%2d] '%s': chain array too large\n"), - idx, section_name (ebl, idx)); - - maxidx = symsize; - } - - size_t cnt; - for (cnt = 2; cnt < 2 + nbucket; ++cnt) - if (((Elf32_Word *) data->d_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) - ERROR (gettext ("\ -section [%2d] '%s': hash chain reference %zu out of bounds\n"), - idx, section_name (ebl, idx), cnt - 2 - nbucket); -} - - -static void -check_sysv_hash64 (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, - GElf_Shdr *symshdr) -{ - Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0]; - Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1]; - - if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize) - ERROR (gettext ("\ -section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), - idx, section_name (ebl, idx), (long int) shdr->sh_size, - (long int) ((2 + nbucket + nchain) * shdr->sh_entsize)); - - size_t maxidx = nchain; - - if (symshdr != NULL) - { - size_t symsize = symshdr->sh_size / symshdr->sh_entsize; - - if (nchain > symshdr->sh_size / symshdr->sh_entsize) - ERROR (gettext ("section [%2d] '%s': chain array too large\n"), - idx, section_name (ebl, idx)); - - maxidx = symsize; - } - - size_t cnt; - for (cnt = 2; cnt < 2 + nbucket; ++cnt) - if (((Elf64_Xword *) data->d_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) - ERROR (gettext ("\ -section [%2d] '%s': hash chain reference %zu out of bounds\n"), - idx, section_name (ebl, idx), cnt - 2 - nbucket); -} - - -static void -check_gnu_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, - GElf_Shdr *symshdr) -{ - Elf32_Word nbuckets = ((Elf32_Word *) data->d_buf)[0]; - Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1]; - - if (shdr->sh_size < (2 + 2 * nbuckets) * sizeof (Elf32_Word)) - { - ERROR (gettext ("\ -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) ((2 + 2 * nbuckets) * sizeof (Elf32_Word))); - return; - } - - size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (2 + 2 * nbuckets); - - if (symshdr != NULL) - maxidx = MIN (maxidx, symshdr->sh_size / symshdr->sh_entsize); - - /* We need the symbol section data. */ - Elf_Data *symdata = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), NULL); - - size_t cnt; - for (cnt = 2; cnt < 2 + 2 * nbuckets; cnt += 2) - { - Elf32_Word bitset = ((Elf32_Word *) data->d_buf)[cnt]; - Elf32_Word symidx = ((Elf32_Word *) data->d_buf)[cnt + 1]; - - if (symidx == 0) - { - /* Nothing in here. No bit in the bitset should be set either. */ - if (bitset != 0) - ERROR (gettext ("\ -section [%2d] '%s': hash chain for bucket %zu empty but bitset is not\n"), - idx, section_name (ebl, idx), cnt / 2 - 1); - - continue; - } - - if (symidx < symbias) - { - ERROR (gettext ("\ -section [%2d] '%s': hash chain for bucket %zu lower than symbol index bias\n"), - idx, section_name (ebl, idx), cnt / 2 - 1); - continue; - } - - Elf32_Word collected_bitset = 0; - while (symidx - symbias < maxidx) - { - Elf32_Word chainhash = ((Elf32_Word *) data->d_buf)[2 + 2 * nbuckets - + symidx - - symbias]; - - if (symdata != NULL) - { - /* Check that the referenced symbol is not undefined. */ - GElf_Sym sym_mem; - GElf_Sym *sym = gelf_getsym (symdata, symidx, &sym_mem); - if (sym != NULL && sym->st_shndx == SHN_UNDEF) - ERROR (gettext ("\ -section [%2d] '%s': symbol %u referenced in chain for bucket %zu is undefined\n"), - idx, section_name (ebl, idx), symidx, cnt / 2 - 1); - - const char *symname = elf_strptr (ebl->elf, symshdr->sh_link, - sym->st_name); - if (symname != NULL) - { - Elf32_Word hval = elf_gnu_hash (symname); - if ((hval & ~1u) != (chainhash & ~1u)) - ERROR (gettext ("\ -section [%2d] '%s': hash value for symbol %u in chain for bucket %zu wrong\n"), - idx, section_name (ebl, idx), symidx, cnt / 2 - 1); - } - } - - collected_bitset |= 1 << ((chainhash >> 5) & 31); - - if ((chainhash & 1) != 0) - break; - - ++symidx; - } - - if (symidx - symbias >= maxidx) - ERROR (gettext ("\ -section [%2d] '%s': hash chain for bucket %zu out of bounds\n"), - idx, section_name (ebl, idx), cnt / 2 - 1); - else if (symshdr != NULL - && symidx > symshdr->sh_size / symshdr->sh_entsize) - ERROR (gettext ("\ -section [%2d] '%s': symbol reference in chain for bucket %zu out of bounds\n"), - idx, section_name (ebl, idx), cnt / 2 - 1); - - if (bitset != collected_bitset) - ERROR (gettext ("\ -section [%2d] '%s': bitset for bucket %zu does not match chain entries: computed %#x, reported %#x\n"), - idx, section_name (ebl, idx), cnt / 2 - 1, - collected_bitset, bitset); - } -} - - -static void -check_hash (int tag, Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) +check_hash (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) { if (ehdr->e_type == ET_REL) { @@ -2023,11 +1744,9 @@ section [%2d] '%s': relocatable files cannot have hash tables\n"), section [%2d] '%s': hash table not for dynamic symbol table\n"), idx, section_name (ebl, idx)); - if (shdr->sh_entsize != (tag == SHT_GNU_HASH - ? sizeof (Elf32_Word) - : (size_t) ebl_sysvhash_entrysize (ebl))) + if (shdr->sh_entsize != sizeof (Elf32_Word)) ERROR (gettext ("\ -section [%2d] '%s': hash table entry size incorrect\n"), +section [%2d] '%s': entry size does not match Elf32_Word\n"), idx, section_name (ebl, idx)); if ((shdr->sh_flags & SHF_ALLOC) == 0) @@ -2037,26 +1756,40 @@ section [%2d] '%s': hash table entry size incorrect\n"), if (shdr->sh_size < 2 * shdr->sh_entsize) { ERROR (gettext ("\ -section [%2d] '%s': hash table has not even room for initial two administrative entries\n"), +section [%2d] '%s': hash table has not even room for nbucket and nchain\n"), idx, section_name (ebl, idx)); return; } - switch (tag) + Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0]; + Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1]; + + if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize) + ERROR (gettext ("\ +section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), + idx, section_name (ebl, idx), (long int) shdr->sh_size, + (long int) ((2 + nbucket + nchain) * shdr->sh_entsize)); + + if (symshdr != NULL) { - case SHT_HASH: - if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword)) - check_sysv_hash64 (ebl, shdr, data, idx, symshdr); - else - check_sysv_hash (ebl, shdr, data, idx, symshdr); - break; + size_t symsize = symshdr->sh_size / symshdr->sh_entsize; + size_t cnt; - case SHT_GNU_HASH: - check_gnu_hash (ebl, shdr, data, idx, symshdr); - break; + if (nchain < symshdr->sh_size / symshdr->sh_entsize) + ERROR (gettext ("section [%2d] '%s': chain array not large enough\n"), + idx, section_name (ebl, idx)); - default: - assert (! "should not happen"); + for (cnt = 2; cnt < 2 + nbucket; ++cnt) + if (((Elf32_Word *) data->d_buf)[cnt] >= symsize) + 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] >= symsize) + ERROR (gettext ("\ +section [%2d] '%s': hash chain reference %zu out of bounds\n"), + idx, section_name (ebl, idx), cnt - 2 - nbucket); } } @@ -2445,7 +2178,7 @@ section [%2d] '%s': symbol %d: local symbol with version\n"), index we need for this symbol. */ struct version_namelist *runp = version_namelist; while (runp != NULL) - if (runp->ndx == (*versym & 0x7fff)) + if (runp->ndx == *versym) break; else runp = runp->next; @@ -3212,8 +2945,7 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"), break; case SHT_HASH: - case SHT_GNU_HASH: - check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt); + check_hash (ebl, ehdr, shdr, cnt); break; case SHT_NULL: |