asan: readelf leak in hppa_process_unwind

This extracts code reading symbol tables into a common function that
tidies up after errors.  I've also changed an error reporting multiple
string tables to an error on multiple symbol tables.

	* readelf.c (get_symbols): New function.
	(process_relocs, ia64_process_unwind, hppa_process_unwind),
	(arm_process_unwind, get_symbol_for_build_attribute): Use it.
This commit is contained in:
Alan Modra 2020-03-16 10:31:45 +10:30
parent 60e63c3e97
commit 28d1356774
2 changed files with 81 additions and 79 deletions

View file

@ -1,3 +1,9 @@
2020-03-16 Alan Modra <amodra@gmail.com>
* readelf.c (get_symbols): New function.
(process_relocs, ia64_process_unwind, hppa_process_unwind),
(arm_process_unwind, get_symbol_for_build_attribute): Use it.
2020-03-16 Alan Modra <amodra@gmail.com> 2020-03-16 Alan Modra <amodra@gmail.com>
* unwind-ia64.c (unw_decode_uleb128): Prevent overlarge shifts. * unwind-ia64.c (unw_decode_uleb128): Prevent overlarge shifts.

View file

@ -6765,6 +6765,47 @@ process_section_headers (Filedata * filedata)
return TRUE; return TRUE;
} }
static bfd_boolean
get_symtab (Filedata *filedata, Elf_Internal_Shdr *symsec,
Elf_Internal_Sym **symtab, unsigned long *nsyms,
char **strtab, unsigned long *strtablen)
{
*strtab = NULL;
*strtablen = 0;
*symtab = GET_ELF_SYMBOLS (filedata, symsec, nsyms);
if (*symtab == NULL)
return FALSE;
if (symsec->sh_link != 0)
{
Elf_Internal_Shdr *strsec;
if (symsec->sh_link >= filedata->file_header.e_shnum)
{
error (_("Bad sh_link in symbol table section\n"));
free (*symtab);
*symtab = NULL;
*nsyms = 0;
return FALSE;
}
strsec = filedata->section_headers + symsec->sh_link;
*strtab = (char *) get_data (NULL, filedata, strsec->sh_offset,
1, strsec->sh_size, _("string table"));
if (*strtab == NULL)
{
free (*symtab);
*symtab = NULL;
*nsyms = 0;
return FALSE;
}
*strtablen = strsec->sh_size;
}
return TRUE;
}
static const char * static const char *
get_group_flags (unsigned int flags) get_group_flags (unsigned int flags)
{ {
@ -7355,7 +7396,6 @@ process_relocs (Filedata * filedata)
if (rel_size) if (rel_size)
{ {
Elf_Internal_Shdr * strsec;
int is_rela; int is_rela;
unsigned long num_rela; unsigned long num_rela;
@ -7388,22 +7428,10 @@ process_relocs (Filedata * filedata)
&& symsec->sh_type != SHT_DYNSYM) && symsec->sh_type != SHT_DYNSYM)
continue; continue;
symtab = GET_ELF_SYMBOLS (filedata, symsec, & nsyms); if (!get_symtab (filedata, symsec,
&symtab, &nsyms, &strtab, &strtablen))
if (symtab == NULL)
continue; continue;
if (symsec->sh_link != 0
&& symsec->sh_link < filedata->file_header.e_shnum)
{
strsec = filedata->section_headers + symsec->sh_link;
strtab = (char *) get_data (NULL, filedata, strsec->sh_offset,
1, strsec->sh_size,
_("string table"));
strtablen = strtab == NULL ? 0 : strsec->sh_size;
}
dump_relocations (filedata, rel_offset, rel_size, dump_relocations (filedata, rel_offset, rel_size,
symtab, nsyms, strtab, strtablen, symtab, nsyms, strtab, strtablen,
is_rela, is_rela,
@ -7804,7 +7832,6 @@ ia64_process_unwind (Filedata * filedata)
{ {
Elf_Internal_Shdr * sec; Elf_Internal_Shdr * sec;
Elf_Internal_Shdr * unwsec = NULL; Elf_Internal_Shdr * unwsec = NULL;
Elf_Internal_Shdr * strsec;
unsigned long i, unwcount = 0, unwstart = 0; unsigned long i, unwcount = 0, unwstart = 0;
struct ia64_unw_aux_info aux; struct ia64_unw_aux_info aux;
bfd_boolean res = TRUE; bfd_boolean res = TRUE;
@ -7813,22 +7840,19 @@ ia64_process_unwind (Filedata * filedata)
for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec) for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec)
{ {
if (sec->sh_type == SHT_SYMTAB if (sec->sh_type == SHT_SYMTAB)
&& sec->sh_link < filedata->file_header.e_shnum)
{ {
aux.symtab = GET_ELF_SYMBOLS (filedata, sec, & aux.nsyms); if (aux.symtab)
strsec = filedata->section_headers + sec->sh_link;
if (aux.strtab != NULL)
{ {
error (_("Multiple auxillary string tables encountered\n")); error (_("Multiple symbol tables encountered\n"));
free (aux.symtab);
aux.symtab = NULL;
free (aux.strtab); free (aux.strtab);
res = FALSE; aux.strtab = NULL;
} }
aux.strtab = (char *) get_data (NULL, filedata, strsec->sh_offset, if (!get_symtab (filedata, sec, &aux.symtab, &aux.nsyms,
1, strsec->sh_size, &aux.strtab, &aux.strtab_size))
_("string table")); return FALSE;
aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
} }
else if (sec->sh_type == SHT_IA_64_UNWIND) else if (sec->sh_type == SHT_IA_64_UNWIND)
unwcount++; unwcount++;
@ -8265,7 +8289,6 @@ hppa_process_unwind (Filedata * filedata)
{ {
struct hppa_unw_aux_info aux; struct hppa_unw_aux_info aux;
Elf_Internal_Shdr * unwsec = NULL; Elf_Internal_Shdr * unwsec = NULL;
Elf_Internal_Shdr * strsec;
Elf_Internal_Shdr * sec; Elf_Internal_Shdr * sec;
unsigned long i; unsigned long i;
bfd_boolean res = TRUE; bfd_boolean res = TRUE;
@ -8277,22 +8300,19 @@ hppa_process_unwind (Filedata * filedata)
for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec) for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec)
{ {
if (sec->sh_type == SHT_SYMTAB if (sec->sh_type == SHT_SYMTAB)
&& sec->sh_link < filedata->file_header.e_shnum)
{ {
aux.symtab = GET_ELF_SYMBOLS (filedata, sec, & aux.nsyms); if (aux.symtab)
strsec = filedata->section_headers + sec->sh_link;
if (aux.strtab != NULL)
{ {
error (_("Multiple auxillary string tables encountered\n")); error (_("Multiple symbol tables encountered\n"));
free (aux.symtab);
aux.symtab = NULL;
free (aux.strtab); free (aux.strtab);
res = FALSE; aux.strtab = NULL;
} }
aux.strtab = (char *) get_data (NULL, filedata, strsec->sh_offset, if (!get_symtab (filedata, sec, &aux.symtab, &aux.nsyms,
1, strsec->sh_size, &aux.strtab, &aux.strtab_size))
_("string table")); return FALSE;
aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
} }
else if (streq (SECTION_NAME (sec), ".PARISC.unwind")) else if (streq (SECTION_NAME (sec), ".PARISC.unwind"))
unwsec = sec; unwsec = sec;
@ -9363,7 +9383,6 @@ arm_process_unwind (Filedata * filedata)
{ {
struct arm_unw_aux_info aux; struct arm_unw_aux_info aux;
Elf_Internal_Shdr *unwsec = NULL; Elf_Internal_Shdr *unwsec = NULL;
Elf_Internal_Shdr *strsec;
Elf_Internal_Shdr *sec; Elf_Internal_Shdr *sec;
unsigned long i; unsigned long i;
unsigned int sec_type; unsigned int sec_type;
@ -9393,22 +9412,19 @@ arm_process_unwind (Filedata * filedata)
for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec) for (i = 0, sec = filedata->section_headers; i < filedata->file_header.e_shnum; ++i, ++sec)
{ {
if (sec->sh_type == SHT_SYMTAB && sec->sh_link < filedata->file_header.e_shnum) if (sec->sh_type == SHT_SYMTAB)
{ {
aux.symtab = GET_ELF_SYMBOLS (filedata, sec, & aux.nsyms); if (aux.symtab)
strsec = filedata->section_headers + sec->sh_link;
/* PR binutils/17531 file: 011-12666-0.004. */
if (aux.strtab != NULL)
{ {
error (_("Multiple string tables found in file.\n")); error (_("Multiple symbol tables encountered\n"));
free (aux.symtab);
aux.symtab = NULL;
free (aux.strtab); free (aux.strtab);
res = FALSE; aux.strtab = NULL;
} }
aux.strtab = get_data (NULL, filedata, strsec->sh_offset, if (!get_symtab (filedata, sec, &aux.symtab, &aux.nsyms,
1, strsec->sh_size, _("string table")); &aux.strtab, &aux.strtab_size))
aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; return FALSE;
} }
else if (sec->sh_type == sec_type) else if (sec->sh_type == sec_type)
unwsec = sec; unwsec = sec;
@ -18836,31 +18852,11 @@ get_symbol_for_build_attribute (Filedata * filedata,
symsec < filedata->section_headers + filedata->file_header.e_shnum; symsec < filedata->section_headers + filedata->file_header.e_shnum;
symsec ++) symsec ++)
{ {
if (symsec->sh_type == SHT_SYMTAB) if (symsec->sh_type == SHT_SYMTAB
{ && get_symtab (filedata, symsec,
ba_cache.symtab = GET_ELF_SYMBOLS (filedata, symsec, &ba_cache.symtab, &ba_cache.nsyms,
&ba_cache.nsyms); &ba_cache.strtab, &ba_cache.strtablen))
break;
if (ba_cache.symtab != NULL
&& symsec->sh_link < filedata->file_header.e_shnum)
{
Elf_Internal_Shdr *strtab_sec
= filedata->section_headers + symsec->sh_link;
ba_cache.strtab
= (char *) get_data (NULL, filedata, strtab_sec->sh_offset,
1, strtab_sec->sh_size,
_("string table"));
ba_cache.strtablen = strtab_sec->sh_size;
}
if (ba_cache.strtab == NULL)
{
free (ba_cache.symtab);
ba_cache.symtab = NULL;
}
if (ba_cache.symtab != NULL)
break;
}
} }
ba_cache.filedata = filedata; ba_cache.filedata = filedata;
} }