PR25993, read of freed memory
authorAlan Modra <amodra@gmail.com>
Tue, 19 May 2020 03:28:59 +0000 (12:58 +0930)
committerAlan Modra <amodra@gmail.com>
Wed, 20 May 2020 02:13:50 +0000 (11:43 +0930)
ldmain.c:add_archive_element copies file name pointers from the bfd to
a lang_input_statement_type.
  input->filename = abfd->filename;
  input->local_sym_name = abfd->filename;
This results in stale pointers when twiddling the bfd filename in
places like the pe ld after_open.  So don't free the bfd filename,
and make copies using bfd_alloc memory that won't result in small
memory leaks that annoy memory checkers.

PR 25993
bfd/
* archive.c (_bfd_get_elt_at_filepos): Don't strdup filename,
use bfd_set_filename.
* elfcode.h (_bfd_elf_bfd_from_remote_memory): Likewise.
* mach-o.c (bfd_mach_o_fat_member_init): Likewise.
* opncls.c (bfd_fopen, bfd_openstreamr, bfd_openr_iovec, bfd_openw),
(bfd_create): Likewise.
(_bfd_delete_bfd): Don't free filename.
(bfd_set_filename): Copy filename param to bfd_alloc'd memory,
return pointer to the copy or NULL on alloc fail.
* vms-lib.c (_bfd_vms_lib_get_module): Free newname and test
result of bfd_set_filename.
* bfd-in2.h: Regenerate.
gdb/
* solib-darwin.c (darwin_bfd_open): Don't strdup pathname for
bfd_set_filename.
* solib-aix.c (solib_aix_bfd_open): Use std::string for name
passed to bfd_set_filename.
* symfile-mem.c (add_vsyscall_page): Likewise for string
passed to symbol_file_add_from_memory.
(symbol_file_add_from_memory): Make name param a const char* and
don't strdup.
ld/
* emultempl/pe.em (gld_${EMULATION_NAME}_after_open): Don't copy
other_bfd_filename for bfd_set_filename, and test result of
bfd_set_filename call.  Don't create a new is->filename, simply
copy from bfd filename.  Free new_name after bfd_set_filename.
* emultempl/pep.em (gld_${EMULATION_NAME}_after_open): Likewise.

14 files changed:
bfd/ChangeLog
bfd/archive.c
bfd/bfd-in2.h
bfd/elfcode.h
bfd/mach-o.c
bfd/opncls.c
bfd/vms-lib.c
gdb/ChangeLog
gdb/solib-aix.c
gdb/solib-darwin.c
gdb/symfile-mem.c
ld/ChangeLog
ld/emultempl/pe.em
ld/emultempl/pep.em

index 6d3673d14c156df81f4ad15c83ae2191cc5e0f5f..eb6191c534a7806f95b228787882e06d68f2a452 100644 (file)
@@ -1,3 +1,19 @@
+2020-05-20  Alan Modra  <amodra@gmail.com>
+
+       PR 25993
+       * archive.c (_bfd_get_elt_at_filepos): Don't strdup filename,
+       use bfd_set_filename.
+       * elfcode.h (_bfd_elf_bfd_from_remote_memory): Likewise.
+       * mach-o.c (bfd_mach_o_fat_member_init): Likewise.
+       * opncls.c (bfd_fopen, bfd_openstreamr, bfd_openr_iovec, bfd_openw),
+       (bfd_create): Likewise.
+       (_bfd_delete_bfd): Don't free filename.
+       (bfd_set_filename): Copy filename param to bfd_alloc'd memory,
+       return pointer to the copy or NULL on alloc fail.
+       * vms-lib.c (_bfd_vms_lib_get_module): Free newname and test
+       result of bfd_set_filename.
+       * bfd-in2.h: Regenerate.
+
 2020-05-20  Alan Modra  <amodra@gmail.com>
 
        PR 26011
index ff64727c44801e1f37d7eacbf8bbd8a0afdfec49..13229777448fe8ee9238eb01c08913e9aeb77c11 100644 (file)
@@ -737,8 +737,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
   else
     {
       n_bfd->origin = n_bfd->proxy_origin;
-      n_bfd->filename = bfd_strdup (filename);
-      if (n_bfd->filename == NULL)
+      if (!bfd_set_filename (n_bfd, filename))
        goto out;
     }
 
