readelf: handle corrupted chains better

The current chain walker tries to protect itself against loops, by only
works with loops of length 1: a chain that points to itself.  If you have
a chain longer than that (3->4->3->4->...), readelf will still hang.

Since we know the max length of the chain, simply abort when we've walked
more times than that.  The only way that could have happened is if there
was a loop.
This commit is contained in:
Mike Frysinger 2015-02-24 01:47:51 -05:00
parent 884151a7b8
commit 94d15024fe
2 changed files with 20 additions and 10 deletions

View File

@ -1,3 +1,10 @@
2015-02-24 Mike Frysinger <vapier@gentoo.org>
PR binutils/17531
* readelf.c (process_symbol_table): Declare chained. Increment it
in every loop. Abort when chained is larger than nchains. Move
error check outside of chain loop.
2015-02-24 Dmitry Antipov <dantipov@nvidia.com>
* readelf.c (find_symbol_for_address): Use a binary search to

View File

@ -10783,6 +10783,7 @@ process_symbol_table (FILE * file)
unsigned long maxlength = 0;
unsigned long nzero_counts = 0;
unsigned long nsyms = 0;
unsigned long chained;
printf (_("\nHistogram for bucket list length (total of %lu buckets):\n"),
(unsigned long) nbuckets);
@ -10797,21 +10798,23 @@ process_symbol_table (FILE * file)
printf (_(" Length Number %% of total Coverage\n"));
for (hn = 0; hn < nbuckets; ++hn)
{
for (si = buckets[hn]; si > 0 && si < nchains && si < nbuckets; si = chains[si])
for (si = buckets[hn], chained = 0;
si > 0 && si < nchains && si < nbuckets && chained <= nchains;
si = chains[si], ++chained)
{
++nsyms;
if (maxlength < ++lengths[hn])
++maxlength;
/* PR binutils/17531: A corrupt binary could contain broken
histogram data. Do not go into an infinite loop trying
to process it. */
if (chains[si] == si)
{
error (_("histogram chain links to itself\n"));
break;
}
}
/* PR binutils/17531: A corrupt binary could contain broken
histogram data. Do not go into an infinite loop trying
to process it. */
if (chained > nchains)
{
error (_("histogram chain is corrupt\n"));
break;
}
}
counts = (unsigned long *) calloc (maxlength + 1, sizeof (*counts));