elflint: Check gnu_hash has enough data and bitmask_words is not zero.
authorMark Wielaard <mjw@redhat.com>
Wed, 6 May 2015 16:02:10 +0000 (18:02 +0200)
committerMark Wielaard <mjw@redhat.com>
Tue, 12 May 2015 14:50:44 +0000 (16:50 +0200)
https://bugzilla.redhat.com/show_bug.cgi?id=1170810#c31

Signed-off-by: Mark Wielaard <mjw@redhat.com>
src/ChangeLog
src/elflint.c

index 089fe93..e79f457 100644 (file)
@@ -1,7 +1,8 @@
 2015-05-06  Mark Wielaard  <mjw@redhat.com>
 
        * elflint.c (check_gnu_hash): Return early when 2nd hash function
-       shift too big.
+       shift too big. Check there is enough data available. Make sure
+       bitmask_words is not zero.
        (check_verdef): Use Elf64_Word for shdr->sh_info cnt.
        (check_verneed): Likewise.
        (check_attributes): Break when vendor name isn't terminated.
index df476a1..1c6a55a 100644 (file)
@@ -2091,26 +2091,40 @@ static void
 check_gnu_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
                GElf_Shdr *symshdr)
 {
+  if (data->d_size < 4 * sizeof (Elf32_Word))
+    {
+      ERROR (gettext ("\
+section [%2d] '%s': not enough data\n"),
+            idx, section_name (ebl, idx));
+      return;
+    }
+
   Elf32_Word nbuckets = ((Elf32_Word *) data->d_buf)[0];
   Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
   Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
 
-  if (!powerof2 (bitmask_words))
-    ERROR (gettext ("\
-section [%2d] '%s': bitmask size not power of 2: %u\n"),
-          idx, section_name (ebl, idx), bitmask_words);
+  if (bitmask_words == 0 || !powerof2 (bitmask_words))
+    {
+      ERROR (gettext ("\
+section [%2d] '%s': bitmask size zero or not power of 2: %u\n"),
+            idx, section_name (ebl, idx), bitmask_words);
+      return;
+    }
 
   size_t bitmask_idxmask = bitmask_words - 1;
   if (gelf_getclass (ebl->elf) == ELFCLASS64)
     bitmask_words *= 2;
   Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
 
-  if (shdr->sh_size < (4 + bitmask_words + nbuckets) * sizeof (Elf32_Word))
+  /* Is there still room for the sym chain?
+     Use uint64_t calculation to prevent 32bit overlow.  */
+  uint64_t used_buf = (4ULL + bitmask_words + nbuckets) * sizeof (Elf32_Word);
+  if (used_buf > data->d_size)
     {
       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) ((4 + bitmask_words + nbuckets) * sizeof (Elf32_Word)));
+            (long int) used_buf);
       return;
     }