index ec23fd49870862c9d2a7c3457884d2119a19ec32..d5c28a5ee25b9549fec8bcc029e2ab0871dbaf21 100644 (file)
@@ -643,7 +643,7 @@ bfd_boolean bfd_fill_in_gnu_debuglink_section
 
 char *bfd_follow_build_id_debuglink (bfd *abfd, const char *dir);
 
-void bfd_set_filename (bfd *abfd, char *filename);
+const char *bfd_set_filename (bfd *abfd, const char *filename);
 
 /* Extracted from libbfd.c.  */
 
index 68db3e9ee3da8888ad7d8429457c545f68edbe17..5e6b2a430f8fe110d152a457b402f8073eb0fb28 100644 (file)
@@ -1680,7 +1680,6 @@ NAME(_bfd_elf,bfd_from_remote_memory)
   bfd_vma high_offset;
   bfd_vma shdr_end;
   bfd_vma loadbase;  /* Bytes.  */
-  char *filename;
   size_t amt;
   unsigned int opb = bfd_octets_per_byte (templ, NULL);
 
@@ -1894,22 +1893,14 @@ NAME(_bfd_elf,bfd_from_remote_memory)
       free (contents);
       return NULL;
     }
-  filename = bfd_strdup ("<in-memory>");
-  if (filename == NULL)
-    {
-      free (bim);
-      free (contents);
-      return NULL;
-    }
   nbfd = _bfd_new_bfd ();
-  if (nbfd == NULL)
+  if (nbfd == NULL
+      || !bfd_set_filename (nbfd, "<in-memory>"))
     {
-      free (filename);
       free (bim);
       free (contents);
       return NULL;
     }
-  nbfd->filename = filename;
   nbfd->xvec = templ->xvec;
   bim->size = high_offset;
   bim->buffer = contents;
index 33bd81e121eb0483dd90d8ef3088f455eff41b1f..43fa56cb5860504788ec6ad60a59f40d3ba932ac 100644 (file)
@@ -5573,26 +5573,23 @@ bfd_mach_o_fat_member_init (bfd *abfd,
   struct areltdata *areltdata;
   /* Create the member filename. Use ARCH_NAME.  */
   const bfd_arch_info_type *ap = bfd_lookup_arch (arch_type, arch_subtype);
-  char *filename;
+  const char *filename;
 
   if (ap)
     {
       /* Use the architecture name if known.  */
-      filename = bfd_strdup (ap->printable_name);
-      if (filename == NULL)
-       return FALSE;
+      filename = bfd_set_filename (abfd, ap->printable_name);
     }
   else
     {
       /* Forge a uniq id.  */
-      const size_t namelen = 2 + 8 + 1 + 2 + 8 + 1;
-      filename = bfd_malloc (namelen);
-      if (filename == NULL)
-       return FALSE;
-      snprintf (filename, namelen, "0x%lx-0x%lx",
+      char buf[2 + 8 + 1 + 2 + 8 + 1];
+      snprintf (buf, sizeof (buf), "0x%lx-0x%lx",
                entry->cputype, entry->cpusubtype);
+      filename = bfd_set_filename (abfd, buf);
     }
-  bfd_set_filename (abfd, filename);
+  if (!filename)
+    return FALSE;
 
   areltdata = bfd_zmalloc (sizeof (struct areltdata));
   if (areltdata == NULL)
index 5d3437d38225b7c9b47299adfa87a9d5b6bc02bb..78b2ad7dd759abc72776fa3375c0d8e9462a4925 100644 (file)
@@ -126,7 +126,6 @@ _bfd_delete_bfd (bfd *abfd)
       objalloc_free ((struct objalloc *) abfd->memory);
     }
 
-  free ((char *) bfd_get_filename (abfd));
   free (abfd->arelt_data);
   free (abfd);
 }
@@ -232,8 +231,7 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd)
 
   /* PR 11983: Do not cache the original filename, but
      rather make a copy - the original might go away.  */
