readelf: handle corrupted chains better
authorMike Frysinger <vapier@gentoo.org>
Tue, 24 Feb 2015 06:47:51 +0000 (01:47 -0500)
committerMike Frysinger <vapier@gentoo.org>
Tue, 24 Feb 2015 15:36:51 +0000 (10:36 -0500)
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.

binutils/ChangeLog
binutils/readelf.c

index a462145a86db2a8c71293c983d09405f12465bf0..599c82c1bd935ec0a2729db9202120857c34c5f6 100644 (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
index 7394e76ab17a220e4994353fb6d097ec522fc344..b3f4733ed2e3b6ae5ea04329c67e3daeff7d2983 100644 (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));