Add ECOFF Symbolic Header sanity checks
authorAlan Modra <amodra@gmail.com>
Thu, 2 Feb 2023 12:09:31 +0000 (22:39 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 3 Feb 2023 05:41:18 +0000 (16:11 +1030)
Anti-fuzzer measures.  The checks don't ensure the various elements in
the header are distinct, but that isn't important as far as making
sure we don't overrun the buffer containing all the elements.  Also,
we now don't care about offsets where the corresponding count is zero.

* ecoff.c (_bfd_ecoff_slurp_symbolic_info): Sanity check offsets
in debug->symbolic_header.

bfd/ecoff.c

index 717d2fa2c75dfc4a2e52adf9cc567d1255065fd2..48f33df630e1d67f9c79eaa12e62b62222bb6d80 100644 (file)
@@ -527,12 +527,24 @@ _bfd_ecoff_slurp_symbolic_info (bfd *abfd,
      documented section. And the ordering of the sections varies between
      statically and dynamically linked executables.
      If bfd supports SEEK_END someday, this code could be simplified.  */
-  raw_end = 0;
+  raw_end = raw_base;
 
 #define UPDATE_RAW_END(start, count, size) \
-  cb_end = internal_symhdr->start + internal_symhdr->count * (size); \
-  if (cb_end > raw_end) \
-    raw_end = cb_end
+  do                                                                   \
+    if (internal_symhdr->count != 0)                                   \
+      {                                                                        \
+       if (internal_symhdr->start < raw_base)                          \
+         goto err;                                                     \
+       if (_bfd_mul_overflow ((unsigned long) internal_symhdr->count,  \
+                              (size), &amt))                           \
+         goto err;                                                     \
+       cb_end = internal_symhdr->start + amt;                          \
+       if (cb_end < internal_symhdr->start)                            \
+         goto err;                                                     \
+       if (cb_end > raw_end)                                           \
+         raw_end = cb_end;                                             \
+      }                                                                        \
+  while (0)
 
   UPDATE_RAW_END (cbLineOffset, cbLine, sizeof (unsigned char));
   UPDATE_RAW_END (cbDnOffset, idnMax, backend->debug_swap.external_dnr_size);
@@ -599,6 +611,7 @@ _bfd_ecoff_slurp_symbolic_info (bfd *abfd,
   if (_bfd_mul_overflow ((unsigned long) internal_symhdr->ifdMax,
                         sizeof (struct fdr), &amt))
     {
+    err:
       bfd_set_error (bfd_error_file_too_big);
       return false;
     }