-  nbfd->filename = bfd_strdup (filename);
-  if (nbfd->filename == NULL)
+  if (!bfd_set_filename (nbfd, filename))
     {
       fclose (nbfd->iostream);
       _bfd_delete_bfd (nbfd);
@@ -406,8 +404,7 @@ bfd_openstreamr (const char *filename, const char *target, void *streamarg)
   nbfd->iostream = stream;
   /* PR 11983: Do not cache the original filename, but
      rather make a copy - the original might go away.  */
-  nbfd->filename = bfd_strdup (filename);
-  if (nbfd->filename == NULL)
+  if (!bfd_set_filename (nbfd, filename))
     {
       _bfd_delete_bfd (nbfd);
       return NULL;
@@ -607,8 +604,7 @@ bfd_openr_iovec (const char *filename, const char *target,
 
   /* PR 11983: Do not cache the original filename, but
      rather make a copy - the original might go away.  */
-  nbfd->filename = bfd_strdup (filename);
-  if (nbfd->filename == NULL)
+  if (!bfd_set_filename (nbfd, filename))
     {
       _bfd_delete_bfd (nbfd);
       return NULL;
@@ -679,8 +675,7 @@ bfd_openw (const char *filename, const char *target)
 
   /* PR 11983: Do not cache the original filename, but
      rather make a copy - the original might go away.  */
-  nbfd->filename = bfd_strdup (filename);
-  if (nbfd->filename == NULL)
+  if (!bfd_set_filename (nbfd, filename))
     {
       _bfd_delete_bfd (nbfd);
       return NULL;
@@ -824,8 +819,7 @@ bfd_create (const char *filename, bfd *templ)
     return NULL;
   /* PR 11983: Do not cache the original filename, but
      rather make a copy - the original might go away.  */
-  nbfd->filename = bfd_strdup (filename);
-  if (nbfd->filename == NULL)
+  if (!bfd_set_filename (nbfd, filename))
     {
       _bfd_delete_bfd (nbfd);
       return NULL;
@@ -2040,17 +2034,23 @@ FUNCTION
        bfd_set_filename
 
 SYNOPSIS
-       void bfd_set_filename (bfd *abfd, char *filename);
+       const char *bfd_set_filename (bfd *abfd, const char *filename);
 
 DESCRIPTION
-       Set the filename of @var{abfd}.  The old filename, if any, is freed.
-       @var{filename} must be allocated using @code{xmalloc}.  After
-       this call, it is owned @var{abfd}.
+       Set the filename of @var{abfd}, copying the FILENAME parameter to
+       bfd_alloc'd memory owned by @var{abfd}.  Returns a pointer the
+       newly allocated name, or NULL if the allocation failed.
 */
 
-void
-bfd_set_filename (bfd *abfd, char *filename)
+const char *
+bfd_set_filename (bfd *abfd, const char *filename)
 {
-  free ((char *) abfd->filename);
-  abfd->filename = filename;
+  size_t len = strlen (filename) + 1;
+  char *n = bfd_alloc (abfd, len);
+  if (n)
+    {
+      memcpy (n, filename, len);
+      abfd->filename = n;
+    }
+  return n;
 }
index 9504cf4976c0e839607be453d879cc62443ca329..6a8a76ecb034bb9b155dee595d07ca658e2c0ba6 100644 (file)
@@ -1452,6 +1452,12 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
       break;
     }
   bfd_set_filename (res, newname);
+  free (newname);
+  if (bfd_get_filename (res) == NULL)
+    {
+      bfd_close (res);
+      return NULL;
+    }
 
   tdata->cache[modidx] = res;
 
index 9799e1ed4a97c7aefadf2a18770238fcd36bc44b..85a016bd6b7acff477083feac12110fbd65b1df1 100644 (file)
@@ -1,3 +1,15 @@
+2020-05-20  Alan Modra  <amodra@gmail.com>
+
+       PR 25993
+       * solib-darwin.c (darwin_bfd_open): Don't strdup pathname for
+       bfd_set_filename.
+       * solib-aix.c (solib_aix_bfd_open): Use std::string for name
+       passed to bfd_set_filename.
+       * symfile-mem.c (add_vsyscall_page): Likewise for string
+       passed to symbol_file_add_from_memory.
+       (symbol_file_add_from_memory): Make name param a const char* and
+       don't strdup.
+
 2020-05-20  Alan Modra  <amodra@gmail.com>
 
        * coff-pe-read.c (read_pe_exported_syms): Use bfd_get_filename
index 5da1214a2564867be86ea58ce50f660aa4e71bc1..344c1f57600310675200a4023b9f84707c073dcd 100644 (file)
@@ -637,10 +637,10 @@ solib_aix_bfd_open (const char *pathname)
      along with appended parenthesized member name in order to allow commands
      listing all shared libraries to display.  Otherwise, we would only be
      displaying the name of the archive member object.  */
-  bfd_set_filename (object_bfd.get (),
-                   xstrprintf ("%s%s",
-                               bfd_get_filename (archive_bfd.get ()),
-                               sep));
+  std::string fname = string_printf ("%s%s",
+                                    bfd_get_filename (archive_bfd.get ()),
+                                    sep);
+  bfd_set_filename (object_bfd.get (), fname.c_str ());
 
   return object_bfd;
 }
index e740a41fa4f6d0d67a5bfe81af66ce8a037cd439..ee0483d2c87a2702beb91c343a5bbf5e3ba23dde 100644 (file)
@@ -662,7 +662,7 @@ darwin_bfd_open (const char *pathname)
   /* The current filename for fat-binary BFDs is a name generated
      by BFD, usually a string containing the name of the architecture.
      Reset its value to the actual filename.  */
-  bfd_set_filename (res.get (), xstrdup (pathname));
+  bfd_set_filename (res.get (), pathname);
 
   return res;
 }
index e2d2e43d7fa7ba5566795a535070e4bb32ce66a3..78096fcbae19e9691da3e5aa6c6726dfebd7db83 100644 (file)
@@ -78,11 +78,10 @@ target_read_memory_bfd (bfd_vma memaddr, bfd_byte *myaddr, bfd_size_type len)
    and read its in-core symbols out of inferior memory.  SIZE, if
    non-zero, is the known size of the object.  TEMPL is a bfd
    representing the target's format.  NAME is the name to use for this
-   symbol file in messages; it can be NULL or a malloc-allocated string
-   which will be attached to the BFD.  */
+   symbol file in messages; it can be NULL.  */
 static struct objfile *
 symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr,
-                            size_t size, char *name, int from_tty)
+                            size_t size, const char *name, int from_tty)
 {
   struct objfile *objf;
   struct bfd *nbfd;
@@ -102,7 +101,7 @@ symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr,
   gdb_bfd_ref_ptr nbfd_holder = gdb_bfd_ref_ptr::new_reference (nbfd);
 
   if (name == NULL)
-    name = xstrdup ("shared object read from target memory");
+    name = "shared object read from target memory";
   bfd_set_filename (nbfd, name);
 
   if (!bfd_check_format (nbfd, bfd_object))
@@ -183,8 +182,9 @@ add_vsyscall_page (struct target_ops *target, int from_tty)
          return;
        }
 
-      char *name = xstrprintf ("system-supplied DSO at %s",
-                              paddress (target_gdbarch (), vsyscall_range.start));
+      std::string name = string_printf ("system-supplied DSO at %s",
+                                       paddress (target_gdbarch (),
+                                                 vsyscall_range.start));
       try
        {
          /* Pass zero for FROM_TTY, because the action of loading the
@@ -193,7 +193,7 @@ add_vsyscall_page (struct target_ops *target, int from_tty)
          symbol_file_add_from_memory (bfd,
                                       vsyscall_range.start,
                                       vsyscall_range.length,
-                                      name,
+                                      name.c_str (),
                                       0 /* from_tty */);
        }
       catch (const gdb_exception &ex)
