diff options
author | Alan Modra <amodra@gmail.com> | 2017-08-25 11:41:06 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2017-08-25 12:23:30 +0930 |
commit | 1445030f313d9b251a6a27c8bdf52197520396e2 (patch) | |
tree | ae30aa0a8c459095fa0e03296a25eece99e12534 /binutils/readelf.c | |
parent | 176047c9f2ec8ccb4e0b6bfade4f21cb25d986e9 (diff) | |
download | gdb-1445030f313d9b251a6a27c8bdf52197520396e2.zip gdb-1445030f313d9b251a6a27c8bdf52197520396e2.tar.gz gdb-1445030f313d9b251a6a27c8bdf52197520396e2.tar.bz2 |
PR21994, readelf looping on verdefs
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.
Diffstat (limited to 'binutils/readelf.c')
-rw-r--r-- | binutils/readelf.c | 43 |
1 files changed, 29 insertions, 14 deletions
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; } |