X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Frescoff.c;h=fed362e7ef852dfdf0ce8bf9c22cd91499bc5908;hb=e2e31f1039e614b11277f5f1acc4182cd7fd3f2c;hp=737eb4f0ba9895a0557dbc26eb16ed24fdc7f48d;hpb=4a594fce16683232bbb2e239d3e3ebcfcde16d1a;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/rescoff.c b/binutils/rescoff.c index 737eb4f0ba..fed362e7ef 100644 --- a/binutils/rescoff.c +++ b/binutils/rescoff.c @@ -1,6 +1,5 @@ /* rescoff.c -- read and write resources in Windows COFF files. - Copyright 1997, 1998, 1999, 2000, 2003, 2007 - Free Software Foundation, Inc. + Copyright (C) 1997-2018 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. Rewritten by Kai Tietz, Onevision. @@ -8,7 +7,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -118,7 +117,7 @@ read_coff_rsrc (const char *filename, const char *target) asection *sec; bfd_size_type size; bfd_byte *data; - struct coff_file_info finfo; + struct coff_file_info flaginfo; if (filename == NULL) fatal (_("filename required for COFF input")); @@ -143,14 +142,20 @@ read_coff_rsrc (const char *filename, const char *target) set_windres_bfd (&wrbfd, abfd, sec, WR_KIND_BFD); size = bfd_section_size (abfd, sec); - data = (bfd_byte *) res_alloc (size); + /* PR 17512: file: 1b25ba5d + The call to get_file_size here may be expensive + 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); + data = (bfd_byte *) res_alloc (size); get_windres_bfd_content (&wrbfd, data, 0, size); - finfo.filename = filename; - finfo.data = data; - finfo.data_end = data + size; - finfo.secaddr = (bfd_get_section_vma (abfd, sec) + flaginfo.filename = filename; + flaginfo.data = data; + flaginfo.data_end = data + size; + flaginfo.secaddr = (bfd_get_section_vma (abfd, sec) - pe_data (abfd)->pe_opthdr.ImageBase); /* Now just read in the top level resource directory. Note that we @@ -158,8 +163,8 @@ read_coff_rsrc (const char *filename, const char *target) it. If we ever want to free up the resource information we read, this will have to be cleaned up. */ - ret = read_coff_res_dir (&wrbfd, data, &finfo, (const rc_res_id *) NULL, 0); - + ret = read_coff_res_dir (&wrbfd, data, &flaginfo, (const rc_res_id *) NULL, 0); + bfd_close (abfd); return ret; @@ -168,16 +173,16 @@ read_coff_rsrc (const char *filename, const char *target) /* Give an error if we are out of bounds. */ static void -overrun (const struct coff_file_info *finfo, const char *msg) +overrun (const struct coff_file_info *flaginfo, const char *msg) { - fatal (_("%s: %s: address out of bounds"), finfo->filename, msg); + fatal (_("%s: %s: address out of bounds"), flaginfo->filename, msg); } /* Read a resource directory. */ static rc_res_directory * read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, - const struct coff_file_info *finfo, + const struct coff_file_info *flaginfo, const rc_res_id *type, int level) { const struct extern_res_directory *erd; @@ -186,8 +191,15 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, rc_res_entry **pp; const struct extern_res_entry *ere; - if ((size_t) (finfo->data_end - data) < sizeof (struct extern_res_directory)) - overrun (finfo, _("directory")); + /* PR 17512: file: 09d80f53. + Whilst in theory resources can nest to any level, in practice + Microsoft only defines 3 levels. Corrupt files however might + claim to use more. */ + if (level > 4) + overrun (flaginfo, _("Resources nest too deep")); + + if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_directory)) + overrun (flaginfo, _("directory")); erd = (const struct extern_res_directory *) data; @@ -214,8 +226,8 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, const bfd_byte *ers; int length, j; - if ((const bfd_byte *) ere >= finfo->data_end) - overrun (finfo, _("named directory entry")); + if ((const bfd_byte *) ere >= flaginfo->data_end) + overrun (flaginfo, _("named directory entry")); name = windres_get_32 (wrbfd, ere->name, 4); rva = windres_get_32 (wrbfd, ere->rva, 4); @@ -223,10 +235,10 @@ 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) (finfo->data_end - finfo->data)) - overrun (finfo, _("directory entry name")); + if (name > (rc_uint_type) (flaginfo->data_end - flaginfo->data)) + overrun (flaginfo, _("directory entry name")); - ers = finfo->data + name; + ers = flaginfo->data + name; re = (rc_res_entry *) res_alloc (sizeof *re); re->next = NULL; @@ -235,7 +247,12 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, re->id.u.n.length = length; re->id.u.n.name = (unichar *) res_alloc (length * sizeof (unichar)); for (j = 0; j < length; j++) - re->id.u.n.name[j] = windres_get_16 (wrbfd, ers + j * 2 + 2, 2); + { + /* 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); + } if (level == 0) type = &re->id; @@ -243,18 +260,18 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, if ((rva & 0x80000000) != 0) { rva &=~ 0x80000000; - if (rva >= (rc_uint_type) (finfo->data_end - finfo->data)) - overrun (finfo, _("named subdirectory")); + if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data)) + overrun (flaginfo, _("named subdirectory")); re->subdir = 1; - re->u.dir = read_coff_res_dir (wrbfd, finfo->data + rva, finfo, type, + re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type, level + 1); } else { - if (rva >= (rc_uint_type) (finfo->data_end - finfo->data)) - overrun (finfo, _("named resource")); + if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data)) + overrun (flaginfo, _("named resource")); re->subdir = 0; - re->u.res = read_coff_data_entry (wrbfd, finfo->data + rva, finfo, type); + re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type); } *pp = re; @@ -266,8 +283,8 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, unsigned long name, rva; rc_res_entry *re; - if ((const bfd_byte *) ere >= finfo->data_end) - overrun (finfo, _("ID directory entry")); + if ((const bfd_byte *) ere >= flaginfo->data_end) + overrun (flaginfo, _("ID directory entry")); name = windres_get_32 (wrbfd, ere->name, 4); rva = windres_get_32 (wrbfd, ere->rva, 4); @@ -283,18 +300,18 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, if ((rva & 0x80000000) != 0) { rva &=~ 0x80000000; - if (rva >= (rc_uint_type) (finfo->data_end - finfo->data)) - overrun (finfo, _("ID subdirectory")); + if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data)) + overrun (flaginfo, _("ID subdirectory")); re->subdir = 1; - re->u.dir = read_coff_res_dir (wrbfd, finfo->data + rva, finfo, type, + re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type, level + 1); } else { - if (rva >= (rc_uint_type) (finfo->data_end - finfo->data)) - overrun (finfo, _("ID resource")); + if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data)) + overrun (flaginfo, _("ID resource")); re->subdir = 0; - re->u.res = read_coff_data_entry (wrbfd, finfo->data + rva, finfo, type); + re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type); } *pp = re; @@ -308,7 +325,7 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data, static rc_res_resource * read_coff_data_entry (windres_bfd *wrbfd, const bfd_byte *data, - const struct coff_file_info *finfo, + const struct coff_file_info *flaginfo, const rc_res_id *type) { const struct extern_res_data *erd; @@ -319,21 +336,21 @@ read_coff_data_entry (windres_bfd *wrbfd, const bfd_byte *data, if (type == NULL) fatal (_("resource type unknown")); - if ((size_t) (finfo->data_end - data) < sizeof (struct extern_res_data)) - overrun (finfo, _("data entry")); + if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_data)) + overrun (flaginfo, _("data entry")); erd = (const struct extern_res_data *) data; size = windres_get_32 (wrbfd, erd->size, 4); rva = windres_get_32 (wrbfd, erd->rva, 4); - if (rva < finfo->secaddr - || rva - finfo->secaddr >= (rc_uint_type) (finfo->data_end - finfo->data)) - overrun (finfo, _("resource data")); + if (rva < flaginfo->secaddr + || rva - flaginfo->secaddr >= (rc_uint_type) (flaginfo->data_end - flaginfo->data)) + overrun (flaginfo, _("resource data")); - resdata = finfo->data + (rva - finfo->secaddr); + resdata = flaginfo->data + (rva - flaginfo->secaddr); - if (size > (rc_uint_type) (finfo->data_end - resdata)) - overrun (finfo, _("resource data size")); + if (size > (rc_uint_type) (flaginfo->data_end - resdata)) + overrun (flaginfo, _("resource data size")); r = bin_to_res (wrbfd, *type, resdata, size); @@ -455,15 +472,12 @@ write_coff_file (const char *filename, const char *target, if (! bfd_set_file_flags (abfd, HAS_SYMS | HAS_RELOC)) bfd_fatal ("bfd_set_file_flags"); - sec = bfd_make_section (abfd, ".rsrc"); + sec = bfd_make_section_with_flags (abfd, ".rsrc", + (SEC_HAS_CONTENTS | SEC_ALLOC + | SEC_LOAD | SEC_DATA)); if (sec == NULL) bfd_fatal ("bfd_make_section"); - if (! bfd_set_section_flags (abfd, sec, - (SEC_HAS_CONTENTS | SEC_ALLOC - | SEC_LOAD | SEC_DATA))) - bfd_fatal ("bfd_set_section_flags"); - if (! bfd_set_symtab (abfd, sec->symbol_ptr_ptr, 1)) bfd_fatal ("bfd_set_symtab"); @@ -504,22 +518,22 @@ write_coff_file (const char *filename, const char *target, know the various offsets we will need. */ coff_bin_sizes (resources, &cwi); - /* Force the directory strings to be 32 bit aligned. Every other - structure is 32 bit aligned anyhow. */ - cwi.dirstrsize = (cwi.dirstrsize + 3) &~ 3; + /* Force the directory strings to be 64 bit aligned. Every other + structure is 64 bit aligned anyhow. */ + cwi.dirstrsize = (cwi.dirstrsize + 7) & ~7; /* Actually convert the resources to binary. */ coff_to_bin (resources, &cwi); - /* Add another 2 bytes to the directory strings if needed for + /* Add another few bytes to the directory strings if needed for alignment. */ - if ((cwi.dirstrs.length & 3) != 0) + if ((cwi.dirstrs.length & 7) != 0) { + rc_uint_type pad = 8 - (cwi.dirstrs.length & 7); bfd_byte *ex; - ex = coff_alloc (&cwi.dirstrs, 2); - ex[0] = 0; - ex[1] = 0; + ex = coff_alloc (& cwi.dirstrs, pad); + memset (ex, 0, pad); } /* Make sure that the data we built came out to the same size as we @@ -744,10 +758,10 @@ coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi) cwi->resources.last->next = d; cwi->resources.last = d; - cwi->resources.length += (d->length + 3) & ~3; + cwi->resources.length += (d->length + 7) & ~7; windres_put_32 (cwi->wrbfd, erd->size, d->length); - /* Force the next resource to have 32 bit alignment. */ - d->length = (d->length + 3) & ~3; + /* Force the next resource to have 64 bit alignment. */ + d->length = (d->length + 7) & ~7; }