ubsan: wasm: shift is too large for 64-bit type 'bfd_vma'
authorAlan Modra <amodra@gmail.com>
Mon, 23 Dec 2019 07:28:09 +0000 (17:58 +1030)
committerAlan Modra <amodra@gmail.com>
Mon, 23 Dec 2019 07:28:09 +0000 (17:58 +1030)
bfd/
* wasm-module.c (wasm_read_leb128): Don't allow oversize shifts.
Catch value overflow.  Sign extend only on terminating byte.
opcodes/
* wasm32-dis.c (wasm_read_leb128): Don't allow oversize shifts.
Catch value overflow.  Sign extend only on terminating byte.

bfd/ChangeLog
bfd/wasm-module.c
opcodes/ChangeLog
opcodes/wasm32-dis.c

index 40f4b663642506e98d304b86782272567b0a1848..8a2120ec2a2f4f06310549998caab25426b229b2 100644 (file)
@@ -1,3 +1,8 @@
+2019-12-23  Alan Modra  <amodra@gmail.com>
+
+       * wasm-module.c (wasm_read_leb128): Don't allow oversize shifts.
+       Catch value overflow.  Sign extend only on terminating byte.
+
 2019-12-20  Alan Modra  <amodra@gmail.com>
 
        * xtensa-isa.c (xtensa_insnbuf_from_chars): Avoid signed overflow.
index a827d108ede260564be7f29702342b0e2c42f8d9..3fa2a87fb47b311cafd46e2fa370bca1771b284c 100644 (file)
@@ -111,18 +111,28 @@ wasm_read_leb128 (bfd *             abfd,
   unsigned int num_read = 0;
   unsigned int shift = 0;
   unsigned char byte = 0;
-  bfd_boolean success = FALSE;
+  int status = 1;
 
   while (bfd_bread (&byte, 1, abfd) == 1)
     {
       num_read++;
 
-      result |= ((bfd_vma) (byte & 0x7f)) << shift;
+      if (shift < sizeof (result) * 8)
+       {
+         result |= ((bfd_vma) (byte & 0x7f)) << shift;
+         if ((result >> shift) != (byte & 0x7f))
+           /* Overflow.  */
+           status |= 2;
+         shift += 7;
+       }
+      else if ((byte & 0x7f) != 0)
+       status |= 2;
 
-      shift += 7;
       if ((byte & 0x80) == 0)
        {
-         success = TRUE;
+         status &= ~1;
+         if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+           result |= -((bfd_vma) 1 << shift);
          break;
        }
     }
@@ -130,10 +140,7 @@ wasm_read_leb128 (bfd *              abfd,
   if (length_return != NULL)
     *length_return = num_read;
   if (error_return != NULL)
-    *error_return = ! success;
-
-  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
-    result |= -((bfd_vma) 1 << shift);
+    *error_return = status != 0;
 
   return result;
 }
index d6d731113201c86f31013607c0fd5c9bfed9962b..9315ddef7ad0476ec1ae2e0fbf5fb33a5afa56e0 100644 (file)
@@ -1,3 +1,8 @@
+2019-12-23  Alan Modra  <amodra@gmail.com>
+
+       * wasm32-dis.c (wasm_read_leb128): Don't allow oversize shifts.
+       Catch value overflow.  Sign extend only on terminating byte.
+
 2019-12-20  Alan Modra  <amodra@gmail.com>
 
        PR 25281
index b1042793a5e42538d551ae07cd6c496f94f4ea58..a885148c8bdd3686a2611fae291e84e7edbd7636 100644 (file)
@@ -192,29 +192,36 @@ wasm_read_leb128 (bfd_vma                   pc,
   unsigned int num_read = 0;
   unsigned int shift = 0;
   unsigned char byte = 0;
-  bfd_boolean success = FALSE;
+  int status = 1;
 
   while (info->read_memory_func (pc + num_read, &byte, 1, info) == 0)
     {
       num_read++;
 
-      result |= ((bfd_vma) (byte & 0x7f)) << shift;
+      if (shift < sizeof (result) * 8)
+       {
+         result |= ((uint64_t) (byte & 0x7f)) << shift;
+         if ((result >> shift) != (byte & 0x7f))
+           /* Overflow.  */
+           status |= 2;
+         shift += 7;
+       }
+      else if ((byte & 0x7f) != 0)
+       status |= 2;
 
-      shift += 7;
       if ((byte & 0x80) == 0)
-        {
-          success = TRUE;
-          break;
-        }
+       {
+         status &= ~1;
+         if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+           result |= -((uint64_t) 1 << shift);
+         break;
+       }
     }
 
   if (length_return != NULL)
     *length_return = num_read;
   if (error_return != NULL)
-    *error_return = ! success;
-
-  if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
-    result |= -((uint64_t) 1 << shift);
+    *error_return = status != 0;
 
   return result;
 }