Fixes for invalid memory accesses triggered by running windres on corrupt binaries.

PR binutils/17512
	* rcparse.y: Add checks to avoid integer divide by zero.
	* rescoff.c (read_coff_rsrc): Add check on the size of the
	resource section.
	(read_coff_res_dir): Add check on the nesting level.
	Check for resource names overrunning the buffer.
	* resrc.c (write_rc_messagetable): Update formatting.
	Add check of 'elen' being zero.
This commit is contained in:
Nick Clifton 2015-01-27 17:32:23 +00:00
parent 877a8638ba
commit 0897ec1581
4 changed files with 89 additions and 52 deletions

View file

@ -142,8 +142,14 @@ 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);
flaginfo.filename = filename;
@ -185,6 +191,13 @@ read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
rc_res_entry **pp;
const struct extern_res_entry *ere;
/* 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"));
@ -234,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 >= (bfd_byte *) ere || ers + j * 2 + 4 >= (bfd_byte *) ere)
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;