Integer overflows in readelf get_data
authorAlan Modra <amodra@gmail.com>
Wed, 7 Aug 2019 14:07:49 +0000 (23:37 +0930)
committerAlan Modra <amodra@gmail.com>
Wed, 7 Aug 2019 14:46:05 +0000 (00:16 +0930)
I noticed the test for overflow of amt = size * nmemb in get_data
wasn't effective.  An obvious example of nmemb = 3 and size = half max
value overflows but doesn't result in amt < nmemb.  This patch fixes
this problem and reports a size truncation or overflow rather than out
of memory in more cases.

* readelf.c (get_data): Improve overflow checks.

binutils/ChangeLog
binutils/readelf.c

index c5d2d8fb8356942f7443cdbaa12562166e23437a..b60ae64b2729a3150095554dfdbad01b598bde06 100644 (file)
@@ -1,3 +1,7 @@
+2019-08-08  Alan Modra  <amodra@gmail.com>
+
+       * readelf.c (get_data): Improve overflow checks.
+
 2019-08-07  Nick Clifton  <nickc@redhat.com>
 
        PR 24777
index 5e18734f10b9455e9bac3dd6b875fbd820730e39..3e3e27d19c5aaaa7525d7424b7549f681625d14d 100644 (file)
@@ -385,9 +385,9 @@ get_data (void *         var,
   /* If the size_t type is smaller than the bfd_size_type, eg because
      you are building a 32-bit tool on a 64-bit host, then make sure
      that when the sizes are cast to (size_t) no information is lost.  */
-  if (sizeof (size_t) < sizeof (bfd_size_type)
-      && (   (bfd_size_type) ((size_t) size) != size
-         || (bfd_size_type) ((size_t) nmemb) != nmemb))
+  if ((size_t) size != size
+      || (size_t) nmemb != nmemb
+      || (size_t) amt != amt)
     {
       if (reason)
        error (_("Size truncation prevents reading %s"
@@ -397,7 +397,7 @@ get_data (void *         var,
     }
 
   /* Check for size overflow.  */
-  if (amt < nmemb)
+  if (amt / size != nmemb || (size_t) amt + 1 == 0)
     {
       if (reason)
        error (_("Size overflow prevents reading %s"
@@ -429,10 +429,8 @@ get_data (void *         var,
   mvar = var;
   if (mvar == NULL)
     {
-      /* Check for overflow.  */
-      if (nmemb < (~(bfd_size_type) 0 - 1) / size)
-       /* + 1 so that we can '\0' terminate invalid string table sections.  */
-       mvar = malloc ((size_t) amt + 1);
+      /* + 1 so that we can '\0' terminate invalid string table sections.  */
+      mvar = malloc ((size_t) amt + 1);
 
       if (mvar == NULL)
        {