summaryrefslogtreecommitdiffstats
path: root/src/elflint.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/elflint.c')
-rw-r--r--src/elflint.c348
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: