This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PR21994, readelf looping on verdefs
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Fri, 25 Aug 2017 16:04:00 +0930
- Subject: PR21994, readelf looping on verdefs
- Authentication-results: sourceware.org; auth=none
This fixes a few more problems with readelf display of verdef and
verneed, and should ensure that files crafted with verdef/verneed
loops no longer result in endless output from readelf. The comment
about PR17531 deleted here isn't totally lost. There's another one
mentioning the same PR and file a little later.
PR 21994
* readelf.c (process_version_sections <SHT_GNU_verdef>): Check
vd_aux and vda_next for sanity. Delete "end". Correct overflow
checks.
(process_version_sections <SHT_GNU_verneed>): Correct overflow
check. Don't report invalid vna_next on overflow. Do report
invalid vna_next on size less than aux info.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 07cd2b0..db3fc03 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -10155,7 +10155,6 @@ process_version_sections (FILE * file)
Elf_External_Verdef * edefs;
unsigned long idx;
unsigned long cnt;
- unsigned long end;
char * endbuf;
found = TRUE;
@@ -10177,10 +10176,7 @@ process_version_sections (FILE * file)
break;
endbuf = (char *) edefs + section->sh_size;
- /* PR 17531: file: id:000001,src:000172+005151,op:splice,rep:2. */
- end = (section->sh_info < section->sh_size
- ? section->sh_info : section->sh_size);
- for (idx = cnt = 0; cnt < end; ++cnt)
+ for (idx = cnt = 0; cnt < section->sh_info; ++cnt)
{
char * vstart;
Elf_External_Verdef * edef;
@@ -10211,13 +10207,13 @@ process_version_sections (FILE * file)
ent.vd_ndx, ent.vd_cnt);
/* Check for overflow. */
- if (vstart + sizeof (*eaux) > endbuf)
- break;
- if (ent.vd_aux > (size_t) (endbuf - (vstart + sizeof (*eaux))))
+ if (ent.vd_aux > (size_t) (endbuf - vstart))
break;
vstart += ent.vd_aux;
+ if (vstart + sizeof (*eaux) > endbuf)
+ break;
eaux = (Elf_External_Verdaux *) vstart;
aux.vda_name = BYTE_GET (eaux->vda_name);
@@ -10232,6 +10228,14 @@ process_version_sections (FILE * file)
for (j = 1; j < ent.vd_cnt; j++)
{
+ if (aux.vda_next < sizeof (*eaux)
+ && !(j == ent.vd_cnt - 1 && aux.vda_next == 0))
+ {
+ warn (_("Invalid vda_next field of %lx\n"),
+ aux.vda_next);
+ j = ent.vd_cnt;
+ break;
+ }
/* Check for overflow. */
if (aux.vda_next > (size_t) (endbuf - vstart))
break;
@@ -10239,9 +10243,9 @@ process_version_sections (FILE * file)
isum += aux.vda_next;
vstart += aux.vda_next;
- eaux = (Elf_External_Verdaux *) vstart;
if (vstart + sizeof (*eaux) > endbuf)
break;
+ eaux = (Elf_External_Verdaux *) vstart;
aux.vda_name = BYTE_GET (eaux->vda_name);
aux.vda_next = BYTE_GET (eaux->vda_next);
@@ -10259,6 +10263,13 @@ process_version_sections (FILE * file)
/* PR 17531:
file: id:000001,src:000172+005151,op:splice,rep:2. */
+ if (ent.vd_next < sizeof (*edef)
+ && !(cnt == section->sh_info - 1 && ent.vd_next == 0))
+ {
+ warn (_("Invalid vd_next field of %lx\n"), ent.vd_next);
+ cnt = section->sh_info;
+ break;
+ }
if (ent.vd_next > (size_t) (endbuf - ((char *) edefs + idx)))
break;
@@ -10357,15 +10368,17 @@ process_version_sections (FILE * file)
printf (_(" Flags: %s Version: %d\n"),
get_ver_flags (aux.vna_flags), aux.vna_other);
- /* Check for overflow. */
- if (aux.vna_next > (size_t) (endbuf - vstart)
- || (aux.vna_next == 0 && j < ent.vn_cnt - 1))
+ if (aux.vna_next < sizeof (*eaux)
+ && !(j == ent.vn_cnt - 1 && aux.vna_next == 0))
{
warn (_("Invalid vna_next field of %lx\n"),
aux.vna_next);
j = ent.vn_cnt;
break;
}
+ /* Check for overflow. */
+ if (aux.vna_next > (size_t) (endbuf - vstart))
+ break;
isum += aux.vna_next;
vstart += aux.vna_next;
}
@@ -10373,13 +10386,15 @@ process_version_sections (FILE * file)
if (j < ent.vn_cnt)
warn (_("Missing Version Needs auxillary information\n"));
- if (ent.vn_next > (size_t) (endbuf - ((char *) eneed + idx))
- || (ent.vn_next == 0 && cnt < section->sh_info - 1))
+ if (ent.vn_next < sizeof (*entry)
+ && !(cnt == section->sh_info - 1 && ent.vn_next == 0))
{
warn (_("Invalid vn_next field of %lx\n"), ent.vn_next);
cnt = section->sh_info;
break;
}
+ if (ent.vn_next > (size_t) (endbuf - ((char *) eneed + idx)))
+ break;
idx += ent.vn_next;
}
--
Alan Modra
Australia Development Lab, IBM