PR24955, libbfd terminating program on out of memory
authorAlan Modra <amodra@gmail.com>
Mon, 2 Sep 2019 06:43:05 +0000 (16:13 +0930)
committerAlan Modra <amodra@gmail.com>
Thu, 5 Sep 2019 02:03:34 +0000 (11:33 +0930)
This patch fixes the worst of the cases where libbfd might terminate
a program due to calling xstrdup or xmalloc.  I've also fixed some
error paths that didn't clean up properly.

PR 24955
* libbfd-in.h (bfd_strdup): New inline function.
* archive.c (_bfd_get_elt_at_filepos): Use bfd_strdup.  Close
bfd on error.
* elfcode.h (_bfd_elf_bfd_from_remote_memory): Use bfd_strdup.
* opncls.c (bfd_fopen): Use bfd_strdup.  Close fd and stream
on error.
(bfd_openstreamr): Use bfd_strdup.
(bfd_openr_iovec, bfd_openw, bfd_create): Likewise.
* plugin.c (try_load_plugin): Use bfd_malloc.
* libbfd.h: Regenerate.

bfd/ChangeLog
bfd/archive.c
bfd/elfcode.h
bfd/libbfd-in.h
bfd/libbfd.h
bfd/opncls.c
bfd/plugin.c

index f033af744362cbd90311ef642d6c348b7d97e31f..319ba5a57129c80fd77256d75c0d83e54bf49a74 100644 (file)
@@ -1,3 +1,17 @@
+2019-09-05  Alan Modra  <amodra@gmail.com>
+
+       PR 24955
+       * libbfd-in.h (bfd_strdup): New inline function.
+       * archive.c (_bfd_get_elt_at_filepos): Use bfd_strdup.  Close
+       bfd on error.
+       * elfcode.h (_bfd_elf_bfd_from_remote_memory): Use bfd_strdup.
+       * opncls.c (bfd_fopen): Use bfd_strdup.  Close fd and stream
+       on error.
+       (bfd_openstreamr): Use bfd_strdup.
+       (bfd_openr_iovec, bfd_openw, bfd_create): Likewise.
+       * plugin.c (try_load_plugin): Use bfd_malloc.
+       * libbfd.h: Regenerate.
+
 2019-09-02  Alan Modra  <amodra@gmail.com>
 
        PR 11983
index 690718e9494cae9cb552d6428e1c3109bcf3a4dd..ef71e8a79632c0d4306c091ab3d40a2460fc1e58 100644 (file)
@@ -728,7 +728,9 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
   else
     {
       n_bfd->origin = n_bfd->proxy_origin;
-      n_bfd->filename = xstrdup (filename);
+      n_bfd->filename = bfd_strdup (filename);
+      if (n_bfd->filename == NULL)
+       goto out;
     }
 
   n_bfd->arelt_data = new_areldata;
@@ -745,8 +747,10 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
       || _bfd_add_bfd_to_archive_cache (archive, filepos, n_bfd))
     return n_bfd;
 
+ out:
   free (new_areldata);
   n_bfd->arelt_data = NULL;
+  bfd_close (n_bfd);
   return NULL;
 }
 
index 9a73c3b71f52daa83b17350489c9275aca2bc3d2..625ae993df6a609ae982a788d1e7e3849f747e10 100644 (file)
@@ -1652,6 +1652,7 @@ NAME(_bfd_elf,bfd_from_remote_memory)
   bfd_vma high_offset;
   bfd_vma shdr_end;
   bfd_vma loadbase;
+  char *filename;
 
   /* Read in the ELF header in external format.  */
   err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr, sizeof x_ehdr);
@@ -1859,14 +1860,22 @@ 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)
     {
+      free (filename);
       free (bim);
       free (contents);
       return NULL;
     }
-  nbfd->filename = xstrdup ("<in-memory>");
+  nbfd->filename = filename;
   nbfd->xvec = templ->xvec;
   bim->size = high_offset;
   bim->buffer = contents;
index 7a97dfae19904ebc32831311818f117e29eb3e37..cac4d3b022e9273aefdd50640d2cbed064d1352a 100644 (file)
@@ -123,6 +123,15 @@ extern void *bfd_realloc2
 extern void *bfd_zmalloc2
   (bfd_size_type, bfd_size_type) ATTRIBUTE_HIDDEN;
 