index cf566b3255911431281313d4706f5fd1dfee57d5..b4ee76c2606d490d2f68a119f0045e33ceb25adb 100644 (file)
@@ -1,3 +1,12 @@
+2020-05-20  Alan Modra  <amodra@gmail.com>
+
+       PR 25993
+       * emultempl/pe.em (gld_${EMULATION_NAME}_after_open): Don't copy
+       other_bfd_filename for bfd_set_filename, and test result of
+       bfd_set_filename call.  Don't create a new is->filename, simply
+       copy from bfd filename.  Free new_name after bfd_set_filename.
+       * emultempl/pep.em (gld_${EMULATION_NAME}_after_open): Likewise.
+
 2020-05-19  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
 
        * testsuite/ld-aarch64/aarch64-elf.exp: New test
index fe65d2b266e5c49ad521a5a49078061e81fef146..8c5ee762334b387ef9e35a5a9aaea43267c1453f 100644 (file)
@@ -1523,7 +1523,6 @@ gld_${EMULATION_NAME}_after_open (void)
                        struct bfd_symbol *s;
                        struct bfd_link_hash_entry * blhe;
                        const char *other_bfd_filename;
-                       char *n;
 
                        s = (relocs[i]->sym_ptr_ptr)[0];
 
@@ -1550,9 +1549,9 @@ gld_${EMULATION_NAME}_after_open (void)
                          continue;
 
                        /* Rename this implib to match the other one.  */
