aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog13
-rw-r--r--bfd/pei-x86_64.c54
-rw-r--r--include/ChangeLog6
-rw-r--r--include/coff/pe.h1
4 files changed, 66 insertions, 8 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 672143b..ddf0d04 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,16 @@
+2018-03-13 Nick Clifton <nickc@redhat.com>
+
+ PR 22113
+ * pei-x86_64.c (pex64_get_unwind_info): Change to a boolean
+ function. Add an end address parameter. Check access of the data
+ pointer to make sure that they do not extend beyond the end
+ address. Return FALSE if any check fails. Add the end address
+ pointer to the ui structure.
+ (pex64_xdata_print_uwd_codes): Check accesses of the raw unwind
+ codes to make sure that they do not extend beyond the end address
+ pointer. Print an error message and return immediately if any
+ check fails.
+
2018-03-09 Nick Clifton <nickc@redhat.com>
* elf64-s390.c (elf_s390_relocate_section): Move check for
diff --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c
index db30726..3a0248d 100644
--- a/bfd/pei-x86_64.c
+++ b/bfd/pei-x86_64.c
@@ -98,14 +98,20 @@ pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf,
/* Swap in unwind info header. */
-static void
-pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
+static bfd_boolean
+pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui,
+ void *data, void *data_end)
{
struct external_pex64_unwind_info *ex_ui =
(struct external_pex64_unwind_info *) data;
bfd_byte *ex_dta = (bfd_byte *) data;
+ bfd_byte *ex_dta_end = (bfd_byte *) data_end;
memset (ui, 0, sizeof (struct pex64_unwind_info));
+
+ if (ex_dta >= ex_dta_end || ex_dta + 4 >= ex_dta_end)
+ return FALSE;
+
ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags);
ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags);
ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue;
@@ -114,25 +120,33 @@ pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset);
ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes);
ui->SizeOfBlock = ui->sizeofUnwindCodes + 4;
- ui->rawUnwindCodes = &ex_dta[4];
+ ui->rawUnwindCodes = ex_dta + 4;
+ ui->rawUnwindCodesEnd = ex_dta_end;
ex_dta += ui->SizeOfBlock;
+ if (ex_dta >= ex_dta_end)
+ return FALSE;
+
switch (ui->Flags)
{
case UNW_FLAG_CHAININFO:
+ if (ex_dta + 12 >= ex_dta_end)
+ return FALSE;
ui->rva_BeginAddress = bfd_get_32 (abfd, ex_dta + 0);
ui->rva_EndAddress = bfd_get_32 (abfd, ex_dta + 4);
ui->rva_UnwindData = bfd_get_32 (abfd, ex_dta + 8);
ui->SizeOfBlock += 12;
- return;
+ return TRUE;
case UNW_FLAG_EHANDLER:
case UNW_FLAG_UHANDLER:
case UNW_FLAG_FHANDLER:
+ if (ex_dta + 4 >= ex_dta_end)
+ return FALSE;
ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta);
ui->SizeOfBlock += 4;
- return;
+ return TRUE;
default:
- return;
+ return TRUE;
}
}
@@ -158,6 +172,12 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
i = 0;
+ if (ui->rawUnwindCodes + 1 >= ui->rawUnwindCodesEnd)
+ {
+ fprintf (file, _("warning: corrupt unwind data\n"));
+ return;
+ }
+
if (ui->Version == 2
&& PEX64_UNWCODE_CODE (ui->rawUnwindCodes[1]) == UWOP_EPILOG)
{
@@ -166,10 +186,18 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
to decode instruction flow if outside an epilog. */
unsigned int func_size = rf->rva_EndAddress - rf->rva_BeginAddress;
+ if (ui->rawUnwindCodes + 1 + (ui->CountOfCodes * 2) >= ui->rawUnwindCodesEnd)
+ {
+ fprintf (file, _("warning: corrupt unwind data\n"));
+ return;
+ }
+
fprintf (file, "\tv2 epilog (length: %02x) at pc+:",
ui->rawUnwindCodes[0]);
+
if (PEX64_UNWCODE_INFO (ui->rawUnwindCodes[1]))
fprintf (file, " 0x%x", func_size - ui->rawUnwindCodes[0]);
+
i++;
for (; i < ui->CountOfCodes; i++)
{
@@ -187,6 +215,12 @@ pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
fputc ('\n', file);
}
+ if (ui->rawUnwindCodes + 2 + (ui->CountOfCodes * 2) >= ui->rawUnwindCodesEnd)
+ {
+ fprintf (file, _("warning: corrupt unwind data\n"));
+ return;
+ }
+
for (; i < ui->CountOfCodes; i++)
{
const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
@@ -338,14 +372,18 @@ pex64_dump_xdata (FILE *file, bfd *abfd,
/* PR 17512: file: 2245-7442-0.004. */
if (end_addr > sec_size)
{
- fprintf (file, _("warning: xdata section corrupt"));
+ fprintf (file, _("warning: xdata section corrupt\n"));
end_addr = sec_size;
}
}
else
end_addr = sec_size;
- pex64_get_unwind_info (abfd, &ui, &xdata[addr]);
+ if (! pex64_get_unwind_info (abfd, &ui, xdata + addr, xdata + end_addr))
+ {
+ fprintf (file, _("warning: xdata section corrupt\n"));
+ return;
+ }
if (ui.Version != 1 && ui.Version != 2)
{
diff --git a/include/ChangeLog b/include/ChangeLog
index 529f43c..942c02b 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,9 @@
+2018-03-13 Nick Clifton <nickc@redhat.com>
+
+ PR 22113
+ * coff/pe.h (struct pex64_unwind_info): Add a rawUnwindCodesEnd
+ field.
+
2018-03-08 H.J. Lu <hongjiu.lu@intel.com>
* opcode/i386 (OLDGCC_COMPAT): Removed.
diff --git a/include/coff/pe.h b/include/coff/pe.h
index 56cc4e2..cb9075a 100644
--- a/include/coff/pe.h
+++ b/include/coff/pe.h
@@ -497,6 +497,7 @@ struct pex64_unwind_info
bfd_vma FrameOffset;
bfd_vma sizeofUnwindCodes;
bfd_byte *rawUnwindCodes;
+ bfd_byte *rawUnwindCodesEnd;
bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER or UNW_FLAG_UHANDLER. */
bfd_vma rva_BeginAddress; /* UNW_FLAG_CHAININFO. */
bfd_vma rva_EndAddress; /* UNW_FLAG_CHAININFO. */