Fix an illegal memory access when dumping corrupt x86_64 PE unwind data.
authorNick Clifton <nickc@redhat.com>
Thu, 22 Aug 2019 13:37:03 +0000 (14:37 +0100)
committerNick Clifton <nickc@redhat.com>
Thu, 22 Aug 2019 13:37:03 +0000 (14:37 +0100)
PR 24922
* pei-x86_64.c (pex64_xdata_print_uwd_codes): Add checks before
reading data from extra records.

bfd/ChangeLog
bfd/pei-x86_64.c

index ef9eee4..1c08d38 100644 (file)
@@ -1,3 +1,9 @@
+2019-08-22  Nick Clifton  <nickc@redhat.com>
+
+       PR 24922
+       * pei-x86_64.c (pex64_xdata_print_uwd_codes): Add checks before
+       reading data from extra records.
+
 2019-08-22  Tamar Christina  <tamar.christina@arm.com>
 
        PR ld/24601
 2019-08-22  Tamar Christina  <tamar.christina@arm.com>
 
        PR ld/24601
index 8a88827..2588e6c 100644 (file)
@@ -228,27 +228,41 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
       int unexpected = FALSE;
 
       fprintf (file, "\t  pc+0x%02x: ", (unsigned int) dta[0]);
       int unexpected = FALSE;
 
       fprintf (file, "\t  pc+0x%02x: ", (unsigned int) dta[0]);