+static inline char *
+bfd_strdup (const char *str)
+{
+  size_t len = strlen (str) + 1;
+  char *buf = bfd_malloc (len);
+  if (buf != NULL)
+    memcpy (buf, str, len);
+  return buf;
+}
 /* These routines allocate and free things on the BFD's objalloc.  */
 
 extern void *bfd_alloc2
index 13f4c5b4082b945dbc9c16ac11eaf56ff51bdc00..aabe247068e8c80b69b890c12bedb6e0ba8027f7 100644 (file)
@@ -128,6 +128,15 @@ extern void *bfd_realloc2
 extern void *bfd_zmalloc2
   (bfd_size_type, bfd_size_type) ATTRIBUTE_HIDDEN;
 
+static inline char *
+bfd_strdup (const char *str)
+{
+  size_t len = strlen (str) + 1;
+  char *buf = bfd_malloc (len);
+  if (buf != NULL)
+    memcpy (buf, str, len);
+  return buf;
+}
 /* These routines allocate and free things on the BFD's objalloc.  */
 
 extern void *bfd_alloc2
index b8cda411e608d13919639cfca361a1ec2cc6322d..07f89b9a4c152a1c69933cea62a84c5e2c4be3c3 100644 (file)
@@ -223,6 +223,8 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd)
   if (nbfd->iostream == NULL)
     {
       bfd_set_error (bfd_error_system_call);
+      if (fd != -1)
+       close (fd);
       _bfd_delete_bfd (nbfd);
       return NULL;
     }
@@ -231,7 +233,13 @@ 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 = xstrdup (filename);
+  nbfd->filename = bfd_strdup (filename);
+  if (nbfd->filename == NULL)
+    {
+      fclose (nbfd->iostream);
+      _bfd_delete_bfd (nbfd);
+      return NULL;
+    }
 
   /* Figure out whether the user is opening the file for reading,
      writing, or both, by looking at the MODE argument.  */
@@ -243,8 +251,9 @@ bfd_fopen (const char *filename, const char *target, const char *mode, int fd)
   else
     nbfd->direction = write_direction;
 
-  if (! bfd_cache_init (nbfd))
+  if (!bfd_cache_init (nbfd))
     {
+      fclose (nbfd->iostream);
       _bfd_delete_bfd (nbfd);
       return NULL;
     }
@@ -398,7 +407,12 @@ 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 = xstrdup (filename);
+  nbfd->filename = bfd_strdup (filename);
+  if (nbfd->filename == NULL)
+    {
+      _bfd_delete_bfd (nbfd);
+      return NULL;
+    }
   nbfd->direction = read_direction;
 
   if (! bfd_cache_init (nbfd))
@@ -594,7 +608,12 @@ 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 = xstrdup (filename);
+  nbfd->filename = bfd_strdup (filename);
+  if (nbfd->filename == NULL)
+    {
+      _bfd_delete_bfd (nbfd);
+      return NULL;
+    }
   nbfd->direction = read_direction;
 
   /* `open_p (...)' would get expanded by an the open(2) syscall macro.  */
@@ -661,7 +680,12 @@ 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 = xstrdup (filename);
+  nbfd->filename = bfd_strdup (filename);
+  if (nbfd->filename == NULL)
+    {
+      _bfd_delete_bfd (nbfd);
+      return NULL;
+    }
   nbfd->direction = write_direction;
 
   if (bfd_open_file (nbfd) == NULL)
@@ -801,7 +825,12 @@ 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 = xstrdup (filename);
+  nbfd->filename = bfd_strdup (filename);
+  if (nbfd->filename == NULL)
+    {
+      _bfd_delete_bfd (nbfd);
+      return NULL;
+    }
   if (templ)
     nbfd->xvec = templ->xvec;
   nbfd->direction = no_direction;
index 376e92cdb3e7117b464e2a5a941486d9a67ddc2d..5f760e9c4297131c581f9f568ea98c754ddd41ee 100644 (file)
@@ -262,7 +262,9 @@ try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p)
        }
     }
 
-  plugin_list_iter = (struct plugin_list_entry *) xmalloc (sizeof *plugin_list_iter);
+  plugin_list_iter = bfd_malloc (sizeof *plugin_list_iter);
+  if (plugin_list_iter == NULL)
+    return 0;
   plugin_list_iter->handle = plugin_handle;
   plugin_list_iter->claim_file = NULL;
   plugin_list_iter->next = plugin_list;