aboutsummaryrefslogtreecommitdiff
path: root/bfd/xcofflink.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/xcofflink.c')
-rw-r--r--bfd/xcofflink.c97
1 files changed, 70 insertions, 27 deletions
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index 446fa5a..b50b17f 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -243,6 +243,55 @@ xcoff_get_section_contents (bfd *abfd, asection *sec)
return contents;
}
+/* Read .loader and swap in the header. Sanity check to prevent
+ buffer overflows. Don't bother to check for overlap as that sort
+ of insanity shouldn't lead to incorrect program behaviour. */
+
+static bfd_byte *
+xcoff_get_ldhdr (bfd *abfd, asection *lsec, struct internal_ldhdr *ldhdr)
+{
+ bfd_byte *contents = xcoff_get_section_contents (abfd, lsec);
+ if (contents)
+ {
+ bfd_xcoff_swap_ldhdr_in (abfd, contents, ldhdr);
+ if (ldhdr->l_nsyms != 0)
+ {
+ bfd_vma symoff = bfd_xcoff_loader_symbol_offset (abfd, ldhdr);
+ if (symoff > lsec->size)
+ goto fail;
+ bfd_size_type onesym = bfd_xcoff_ldsymsz (abfd);
+ bfd_size_type syms;
+ if (_bfd_mul_overflow (ldhdr->l_nsyms, onesym, &syms)
+ || syms > lsec->size - symoff)
+ goto fail;
+ }
+ if (ldhdr->l_stlen != 0
+ && (ldhdr->l_stoff > lsec->size
+ || ldhdr->l_stlen > lsec->size - ldhdr->l_stoff))
+ goto fail;
+ if (ldhdr->l_nreloc != 0)
+ {
+ bfd_vma reloff = bfd_xcoff_loader_reloc_offset (abfd, ldhdr);
+ if (reloff > lsec->size)
+ goto fail;
+ bfd_size_type onerel = bfd_xcoff_ldrelsz (abfd);
+ bfd_size_type rels;
+ if (_bfd_mul_overflow (ldhdr->l_nreloc, onerel, &rels)
+ || rels > lsec->size - reloff)
+ goto fail;
+ }
+ if (ldhdr->l_nimpid != 0
+ && (ldhdr->l_impoff > lsec->size
+ || ldhdr->l_istlen > lsec->size - ldhdr->l_impoff))
+ goto fail;
+ }
+ return contents;
+
+ fail:
+ bfd_set_error (bfd_error_file_truncated);
+ return NULL;
+}
+
/* Get the size required to hold the dynamic symbols. */
long
@@ -265,12 +314,10 @@ _bfd_xcoff_get_dynamic_symtab_upper_bound (bfd *abfd)
return -1;
}
- contents = xcoff_get_section_contents (abfd, lsec);
+ contents = xcoff_get_ldhdr (abfd, lsec, &ldhdr);
if (!contents)
return -1;
- bfd_xcoff_swap_ldhdr_in (abfd, (void *) contents, &ldhdr);
-
return (ldhdr.l_nsyms + 1) * sizeof (asymbol *);
}
@@ -299,12 +346,10 @@ _bfd_xcoff_canonicalize_dynamic_symtab (bfd *abfd, asymbol **psyms)
return -1;
}
- contents = xcoff_get_section_contents (abfd, lsec);
+ contents = xcoff_get_ldhdr (abfd, lsec, &ldhdr);
if (!contents)
return -1;
- bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr);
-
strings = (char *) contents + ldhdr.l_stoff;
symbuf = bfd_zalloc (abfd, ldhdr.l_nsyms * sizeof (* symbuf));
@@ -322,9 +367,7 @@ _bfd_xcoff_canonicalize_dynamic_symtab (bfd *abfd, asymbol **psyms)
symbuf->symbol.the_bfd = abfd;
- if (ldsym._l._l_l._l_zeroes == 0)
- symbuf->symbol.name = strings + ldsym._l._l_l._l_offset;
- else
+ if (ldsym._l._l_l._l_zeroes != 0)
{
char *c;
@@ -335,6 +378,10 @@ _bfd_xcoff_canonicalize_dynamic_symtab (bfd *abfd, asymbol **psyms)
c[SYMNMLEN] = '\0';
symbuf->symbol.name = c;
}
+ else if (ldsym._l._l_l._l_offset < ldhdr.l_stlen)
+ symbuf->symbol.name = strings + ldsym._l._l_l._l_offset;
+ else
+ symbuf->symbol.name = _("<corrupt>");
if (ldsym.l_smclas == XMC_XO)
symbuf->symbol.section = bfd_abs_section_ptr;
@@ -384,12 +431,10 @@ _bfd_xcoff_get_dynamic_reloc_upper_bound (bfd *abfd)
return -1;
}
- contents = xcoff_get_section_contents (abfd, lsec);
+ contents = xcoff_get_ldhdr (abfd, lsec, &ldhdr);
if (!contents)
return -1;
- bfd_xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
-
return (ldhdr.l_nreloc + 1) * sizeof (arelent *);
}
@@ -419,12 +464,10 @@ _bfd_xcoff_canonicalize_dynamic_reloc (bfd *abfd,
return -1;
}
- contents = xcoff_get_section_contents (abfd, lsec);
+ contents = xcoff_get_ldhdr (abfd, lsec, &ldhdr);
if (!contents)
return -1;
- bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr);
-
relbuf = bfd_alloc (abfd, ldhdr.l_nreloc * sizeof (arelent));
if (relbuf == NULL)
return -1;
@@ -905,7 +948,7 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info)
return false;
}
- contents = xcoff_get_section_contents (abfd, lsec);
+ contents = xcoff_get_ldhdr (abfd, lsec, &ldhdr);
if (!contents)
return false;
@@ -913,8 +956,6 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info)
included in the link. */
bfd_section_list_clear (abfd);
- bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr);
-
strings = (char *) contents + ldhdr.l_stoff;
elsym = contents + bfd_xcoff_loader_symbol_offset(abfd, &ldhdr);
@@ -934,14 +975,16 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info)
if ((ldsym.l_smtype & L_EXPORT) == 0)
continue;
- if (ldsym._l._l_l._l_zeroes == 0)
- name = strings + ldsym._l._l_l._l_offset;
- else
+ if (ldsym._l._l_l._l_zeroes != 0)
{
memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
nambuf[SYMNMLEN] = '\0';
name = nambuf;
}
+ else if (ldsym._l._l_l._l_offset < ldhdr.l_stlen)
+ name = strings + ldsym._l._l_l._l_offset;
+ else
+ continue;
/* Normally we could not call xcoff_link_hash_lookup in an add
symbols routine, since we might not be using an XCOFF hash
@@ -2368,12 +2411,10 @@ xcoff_link_check_dynamic_ar_symbols (bfd *abfd,
/* There are no symbols, so don't try to include it. */
return true;
- contents = xcoff_get_section_contents (abfd, lsec);
+ contents = xcoff_get_ldhdr (abfd, lsec, &ldhdr);
if (!contents)
return false;
- bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr);
-
strings = (char *) contents + ldhdr.l_stoff;
elsym = contents + bfd_xcoff_loader_symbol_offset (abfd, &ldhdr);
@@ -2392,14 +2433,16 @@ xcoff_link_check_dynamic_ar_symbols (bfd *abfd,
if ((ldsym.l_smtype & L_EXPORT) == 0)
continue;
- if (ldsym._l._l_l._l_zeroes == 0)
- name = strings + ldsym._l._l_l._l_offset;
- else
+ if (ldsym._l._l_l._l_zeroes != 0)
{
memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
nambuf[SYMNMLEN] = '\0';
name = nambuf;
}
+ else if (ldsym._l._l_l._l_offset < ldhdr.l_stlen)
+ name = strings + ldsym._l._l_l._l_offset;
+ else
+ continue;
h = bfd_link_hash_lookup (info->hash, name, false, false, true);