-                       n = xmalloc (strlen (other_bfd_filename) + 1);
-                       strcpy (n, other_bfd_filename);
-                       bfd_set_filename (is->the_bfd->my_archive, n);
+                       if (!bfd_set_filename (is->the_bfd->my_archive,
+                                              other_bfd_filename))
+                         einfo ("%F%P: %pB: %E\n", is->the_bfd);
                      }
 
                    free (relocs);
@@ -1655,28 +1654,14 @@ gld_${EMULATION_NAME}_after_open (void)
                else /* sentinel */
                  seq = 'c';
 
-               /* PR 25993: It is possible that is->the_bfd-filename == is->filename.
-                  In which case calling bfd_set_filename on one will free the memory
-                  pointed to by the other.  */
-               if (is->filename == bfd_get_filename (is->the_bfd))
-                 {
-                   new_name = xmalloc (strlen (is->filename) + 3);
-                   sprintf (new_name, "%s.%c", is->filename, seq);
-                   bfd_set_filename (is->the_bfd, new_name);
-                   is->filename = new_name;
-                 }
-               else
-                 {
-                   new_name
-                     = xmalloc (strlen (bfd_get_filename (is->the_bfd)) + 3);
-                   sprintf (new_name, "%s.%c",
-                            bfd_get_filename (is->the_bfd), seq);
-                   bfd_set_filename (is->the_bfd, new_name);
-
-                   new_name = xmalloc (strlen (is->filename) + 3);
-                   sprintf (new_name, "%s.%c", is->filename, seq);
-                   is->filename = new_name;
-                 }
+               new_name
+                 = xmalloc (strlen (bfd_get_filename (is->the_bfd)) + 3);
+               sprintf (new_name, "%s.%c",
+                        bfd_get_filename (is->the_bfd), seq);
+               is->filename = bfd_set_filename (is->the_bfd, new_name);
+               free (new_name);
+               if (!is->filename)
+                 einfo ("%F%P: %pB: %E\n", is->the_bfd);
              }
          }
       }
index 699b86501c55a325d8348420dd34817f41364341..ea8e768ea93f7825e9546d08ff029286ec26ddf5 100644 (file)
@@ -1491,7 +1491,6 @@ gld_${EMULATION_NAME}_after_open (void)
                        struct bfd_symbol *s;
                        struct bfd_link_hash_entry * blhe;
                        const char *other_bfd_filename;
-                       char *n;
 
                        s = (relocs[i]->sym_ptr_ptr)[0];
 
@@ -1518,9 +1517,9 @@ gld_${EMULATION_NAME}_after_open (void)
                          continue;
 
                        /* Rename this implib to match the other one.  */
-                       n = xmalloc (strlen (other_bfd_filename) + 1);
-                       strcpy (n, other_bfd_filename);
-                       bfd_set_filename (is->the_bfd->my_archive, n);
+                       if (!bfd_set_filename (is->the_bfd->my_archive,
+                                              other_bfd_filename))
+                         einfo ("%F%P: %pB: %E\n", is->the_bfd);
                      }
 
                    free (relocs);
@@ -1623,28 +1622,14 @@ gld_${EMULATION_NAME}_after_open (void)
                else /* sentinel */
                  seq = 'c';
 
-               /* PR 25993: It is possible that is->the_bfd-filename == is->filename.
-                  In which case calling bfd_set_filename on one will free the memory
-                  pointed to by the other.  */
-               if (is->filename == bfd_get_filename (is->the_bfd))
-                 {
-                   new_name = xmalloc (strlen (is->filename) + 3);
-                   sprintf (new_name, "%s.%c", is->filename, seq);
-                   bfd_set_filename (is->the_bfd, new_name);
-                   is->filename = new_name;
-                 }
-               else
-                 {
-                   new_name
-                     = xmalloc (strlen (bfd_get_filename (is->the_bfd)) + 3);
-                   sprintf (new_name, "%s.%c",
-                            bfd_get_filename (is->the_bfd), seq);
-                   bfd_set_filename (is->the_bfd, new_name);
-
-                   new_name = xmalloc (strlen (is->filename) + 3);
-                   sprintf (new_name, "%s.%c", is->filename, seq);
-                   is->filename = new_name;
-                 }
+               new_name
+                 = xmalloc (strlen (bfd_get_filename (is->the_bfd)) + 3);
+               sprintf (new_name, "%s.%c",
+                        bfd_get_filename (is->the_bfd), seq);
+               is->filename = bfd_set_filename (is->the_bfd, new_name);
+               free (new_name);
+               if (!is->filename)
+                 einfo ("%F%P: %pB: %E\n", is->the_bfd);
              }
          }
       }