robustify: elflint.
authorJakub Jelinek <jakub@redhat.com>
Fri, 17 Jan 2014 16:07:27 +0000 (17:07 +0100)
committerMark Wielaard <mjw@redhat.com>
Thu, 23 Jan 2014 10:31:53 +0000 (11:31 +0100)
Signed-off-by: Mark Wielaard <mjw@redhat.com>
src/ChangeLog
src/elflint.c

index a3f56fb..9fdc9f9 100644 (file)
@@ -1,3 +1,12 @@
+2014-01-17  Jakub Jelinek  <jakub@redhat.com>
+
+       * elflint.c (section_name): Return "<invalid>" 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  <pmachata@redhat.com>
 
        * readelf.c (handle_dynamic, handle_relocs_rel)
index e42072b..5a500b7 100644 (file)
@@ -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 <drepper@redhat.com>, 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 "<invalid>";
 
   shdr = gelf_getshdr (elf_getscn (ebl->elf, idx), &shdr_mem);
+  if (shdr == NULL)
+    return "<invalid>";
 
-  return elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
+  ret = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
+  if (ret == NULL)
+    return "<invalid>";
+  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),