From 89bdc77eabf5ede68322f6e47e003c1dc45b9ccb Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 2 Sep 2019 16:13:05 +0930 Subject: [PATCH] PR24955, libbfd terminating program on out of memory 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 | 14 ++++++++++++++ bfd/archive.c | 6 +++++- bfd/elfcode.h | 11 ++++++++++- bfd/libbfd-in.h | 9 +++++++++ bfd/libbfd.h | 9 +++++++++ bfd/opncls.c | 41 +++++++++++++++++++++++++++++++++++------ bfd/plugin.c | 4 +++- 7 files changed, 85 insertions(+), 9 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f033af74436..319ba5a5712 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2019-09-05 Alan Modra + + 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 PR 11983 diff --git a/bfd/archive.c b/bfd/archive.c index 690718e9494..ef71e8a7963 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -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; } diff --git a/bfd/elfcode.h b/bfd/elfcode.h index 9a73c3b71f5..625ae993df6 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -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 (""); + 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 (""); + nbfd->filename = filename; nbfd->xvec = templ->xvec; bim->size = high_offset; bim->buffer = contents; diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h index 7a97dfae199..cac4d3b022e 100644 --- a/bfd/libbfd-in.h +++ b/bfd/libbfd-in.h @@ -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 diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 13f4c5b4082..aabe247068e 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -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 diff --git a/bfd/opncls.c b/bfd/opncls.c index b8cda411e60..07f89b9a4c1 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -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; diff --git a/bfd/plugin.c b/bfd/plugin.c index 376e92cdb3e..5f760e9c429 100644 --- a/bfd/plugin.c +++ b/bfd/plugin.c @@ -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; -- 2.30.2