+
       switch (PEX64_UNWCODE_CODE (dta[1]))
        {
        case UWOP_PUSH_NONVOL:
          fprintf (file, "push %s", pex_regs[info]);
          break;
       switch (PEX64_UNWCODE_CODE (dta[1]))
        {
        case UWOP_PUSH_NONVOL:
          fprintf (file, "push %s", pex_regs[info]);
          break;
+
        case UWOP_ALLOC_LARGE:
          if (info == 0)
            {
        case UWOP_ALLOC_LARGE:
          if (info == 0)
            {
-             tmp = bfd_get_16 (abfd, &dta[2]) * 8;
+             if (dta + 4 > ui->rawUnwindCodesEnd)
+               {
+                 fprintf (file, _("warning: corrupt unwind data\n"));
+                 return;
+               }
+             tmp = bfd_get_16 (abfd, dta + 2) * 8;
              i++;
            }
          else
            {
              i++;
            }
          else
            {
-             tmp = bfd_get_32 (abfd, &dta[2]);
+             if (dta + 6 > ui->rawUnwindCodesEnd)
+               {
+                 fprintf (file, _("warning: corrupt unwind data\n"));
+                 return;
+               }
+             tmp = bfd_get_32 (abfd, dta + 2);
              i += 2;
            }
          fprintf (file, "alloc large area: rsp = rsp - 0x%x", tmp);
          break;
              i += 2;
            }
          fprintf (file, "alloc large area: rsp = rsp - 0x%x", tmp);
          break;
+
        case UWOP_ALLOC_SMALL:
          fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
          break;
        case UWOP_ALLOC_SMALL:
          fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
          break;
+
        case UWOP_SET_FPREG:
          /* According to the documentation, info field is unused.  */
          fprintf (file, "FPReg: %s = rsp + 0x%x (info = 0x%x)",
        case UWOP_SET_FPREG:
          /* According to the documentation, info field is unused.  */
          fprintf (file, "FPReg: %s = rsp + 0x%x (info = 0x%x)",
@@ -257,22 +271,40 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
          unexpected = ui->FrameRegister == 0;
          save_allowed = FALSE;
          break;
          unexpected = ui->FrameRegister == 0;
          save_allowed = FALSE;
          break;
+
        case UWOP_SAVE_NONVOL:
        case UWOP_SAVE_NONVOL:
-         tmp = bfd_get_16 (abfd, &dta[2]) * 8;
+         if (dta + 4 > ui->rawUnwindCodesEnd)
+           {
+             fprintf (file, _("warning: corrupt unwind data\n"));
+             return;
+           }
+         tmp = bfd_get_16 (abfd, dta + 2) * 8;
          i++;
          fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
          unexpected = !save_allowed;
          break;
          i++;
          fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
          unexpected = !save_allowed;
          break;
+
        case UWOP_SAVE_NONVOL_FAR:
        case UWOP_SAVE_NONVOL_FAR:
-         tmp = bfd_get_32 (abfd, &dta[2]);
+         if (dta + 6 > ui->rawUnwindCodesEnd)
+           {
+             fprintf (file, _("warning: corrupt unwind data\n"));
+             return;
+           }
+         tmp = bfd_get_32 (abfd, dta + 2);
          i += 2;
          fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
          unexpected = !save_allowed;
          break;
          i += 2;
          fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
          unexpected = !save_allowed;
          break;
+
        case UWOP_SAVE_XMM:
          if (ui->Version == 1)
            {
        case UWOP_SAVE_XMM:
          if (ui->Version == 1)
            {
-             tmp = bfd_get_16 (abfd, &dta[2]) * 8;
+             if (dta + 4 > ui->rawUnwindCodesEnd)
+               {
+                 fprintf (file, _("warning: corrupt unwind data\n"));
+                 return;
+               }
+             tmp = bfd_get_16 (abfd, dta + 2) * 8;
              i++;
              fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
              unexpected = !save_allowed;
              i++;
              fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
              unexpected = !save_allowed;
@@ -283,24 +315,43 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
              unexpected = TRUE;
            }
          break;
              unexpected = TRUE;
            }
          break;
+
        case UWOP_SAVE_XMM_FAR:
        case UWOP_SAVE_XMM_FAR:
-         tmp = bfd_get_32 (abfd, &dta[2]) * 8;
+         if (dta + 6 > ui->rawUnwindCodesEnd)
+           {
+             fprintf (file, _("warning: corrupt unwind data\n"));
+             return;
+           }
+         tmp = bfd_get_32 (abfd, dta + 2) * 8;
          i += 2;
          fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
          unexpected = !save_allowed;
          break;
          i += 2;
          fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
          unexpected = !save_allowed;
          break;
+
        case UWOP_SAVE_XMM128:
        case UWOP_SAVE_XMM128:
-         tmp = bfd_get_16 (abfd, &dta[2]) * 16;
+         if (dta + 4 > ui->rawUnwindCodesEnd)
+           {
+             fprintf (file, _("warning: corrupt unwind data\n"));
+             return;
+           }
+         tmp = bfd_get_16 (abfd, dta + 2) * 16;
          i++;
          fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
          unexpected = !save_allowed;
          break;
          i++;
          fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
          unexpected = !save_allowed;
          break;
+
        case UWOP_SAVE_XMM128_FAR:
        case UWOP_SAVE_XMM128_FAR:
-         tmp = bfd_get_32 (abfd, &dta[2]) * 16;
+         if (dta + 6 > ui->rawUnwindCodesEnd)
+           {
+             fprintf (file, _("warning: corrupt unwind data\n"));
+             return;
+           }
+         tmp = bfd_get_32 (abfd, dta + 2) * 16;
          i += 2;
          fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
          unexpected = !save_allowed;
          break;
          i += 2;
          fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
          unexpected = !save_allowed;
          break;
+
        case UWOP_PUSH_MACHFRAME:
          fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
          if (info == 0)
        case UWOP_PUSH_MACHFRAME:
          fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
          if (info == 0)
@@ -310,11 +361,13 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
          else
            fprintf (file, ", unknown(%u))", info);
          break;
          else
            fprintf (file, ", unknown(%u))", info);
          break;
+
        default:
          /* PR 17512: file: 2245-7442-0.004.  */
          fprintf (file, _("Unknown: %x"), PEX64_UNWCODE_CODE (dta[1]));
          break;
        default:
          /* PR 17512: file: 2245-7442-0.004.  */
          fprintf (file, _("Unknown: %x"), PEX64_UNWCODE_CODE (dta[1]));
          break;
-      }
+       }
+
       if (unexpected)
        fprintf (file, " [Unexpected!]");
       fputc ('\n', file);
       if (unexpected)
        fprintf (file, " [Unexpected!]");
       fputc ('\n', file);