PR25993, read of freed memory

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.
This commit is contained in:
Alan Modra 2020-05-19 12:58:59 +09:30
parent 84f800117f
commit 7b958a48e1
14 changed files with 107 additions and 107 deletions

View 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> 2020-05-20 Alan Modra <amodra@gmail.com>
PR 26011 PR 26011

View File

@ -737,8 +737,7 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
else else
{ {
n_bfd->origin = n_bfd->proxy_origin; n_bfd->origin = n_bfd->proxy_origin;
n_bfd->filename = bfd_strdup (filename); if (!bfd_set_filename (n_bfd, filename))
if (n_bfd->filename == NULL)
goto out; goto out;
} }

View File

@ -643,7 +643,7 @@ bfd_boolean bfd_fill_in_gnu_debuglink_section
char *bfd_follow_build_id_debuglink (bfd *abfd, const char *dir); 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. */ /* Extracted from libbfd.c. */

View File

@ -1680,7 +1680,6 @@ NAME(_bfd_elf,bfd_from_remote_memory)
bfd_vma high_offset; bfd_vma high_offset;
bfd_vma shdr_end; bfd_vma shdr_end;
bfd_vma loadbase; /* Bytes. */ bfd_vma loadbase; /* Bytes. */
char *filename;
size_t amt; size_t amt;
unsigned int opb = bfd_octets_per_byte (templ, NULL); unsigned int opb = bfd_octets_per_byte (templ, NULL);
@ -1894,22 +1893,14 @@ NAME(_bfd_elf,bfd_from_remote_memory)
free (contents); free (contents);
return NULL; return NULL;
} }
filename = bfd_strdup ("<in-memory>");
if (filename == NULL)
{
free (bim);
free (contents);
return NULL;
}
nbfd = _bfd_new_bfd (); nbfd = _bfd_new_bfd ();
if (nbfd == NULL) if (nbfd == NULL
|| !bfd_set_filename (nbfd, "<in-memory>"))
{ {
free (filename);
free (bim); free (bim);
free (contents); free (contents);
return NULL; return NULL;
} }
nbfd->filename = filename;
nbfd->xvec = templ->xvec; nbfd->xvec = templ->xvec;
bim->size = high_offset; bim->size = high_offset;
bim->buffer = contents; bim->buffer = contents;

View File

@ -5573,26 +5573,23 @@ bfd_mach_o_fat_member_init (bfd *abfd,
struct areltdata *areltdata; struct areltdata *areltdata;
/* Create the member filename. Use ARCH_NAME. */ /* Create the member filename. Use ARCH_NAME. */
const bfd_arch_info_type *ap = bfd_lookup_arch (arch_type, arch_subtype); const bfd_arch_info_type *ap = bfd_lookup_arch (arch_type, arch_subtype);
char *filename; const char *filename;
if (ap) if (ap)
{ {
/* Use the architecture name if known. */ /* Use the architecture name if known. */
filename = bfd_strdup (ap->printable_name); filename = bfd_set_filename (abfd, ap->printable_name);
if (filename == NULL)
return FALSE;
} }
else else
{ {
/* Forge a uniq id. */ /* Forge a uniq id. */
const size_t namelen = 2 + 8 + 1 + 2 + 8 + 1; char buf[2 + 8 + 1 + 2 + 8 + 1];
filename = bfd_malloc (namelen); snprintf (buf, sizeof (buf), "0x%lx-0x%lx",
if (filename == NULL)
return FALSE;
snprintf (filename, namelen, "0x%lx-0x%lx",
entry->cputype, entry->cpusubtype); 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)); areltdata = bfd_zmalloc (sizeof (struct areltdata));
if (areltdata == NULL) if (areltdata == NULL)

View File

@ -126,7 +126,6 @@ _bfd_delete_bfd (bfd *abfd)
objalloc_free ((struct objalloc *) abfd->memory); objalloc_free ((struct objalloc *) abfd->memory);
} }
free ((char *) bfd_get_filename (abfd));
free (abfd->arelt_data); free (abfd->arelt_data);
free (abfd); 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 /* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */ rather make a copy - the original might go away. */
nbfd->filename = bfd_strdup (filename); if (!bfd_set_filename (nbfd, filename))
if (nbfd->filename == NULL)
{ {
fclose (nbfd->iostream); fclose (nbfd->iostream);
_bfd_delete_bfd (nbfd); _bfd_delete_bfd (nbfd);
@ -406,8 +404,7 @@ bfd_openstreamr (const char *filename, const char *target, void *streamarg)
nbfd->iostream = stream; nbfd->iostream = stream;
/* PR 11983: Do not cache the original filename, but /* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */ rather make a copy - the original might go away. */
nbfd->filename = bfd_strdup (filename); if (!bfd_set_filename (nbfd, filename))
if (nbfd->filename == NULL)
{ {
_bfd_delete_bfd (nbfd); _bfd_delete_bfd (nbfd);
return NULL; return NULL;
@ -607,8 +604,7 @@ bfd_openr_iovec (const char *filename, const char *target,
/* PR 11983: Do not cache the original filename, but /* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */ rather make a copy - the original might go away. */
nbfd->filename = bfd_strdup (filename); if (!bfd_set_filename (nbfd, filename))
if (nbfd->filename == NULL)
{ {
_bfd_delete_bfd (nbfd); _bfd_delete_bfd (nbfd);
return NULL; return NULL;
@ -679,8 +675,7 @@ bfd_openw (const char *filename, const char *target)
/* PR 11983: Do not cache the original filename, but /* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */ rather make a copy - the original might go away. */
nbfd->filename = bfd_strdup (filename); if (!bfd_set_filename (nbfd, filename))
if (nbfd->filename == NULL)
{ {
_bfd_delete_bfd (nbfd); _bfd_delete_bfd (nbfd);
return NULL; return NULL;
@ -824,8 +819,7 @@ bfd_create (const char *filename, bfd *templ)
return NULL; return NULL;
/* PR 11983: Do not cache the original filename, but /* PR 11983: Do not cache the original filename, but
rather make a copy - the original might go away. */ rather make a copy - the original might go away. */
nbfd->filename = bfd_strdup (filename); if (!bfd_set_filename (nbfd, filename))
if (nbfd->filename == NULL)
{ {
_bfd_delete_bfd (nbfd); _bfd_delete_bfd (nbfd);
return NULL; return NULL;
@ -2040,17 +2034,23 @@ FUNCTION
bfd_set_filename bfd_set_filename
SYNOPSIS SYNOPSIS
void bfd_set_filename (bfd *abfd, char *filename); const char *bfd_set_filename (bfd *abfd, const char *filename);
DESCRIPTION DESCRIPTION
Set the filename of @var{abfd}. The old filename, if any, is freed. Set the filename of @var{abfd}, copying the FILENAME parameter to
@var{filename} must be allocated using @code{xmalloc}. After bfd_alloc'd memory owned by @var{abfd}. Returns a pointer the
this call, it is owned @var{abfd}. newly allocated name, or NULL if the allocation failed.
*/ */
void const char *
bfd_set_filename (bfd *abfd, char *filename) bfd_set_filename (bfd *abfd, const char *filename)
{ {
free ((char *) abfd->filename); size_t len = strlen (filename) + 1;
abfd->filename = filename; char *n = bfd_alloc (abfd, len);
if (n)
{
memcpy (n, filename, len);
abfd->filename = n;
}
return n;
} }

View File

@ -1452,6 +1452,12 @@ _bfd_vms_lib_get_module (bfd *abfd, unsigned int modidx)
break; break;
} }
bfd_set_filename (res, newname); bfd_set_filename (res, newname);
free (newname);
if (bfd_get_filename (res) == NULL)
{
bfd_close (res);
return NULL;
}
tdata->cache[modidx] = res; tdata->cache[modidx] = res;

View 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> 2020-05-20 Alan Modra <amodra@gmail.com>
* coff-pe-read.c (read_pe_exported_syms): Use bfd_get_filename * coff-pe-read.c (read_pe_exported_syms): Use bfd_get_filename

View File

@ -637,10 +637,10 @@ solib_aix_bfd_open (const char *pathname)
along with appended parenthesized member name in order to allow commands along with appended parenthesized member name in order to allow commands
listing all shared libraries to display. Otherwise, we would only be listing all shared libraries to display. Otherwise, we would only be
displaying the name of the archive member object. */ displaying the name of the archive member object. */
bfd_set_filename (object_bfd.get (), std::string fname = string_printf ("%s%s",
xstrprintf ("%s%s", bfd_get_filename (archive_bfd.get ()),
bfd_get_filename (archive_bfd.get ()), sep);
sep)); bfd_set_filename (object_bfd.get (), fname.c_str ());
return object_bfd; return object_bfd;
} }

View File

@ -662,7 +662,7 @@ darwin_bfd_open (const char *pathname)
/* The current filename for fat-binary BFDs is a name generated /* The current filename for fat-binary BFDs is a name generated
by BFD, usually a string containing the name of the architecture. by BFD, usually a string containing the name of the architecture.
Reset its value to the actual filename. */ Reset its value to the actual filename. */
bfd_set_filename (res.get (), xstrdup (pathname)); bfd_set_filename (res.get (), pathname);
return res; return res;
} }

View 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 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 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 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 symbol file in messages; it can be NULL. */
which will be attached to the BFD. */
static struct objfile * static struct objfile *
symbol_file_add_from_memory (struct bfd *templ, CORE_ADDR addr, 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 objfile *objf;
struct bfd *nbfd; 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); gdb_bfd_ref_ptr nbfd_holder = gdb_bfd_ref_ptr::new_reference (nbfd);
if (name == NULL) if (name == NULL)
name = xstrdup ("shared object read from target memory"); name = "shared object read from target memory";
bfd_set_filename (nbfd, name); bfd_set_filename (nbfd, name);
if (!bfd_check_format (nbfd, bfd_object)) if (!bfd_check_format (nbfd, bfd_object))
@ -183,8 +182,9 @@ add_vsyscall_page (struct target_ops *target, int from_tty)
return; return;
} }
char *name = xstrprintf ("system-supplied DSO at %s", std::string name = string_printf ("system-supplied DSO at %s",
paddress (target_gdbarch (), vsyscall_range.start)); paddress (target_gdbarch (),
vsyscall_range.start));
try try
{ {
/* Pass zero for FROM_TTY, because the action of loading the /* 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, symbol_file_add_from_memory (bfd,
vsyscall_range.start, vsyscall_range.start,
vsyscall_range.length, vsyscall_range.length,
name, name.c_str (),
0 /* from_tty */); 0 /* from_tty */);
} }
catch (const gdb_exception &ex) catch (const gdb_exception &ex)

View 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> 2020-05-19 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* testsuite/ld-aarch64/aarch64-elf.exp: New test * testsuite/ld-aarch64/aarch64-elf.exp: New test

View File

@ -1523,7 +1523,6 @@ gld_${EMULATION_NAME}_after_open (void)
struct bfd_symbol *s; struct bfd_symbol *s;
struct bfd_link_hash_entry * blhe; struct bfd_link_hash_entry * blhe;
const char *other_bfd_filename; const char *other_bfd_filename;
char *n;
s = (relocs[i]->sym_ptr_ptr)[0]; s = (relocs[i]->sym_ptr_ptr)[0];
@ -1550,9 +1549,9 @@ gld_${EMULATION_NAME}_after_open (void)
continue; continue;
/* Rename this implib to match the other one. */ /* Rename this implib to match the other one. */
n = xmalloc (strlen (other_bfd_filename) + 1); if (!bfd_set_filename (is->the_bfd->my_archive,
strcpy (n, other_bfd_filename); other_bfd_filename))
bfd_set_filename (is->the_bfd->my_archive, n); einfo ("%F%P: %pB: %E\n", is->the_bfd);
} }
free (relocs); free (relocs);
@ -1655,28 +1654,14 @@ gld_${EMULATION_NAME}_after_open (void)
else /* sentinel */ else /* sentinel */
seq = 'c'; seq = 'c';
/* PR 25993: It is possible that is->the_bfd-filename == is->filename. new_name
In which case calling bfd_set_filename on one will free the memory = xmalloc (strlen (bfd_get_filename (is->the_bfd)) + 3);
pointed to by the other. */ sprintf (new_name, "%s.%c",
if (is->filename == bfd_get_filename (is->the_bfd)) bfd_get_filename (is->the_bfd), seq);
{ is->filename = bfd_set_filename (is->the_bfd, new_name);
new_name = xmalloc (strlen (is->filename) + 3); free (new_name);
sprintf (new_name, "%s.%c", is->filename, seq); if (!is->filename)
bfd_set_filename (is->the_bfd, new_name); einfo ("%F%P: %pB: %E\n", is->the_bfd);
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;
}
} }
} }
} }

View File

@ -1491,7 +1491,6 @@ gld_${EMULATION_NAME}_after_open (void)
struct bfd_symbol *s; struct bfd_symbol *s;
struct bfd_link_hash_entry * blhe; struct bfd_link_hash_entry * blhe;
const char *other_bfd_filename; const char *other_bfd_filename;
char *n;
s = (relocs[i]->sym_ptr_ptr)[0]; s = (relocs[i]->sym_ptr_ptr)[0];
@ -1518,9 +1517,9 @@ gld_${EMULATION_NAME}_after_open (void)
continue; continue;
/* Rename this implib to match the other one. */ /* Rename this implib to match the other one. */
n = xmalloc (strlen (other_bfd_filename) + 1); if (!bfd_set_filename (is->the_bfd->my_archive,
strcpy (n, other_bfd_filename); other_bfd_filename))
bfd_set_filename (is->the_bfd->my_archive, n); einfo ("%F%P: %pB: %E\n", is->the_bfd);
} }
free (relocs); free (relocs);
@ -1623,28 +1622,14 @@ gld_${EMULATION_NAME}_after_open (void)
else /* sentinel */ else /* sentinel */
seq = 'c'; seq = 'c';
/* PR 25993: It is possible that is->the_bfd-filename == is->filename. new_name
In which case calling bfd_set_filename on one will free the memory = xmalloc (strlen (bfd_get_filename (is->the_bfd)) + 3);
pointed to by the other. */ sprintf (new_name, "%s.%c",
if (is->filename == bfd_get_filename (is->the_bfd)) bfd_get_filename (is->the_bfd), seq);
{ is->filename = bfd_set_filename (is->the_bfd, new_name);
new_name = xmalloc (strlen (is->filename) + 3); free (new_name);
sprintf (new_name, "%s.%c", is->filename, seq); if (!is->filename)
bfd_set_filename (is->the_bfd, new_name); einfo ("%F%P: %pB: %E\n", is->the_bfd);
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;
}
} }
} }
} }