GNU Binutils produce a PE debug directory with one EFI_IMAGE_DEBUG_DIRECTORY_ENTRY: - the Type field of the entry is EFI_IMAGE_DEBUG_TYPE_CODEVIEW, - the FileOffset field of the entry points right past the entry itself, - the data structure placed at FileOffset is a CV_INFO_PDB20 structure, with an "NB10" signature.
This is all correct, except GNU Binutils include the pointed-to CV_INFO_PDB20 structure in the size of the debug directory (that is, Optional64Hdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size). That's a bug. The malformed debug directory size causes the loop in GenFw's ZeroDebugData() function to process the CV_INFO_PDB20 structure as a set of EFI_IMAGE_DEBUG_DIRECTORY_ENTRY elements, which crashes GenFw. This problem was exposed by commit e4129b0e5897 ("BaseTools: Update GenFw to clear unused debug entry generated by VS tool chain", 2017-06-19). Work around the Binutils issue by noticing when an EFI_IMAGE_DEBUG_DIRECTORY_ENTRY.FileOffset points back into the debug directory. (This can never happen with a well-formed PE file.) In this case, truncate DebugDirectoryEntrySize such that the debug directory will end right before the debug structure pointed-to by EFI_IMAGE_DEBUG_DIRECTORY_ENTRY.FileOffset. Tested with OVMF: - gcc-4.8.5-14.el7.x86_64 - binutils-2.25.1-27.base.el7.x86_64 and with ArmVirtPkg: - gcc-aarch64-linux-gnu-6.1.1-2.el7.x86_64 - binutils-aarch64-linux-gnu-2.27-3.el7.x86_64 Cc: Ard Biesheuvel <ard.biesheu...@linaro.org> Cc: Gerd Hoffmann <kra...@redhat.com> Cc: Leif Lindholm <leif.lindh...@linaro.org> Cc: Liming Gao <liming....@intel.com> Cc: Yonghong Zhu <yonghong....@intel.com> Reported-by: Gerd Hoffmann <kra...@redhat.com> Reported-by: Leif Lindholm <leif.lindh...@linaro.org> Ref: a1de67a8-57c2-908e-dd4d-9726d60fb388@redhat.com">http://mid.mail-archive.com/a1de67a8-57c2-908e-dd4d-9726d60fb388@redhat.com Ref: 20170705134136.GB26676@bivouac.eciton.net">http://mid.mail-archive.com/20170705134136.GB26676@bivouac.eciton.net Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <ler...@redhat.com> --- Notes: Repo: https://github.com/lersek/edk2.git Branch: binutils_debugdirsize_workaround BaseTools/Source/C/GenFw/GenFw.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/BaseTools/Source/C/GenFw/GenFw.c b/BaseTools/Source/C/GenFw/GenFw.c index 6569460f34f7..a79f485ee681 100644 --- a/BaseTools/Source/C/GenFw/GenFw.c +++ b/BaseTools/Source/C/GenFw/GenFw.c @@ -2771,6 +2771,7 @@ Returns: UINT32 Index; UINT32 DebugDirectoryEntryRva; UINT32 DebugDirectoryEntrySize; + UINT32 TruncatedDebugDirectorySize; UINT32 DebugDirectoryEntryFileOffset; UINT32 ExportDirectoryEntryRva; UINT32 ExportDirectoryEntryFileOffset; @@ -2893,6 +2894,25 @@ Returns: DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (FileBuffer + DebugDirectoryEntryFileOffset); Index = 0; for (Index=0; Index < DebugDirectoryEntrySize / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); Index ++, DebugEntry ++) { + // + // Work around GNU Binutils bug: if the debug information pointed-to by + // DebugEntry was incorrectly included in DebugDirectoryEntrySize, then + // the debug directory doesn't actually extend past the pointed-to debug + // information. Truncate DebugDirectoryEntrySize accordingly. + // + if (DebugEntry->FileOffset >= DebugDirectoryEntryFileOffset && + DebugEntry->FileOffset < (DebugDirectoryEntryFileOffset + + DebugDirectoryEntrySize)) { + TruncatedDebugDirectorySize = (DebugEntry->FileOffset - + DebugDirectoryEntryFileOffset); + VerboseMsg ( + "truncating debug directory size from %u to %u", + DebugDirectoryEntrySize, + TruncatedDebugDirectorySize + ); + DebugDirectoryEntrySize = TruncatedDebugDirectorySize; + } + DebugEntry->TimeDateStamp = 0; if (ZeroDebugFlag || DebugEntry->Type != EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { memset (FileBuffer + DebugEntry->FileOffset, 0, DebugEntry->SizeOfData); -- 2.13.1.3.g8be5a757fa67 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel