aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2013-12-20 23:57:52 +1030
committerAlan Modra <amodra@gmail.com>2013-12-21 00:08:34 +1030
commit99d190fac4d2aab238cfc798dc5c28ab41456882 (patch)
treee05cdd046418c9f609282c8997528d923d7caa10
parent21986715b1e238269e919f7d7c85b134a9e18b17 (diff)
downloadgdb-99d190fac4d2aab238cfc798dc5c28ab41456882.zip
gdb-99d190fac4d2aab238cfc798dc5c28ab41456882.tar.gz
gdb-99d190fac4d2aab238cfc798dc5c28ab41456882.tar.bz2
Don't segv on cie.initial_instructions[] overflow.
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.
-rw-r--r--bfd/ChangeLog8
-rw-r--r--bfd/elf-eh-frame.c16
2 files changed, 18 insertions, 6 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 70c7e72..bc9e033 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index 832a991..4b6e8ea 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -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);