Don't segv on cie.initial_instructions[] overflow.
authorAlan Modra <amodra@gmail.com>
Fri, 20 Dec 2013 13:27:52 +0000 (23:57 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 20 Dec 2013 13:38:34 +0000 (00:08 +1030)
Don't attempt to merge CIEs with a larger number of insns than will
fit in the buffer.

* elf-eh-frame.c (cie_eq): Return false when initial_insn_length
is too large.
(cie_compute_hash): Don't exceed bounds of initial_instructions.
(_bfd_elf_parse_eh_frame): Always set initial_insn_length, and
save as much of insns to initial_instructions[] as will fit.

bfd/ChangeLog
bfd/elf-eh-frame.c

index 70c7e72..bc9e033 100644 (file)
@@ -1,3 +1,11 @@
+2013-12-20  Alan Modra  <amodra@gmail.com>
+
+       * elf-eh-frame.c (cie_eq): Return false when initial_insn_length
+       is too large.
+       (cie_compute_hash): Don't exceed bounds of initial_instructions.
+       (_bfd_elf_parse_eh_frame): Always set initial_insn_length, and
+       save as much of insns to initial_instructions[] as will fit.
+
 2013-12-19  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR binutils/16317
index 832a991..4b6e8ea 100644 (file)
@@ -235,6 +235,7 @@ cie_eq (const void *e1, const void *e2)
       && c1->lsda_encoding == c2->lsda_encoding
       && c1->fde_encoding == c2->fde_encoding
       && c1->initial_insn_length == c2->initial_insn_length
+      && c1->initial_insn_length <= sizeof (c1->initial_instructions)
       && memcmp (c1->initial_instructions,
                 c2->initial_instructions,
                 c1->initial_insn_length) == 0)
@@ -254,6 +255,7 @@ static hashval_t
 cie_compute_hash (struct cie *c)
 {
   hashval_t h = 0;
+  size_t len;
   h = iterative_hash_object (c->length, h);
   h = iterative_hash_object (c->version, h);
   h = iterative_hash (c->augmentation, strlen (c->augmentation) + 1, h);
@@ -267,7 +269,10 @@ cie_compute_hash (struct cie *c)
   h = iterative_hash_object (c->lsda_encoding, h);
   h = iterative_hash_object (c->fde_encoding, h);
   h = iterative_hash_object (c->initial_insn_length, h);
-  h = iterative_hash (c->initial_instructions, c->initial_insn_length, h);
+  len = c->initial_insn_length;
+  if (len > sizeof (c->initial_instructions))
+    len = sizeof (c->initial_instructions);
+  h = iterative_hash (c->initial_instructions, len, h);
   c->hash = h;
   return h;
 }
@@ -762,11 +767,10 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
            cie->fde_encoding = DW_EH_PE_absptr;
 
          initial_insn_length = end - buf;
-         if (initial_insn_length <= sizeof (cie->initial_instructions))
-           {
-             cie->initial_insn_length = initial_insn_length;
-             memcpy (cie->initial_instructions, buf, initial_insn_length);
-           }
+         cie->initial_insn_length = initial_insn_length;
+         memcpy (cie->initial_instructions, buf,
+                 initial_insn_length <= sizeof (cie->initial_instructions)
+                 ? initial_insn_length : sizeof (cie->initial_instructions));
          insns = buf;
          buf += initial_insn_length;
          ENSURE_NO_RELOCS (buf);