aboutsummaryrefslogtreecommitdiff
path: root/binutils/rescoff.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils/rescoff.c')
-rw-r--r--binutils/rescoff.c288
1 files changed, 217 insertions, 71 deletions
diff --git a/binutils/rescoff.c b/binutils/rescoff.c
index f9a1e70..6031602 100644
--- a/binutils/rescoff.c
+++ b/binutils/rescoff.c
@@ -120,27 +120,41 @@ read_coff_rsrc (const char *filename, const char *target)
struct coff_file_info flaginfo;
if (filename == NULL)
- fatal (_("filename required for COFF input"));
+ {
+ non_fatal (_("filename required for COFF input"));
+ return NULL;
+ }
abfd = bfd_openr (filename, target);
if (abfd == NULL)
- bfd_fatal (filename);
+ {
+ bfd_nonfatal (filename);
+ return NULL;
+ }
if (! bfd_check_format_matches (abfd, bfd_object, &matching))
{
bfd_nonfatal (bfd_get_filename (abfd));
if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
list_matching_formats (matching);
- xexit (1);
+ free (matching);
+ bfd_close (abfd);
+ return NULL;
}
if (bfd_get_flavour (abfd) != bfd_target_coff_flavour
|| !obj_pe (abfd))
- fatal (_("%s: not a PE file"), filename);
+ {
+ non_fatal (_("%s: not a PE file"), filename);
+ bfd_close (abfd);
+ return NULL;
+ }
sec = bfd_get_section_by_name (abfd, ".rsrc");
if (sec == NULL)
{
- fatal (_("%s: no resource section"), filename);
+ non_fatal (_("%s: no resource section"), filename);
+ bfd_close (abfd);
+ return NULL;
}
set_windres_bfd (&wrbfd, abfd, sec, WR_KIND_BFD);
@@ -150,7 +164,11 @@ read_coff_rsrc (const char *filename, const char *target)
but there is no other way to determine if the section size
is reasonable. */
if (size > (bfd_size_type) get_file_size (filename))
- fatal (_("%s: .rsrc section is bigger than the file!"), filename);
+ {
+ non_fatal (_("%s: .rsrc section is bigger than the file!"), filename);
+ bfd_close (abfd);
+ return NULL;
+ }
data = (bfd_byte *) res_alloc (size);
get_windres_bfd_content (&wrbfd, data, 0, size);
@@ -178,7 +196,7 @@ read_coff_rsrc (const char *filename, const char *target)
static void
overrun (const struct coff_file_info *flaginfo, const char *msg)
{
- fatal (_("%s: %s: address out of bounds"), flaginfo->filename, msg);
+ non_fatal (_("%s: %s: address out of bounds"), flaginfo->filename, msg);
}
/* Read a resource directory. */
@@ -199,10 +217,17 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
Microsoft only defines 3 levels. Corrupt files however might
claim to use more. */
if (level > 4)
- fatal (_("%s: resources nest too deep"), flaginfo->filename);
+ {
+ non_fatal (_("%s: resources nest too deep"), flaginfo->filename);
+ return NULL;
+ }
- if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_directory))
- overrun (flaginfo, _("directory"));
+ size_t data_len = flaginfo->data_end - data;
+ if (data_len < sizeof (struct extern_res_directory))
+ {
+ overrun (flaginfo, _("directory"));
+ return NULL;
+ }
erd = (const struct extern_res_directory *) data;
@@ -229,8 +254,12 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
const bfd_byte *ers;
int length, j;
- if ((const bfd_byte *) ere >= flaginfo->data_end)
- overrun (flaginfo, _("named directory entry"));
+ if ((const bfd_byte *) ere > flaginfo->data_end
+ || flaginfo->data_end - (const bfd_byte *) ere < 8)
+ {
+ overrun (flaginfo, _("named directory entry"));
+ return NULL;
+ }
name = windres_get_32 (wrbfd, ere->name, 4);
rva = windres_get_32 (wrbfd, ere->rva, 4);
@@ -238,24 +267,32 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
/* For some reason the high bit in NAME is set. */
name &=~ 0x80000000;
- if (name > (rc_uint_type) (flaginfo->data_end - flaginfo->data))
- overrun (flaginfo, _("directory entry name"));
+ if (name > data_len)
+ {
+ overrun (flaginfo, _("directory entry name"));
+ return NULL;
+ }
ers = flaginfo->data + name;
-
+ if (flaginfo->data_end - ers < 2)
+ {
+ overrun (flaginfo, _("resource name"));
+ return NULL;
+ }
+ length = windres_get_16 (wrbfd, ers, 2);
+ /* PR 17512: file: 05dc4a16. */
+ if (length * 2 + 4 > flaginfo->data_end - ers)
+ {
+ overrun (flaginfo, _("resource name"));
+ return NULL;
+ }
re = (rc_res_entry *) res_alloc (sizeof *re);
re->next = NULL;
re->id.named = 1;
- length = windres_get_16 (wrbfd, ers, 2);
re->id.u.n.length = length;
re->id.u.n.name = (unichar *) res_alloc (length * sizeof (unichar));
for (j = 0; j < length; j++)
- {
- /* PR 17512: file: 05dc4a16. */
- if (length < 0 || ers >= flaginfo->data_end || ers + j * 2 + 4 >= flaginfo->data_end)
- overrun (flaginfo, _("resource name"));
- re->id.u.n.name[j] = windres_get_16 (wrbfd, ers + j * 2 + 2, 2);
- }
+ re->id.u.n.name[j] = windres_get_16 (wrbfd, ers + j * 2 + 2, 2);
if (level == 0)
type = &re->id;
@@ -263,18 +300,25 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
if ((rva & 0x80000000) != 0)
{
rva &=~ 0x80000000;
- if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
- overrun (flaginfo, _("named subdirectory"));
+ if (rva >= data_len)
+ {
+ overrun (flaginfo, _("named subdirectory"));
+ return NULL;
+ }
re->subdir = 1;
- re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type,
- level + 1);
+ re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo,
+ type, level + 1);
}
else
{
- if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
- overrun (flaginfo, _("named resource"));
+ if (rva >= data_len)
+ {
+ overrun (flaginfo, _("named resource"));
+ return NULL;
+ }
re->subdir = 0;
- re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type);
+ re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva,
+ flaginfo, type);
}
*pp = re;
@@ -286,8 +330,12 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
unsigned long name, rva;
rc_res_entry *re;
- if ((const bfd_byte *) ere >= flaginfo->data_end)
- overrun (flaginfo, _("ID directory entry"));
+ if ((const bfd_byte *) ere > flaginfo->data_end
+ || flaginfo->data_end - (const bfd_byte *) ere < 8)
+ {
+ overrun (flaginfo, _("ID directory entry"));
+ return NULL;
+ }
name = windres_get_32 (wrbfd, ere->name, 4);
rva = windres_get_32 (wrbfd, ere->rva, 4);
@@ -303,18 +351,25 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
if ((rva & 0x80000000) != 0)
{
rva &=~ 0x80000000;
- if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
- overrun (flaginfo, _("ID subdirectory"));
+ if (rva >= data_len)
+ {
+ overrun (flaginfo, _("ID subdirectory"));
+ return NULL;
+ }
re->subdir = 1;
- re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type,
- level + 1);
+ re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo,
+ type, level + 1);
}
else
{
- if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
- overrun (flaginfo, _("ID resource"));
+ if (rva >= data_len)
+ {
+ overrun (flaginfo, _("ID resource"));
+ return NULL;
+ }
re->subdir = 0;
- re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type);
+ re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva,
+ flaginfo, type);
}
*pp = re;
@@ -337,10 +392,16 @@ read_coff_data_entry (windres_bfd *wrbfd, const bfd_byte *data,
const bfd_byte *resdata;
if (type == NULL)
- fatal (_("resource type unknown"));
+ {
+ non_fatal (_("resource type unknown"));
+ return NULL;
+ }
if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_data))
- overrun (flaginfo, _("data entry"));
+ {
+ overrun (flaginfo, _("data entry"));
+ return NULL;
+ }
erd = (const struct extern_res_data *) data;
@@ -348,18 +409,26 @@ read_coff_data_entry (windres_bfd *wrbfd, const bfd_byte *data,
rva = windres_get_32 (wrbfd, erd->rva, 4);
if (rva < flaginfo->secaddr
|| rva - flaginfo->secaddr >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
- overrun (flaginfo, _("resource data"));
+ {
+ overrun (flaginfo, _("resource data"));
+ return NULL;
+ }
resdata = flaginfo->data + (rva - flaginfo->secaddr);
if (size > (rc_uint_type) (flaginfo->data_end - resdata))
- overrun (flaginfo, _("resource data size"));
+ {
+ overrun (flaginfo, _("resource data size"));
+ return NULL;
+ }
r = bin_to_res (wrbfd, *type, resdata, size);
-
- memset (&r->res_info, 0, sizeof (rc_res_res_info));
- r->coff_info.codepage = windres_get_32 (wrbfd, erd->codepage, 4);
- r->coff_info.reserved = windres_get_32 (wrbfd, erd->reserved, 4);
+ if (r != NULL)
+ {
+ memset (&r->res_info, 0, sizeof (rc_res_res_info));
+ r->coff_info.codepage = windres_get_32 (wrbfd, erd->codepage, 4);
+ r->coff_info.reserved = windres_get_32 (wrbfd, erd->reserved, 4);
+ }
return r;
}
@@ -422,9 +491,9 @@ struct coff_write_info
static void coff_bin_sizes (const rc_res_directory *, struct coff_write_info *);
static bfd_byte *coff_alloc (struct bindata_build *, rc_uint_type);
-static void coff_to_bin
+static bool coff_to_bin
(const rc_res_directory *, struct coff_write_info *);
-static void coff_res_to_bin
+static bool coff_res_to_bin
(const rc_res_resource *, struct coff_write_info *);
/* Write resources to a COFF file. RESOURCES should already be
@@ -435,7 +504,7 @@ static void coff_res_to_bin
would require doing the basic work of objcopy, just modifying or
adding the .rsrc section. */
-void
+bool
write_coff_file (const char *filename, const char *target,
const rc_res_directory *resources)
{
@@ -448,44 +517,86 @@ write_coff_file (const char *filename, const char *target,
unsigned long length, offset;
if (filename == NULL)
- fatal (_("filename required for COFF output"));
+ {
+ non_fatal (_("filename required for COFF output"));
+ return false;
+ }
abfd = bfd_openw (filename, target);
if (abfd == NULL)
- bfd_fatal (filename);
+ {
+ bfd_nonfatal (filename);
+ return false;
+ }
if (! bfd_set_format (abfd, bfd_object))
- bfd_fatal ("bfd_set_format");
+ {
+ bfd_nonfatal ("bfd_set_format");
+ bfd_close_all_done (abfd);
+ return false;
+ }
#if defined DLLTOOL_SH
if (! bfd_set_arch_mach (abfd, bfd_arch_sh, 0))
- bfd_fatal ("bfd_set_arch_mach(sh)");
+ {
+ bfd_nonfatal ("bfd_set_arch_mach(sh)");
+ bfd_close_all_done (abfd);
+ return false;
+ }
#elif defined DLLTOOL_MIPS
if (! bfd_set_arch_mach (abfd, bfd_arch_mips, 0))
- bfd_fatal ("bfd_set_arch_mach(mips)");
+ {
+ bfd_nonfatal ("bfd_set_arch_mach(mips)");
+ bfd_close_all_done (abfd);
+ return false;
+ }
#elif defined DLLTOOL_ARM
if (! bfd_set_arch_mach (abfd, bfd_arch_arm, 0))
- bfd_fatal ("bfd_set_arch_mach(arm)");
+ {
+ bfd_nonfatal ("bfd_set_arch_mach(arm)");
+ bfd_close_all_done (abfd);
+ return false;
+ }
#elif defined DLLTOOL_AARCH64
if (! bfd_set_arch_mach (abfd, bfd_arch_aarch64, 0))
- bfd_fatal ("bfd_set_arch_mach(aarch64)");
+ {
+ bfd_nonfatal ("bfd_set_arch_mach(aarch64)");
+ bfd_close_all_done (abfd);
+ return false;
+ }
#else
/* FIXME: This is obviously i386 specific. */
if (! bfd_set_arch_mach (abfd, bfd_arch_i386, 0))
- bfd_fatal ("bfd_set_arch_mach(i386)");
+ {
+ bfd_nonfatal ("bfd_set_arch_mach(i386)");
+ bfd_close_all_done (abfd);
+ return false;
+ }
#endif
if (! bfd_set_file_flags (abfd, HAS_SYMS | HAS_RELOC))
- bfd_fatal ("bfd_set_file_flags");
+ {
+ bfd_nonfatal ("bfd_set_file_flags");
+ bfd_close_all_done (abfd);
+ return false;
+ }
sec = bfd_make_section_with_flags (abfd, ".rsrc",
(SEC_HAS_CONTENTS | SEC_ALLOC
| SEC_LOAD | SEC_DATA | SEC_READONLY));
if (sec == NULL)
- bfd_fatal ("bfd_make_section");
+ {
+ bfd_nonfatal ("bfd_make_section");
+ bfd_close_all_done (abfd);
+ return false;
+ }
if (! bfd_set_symtab (abfd, &sec->symbol, 1))
- bfd_fatal ("bfd_set_symtab");
+ {
+ bfd_nonfatal ("bfd_set_symtab");
+ bfd_close_all_done (abfd);
+ return false;
+ }
/* Requiring this is probably a bug in BFD. */
sec->output_section = sec;
@@ -529,7 +640,12 @@ write_coff_file (const char *filename, const char *target,
cwi.dirstrsize = (cwi.dirstrsize + 7) & ~7;
/* Actually convert the resources to binary. */
- coff_to_bin (resources, &cwi);
+ if (!coff_to_bin (resources, &cwi))
+ {
+ bfd_close_all_done (abfd);
+ free (cwi.relocs);
+ return false;
+ }
/* Add another few bytes to the directory strings if needed for
alignment. */
@@ -554,7 +670,12 @@ write_coff_file (const char *filename, const char *target,
+ cwi.resources.length);
if (!bfd_set_section_size (sec, length))
- bfd_fatal ("bfd_set_section_size");
+ {
+ bfd_nonfatal ("bfd_set_section_size");
+ bfd_close_all_done (abfd);
+ free (cwi.relocs);
+ return false;
+ }
bfd_set_reloc (abfd, sec, cwi.relocs, cwi.reloc_count);
@@ -562,7 +683,12 @@ write_coff_file (const char *filename, const char *target,
for (d = cwi.dirs.d; d != NULL; d = d->next)
{
if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
- bfd_fatal ("bfd_set_section_contents");
+ {
+ bfd_nonfatal ("bfd_set_section_contents");
+ bfd_close_all_done (abfd);
+ free (cwi.relocs);
+ return false;
+ }
offset += d->length;
}
for (d = cwi.dirstrs.d; d != NULL; d = d->next)
@@ -577,17 +703,28 @@ write_coff_file (const char *filename, const char *target,
}
for (rd = cwi.resources.d; rd != NULL; rd = rd->next)
{
- res_to_bin (cwi.wrbfd, (rc_uint_type) offset, rd->res);
+ if (res_to_bin (cwi.wrbfd, (rc_uint_type) offset, rd->res)
+ == (rc_uint_type) -1)
+ {
+ bfd_close_all_done (abfd);
+ free (cwi.relocs);
+ return false;
+ }
offset += rd->length;
}
assert (offset == length);
if (! bfd_close (abfd))
- bfd_fatal ("bfd_close");
+ {
+ bfd_nonfatal ("bfd_close");
+ free (cwi.relocs);
+ return false;
+ }
/* We allocated the relocs array using malloc. */
free (cwi.relocs);
+ return true;
}
/* Work out the sizes of the various fixed size resource directory
@@ -640,7 +777,7 @@ coff_alloc (struct bindata_build *bb, rc_uint_type size)
/* Convert the resource directory RESDIR to binary. */
-static void
+static bool
coff_to_bin (const rc_res_directory *resdir, struct coff_write_info *cwi)
{
struct extern_res_directory *erd;
@@ -701,21 +838,24 @@ coff_to_bin (const rc_res_directory *resdir, struct coff_write_info *cwi)
if (e->subdir)
{
windres_put_32 (cwi->wrbfd, ere->rva, 0x80000000 | cwi->dirs.length);
- coff_to_bin (e->u.dir, cwi);
+ if (!coff_to_bin (e->u.dir, cwi))
+ return false;
}
else
{
windres_put_32 (cwi->wrbfd, ere->rva,
- cwi->dirsize + cwi->dirstrsize + cwi->dataents.length);
+ cwi->dirsize + cwi->dirstrsize + cwi->dataents.length);
- coff_res_to_bin (e->u.res, cwi);
+ if (!coff_res_to_bin (e->u.res, cwi))
+ return false;
}
}
+ return true;
}
/* Convert the resource RES to binary. */
-static void
+static bool
coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
{
arelent *r;
@@ -735,7 +875,10 @@ coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
r->addend = 0;
r->howto = bfd_reloc_type_lookup (WR_BFD (cwi->wrbfd), BFD_RELOC_RVA);
if (r->howto == NULL)
- bfd_fatal (_("can't get BFD_RELOC_RVA relocation type"));
+ {
+ bfd_nonfatal (_("can't get BFD_RELOC_RVA relocation type"));
+ return false;
+ }
cwi->relocs = xrealloc (cwi->relocs,
(cwi->reloc_count + 2) * sizeof (arelent *));
@@ -755,6 +898,8 @@ coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
d = (coff_res_data *) reswr_alloc (sizeof (coff_res_data));
d->length = res_to_bin (NULL, (rc_uint_type) 0, res);
+ if (d->length == (rc_uint_type) -1)
+ return false;
d->res = res;
d->next = NULL;
@@ -770,4 +915,5 @@ coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
/* Force the next resource to have 64 bit alignment. */
d->length = (d->length + 7) & ~7;
+ return true;
}