Automatic date update in version.in
[deliverable/binutils-gdb.git] / binutils / rescoff.c
index 525629dd88b01af75722b2ef6a05bb274ffde816..74a61a7be5d1fd0e87d31855de3c5a77dcf30fae 100644 (file)
@@ -1,6 +1,5 @@
 /* rescoff.c -- read and write resources in Windows COFF files.
-   Copyright 1997, 1998, 1999, 2000, 2003, 2005, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright (C) 1997-2016 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
    Rewritten by Kai Tietz, Onevision.
 
@@ -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 >= (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;
@@ -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);
 
@@ -501,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
@@ -741,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;
 }
This page took 0.076504 seconds and 4 git commands to generate.