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>
PR 26011

View 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;
}

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);
void bfd_set_filename (bfd *abfd, char *filename);
const char *bfd_set_filename (bfd *abfd, const char *filename);
/* Extracted from libbfd.c. */

View 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;

View 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)

View 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;
}

View 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;

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>
* 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
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;
}

View 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;
}

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
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)

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>
* 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_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);
}
}
}

View 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);
}
}
}