From: Jon Turney Date: Wed, 15 Jan 2020 17:03:48 +0000 (+0000) Subject: Identify reproducible builds in 'objdump -p' output for PE files X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b5d36aaa8ad9b0aee720b7a6b3270d561a27cb6f;p=binutils-gdb.git Identify reproducible builds in 'objdump -p' output for PE files These are produced by MSVC when the '/Brepro' flag is used. To quote from the PE specification [1]: "The presence of an entry of type IMAGE_DEBUG_TYPE_REPRO indicates the PE file is built in a way to achieve determinism or reproducibility. If the input does not change, the output PE file is guaranteed to be bit-for-bit identical no matter when or where the PE is produced. Various date/time stamp fields in the PE file are filled with part or all the bits from a calculated hash value that uses PE file content as input, and therefore no longer represent the actual date and time when a PE file or related specific data within the PE is produced. The raw data of this debug entry may be empty, or may contain a calculated hash value preceded by a four-byte value that represents the hash value length." [1] https://docs.microsoft.com/en-us/windows/win32/debug/pe-format bfd/ChangeLog: 2020-01-16 Jon Turney * peXXigen.c (pe_is_repro): New function. (_bfd_XX_print_private_bfd_data_common): Note timestamp is actually a build hash if PE_IMAGE_DEBUG_TYPE_REPRO is present. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 43f99b35afd..30766c113e3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2020-01-16 Jon Turney + + * peXXigen.c (pe_is_repro): New function. + (_bfd_XX_print_private_bfd_data_common): Note timestamp is + actually a build hash if PE_IMAGE_DEBUG_TYPE_REPRO is present. + 2020-01-16 Jon Turney * peXXigen.c (debug_type_names): Add names for new debug data type diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index dc7951f8d9f..d9bf0e46236 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -2746,6 +2746,71 @@ pe_print_debugdata (bfd * abfd, void * vfile) return TRUE; } +static bfd_boolean +pe_is_repro (bfd * abfd) +{ + pe_data_type *pe = pe_data (abfd); + struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; + asection *section; + bfd_byte *data = 0; + bfd_size_type dataoff; + unsigned int i; + bfd_boolean res = FALSE; + + bfd_vma addr = extra->DataDirectory[PE_DEBUG_DATA].VirtualAddress; + bfd_size_type size = extra->DataDirectory[PE_DEBUG_DATA].Size; + + if (size == 0) + return FALSE; + + addr += extra->ImageBase; + for (section = abfd->sections; section != NULL; section = section->next) + { + if ((addr >= section->vma) && (addr < (section->vma + section->size))) + break; + } + + if ((section == NULL) + || (!(section->flags & SEC_HAS_CONTENTS)) + || (section->size < size)) + { + return FALSE; + } + + dataoff = addr - section->vma; + + if (size > (section->size - dataoff)) + { + return FALSE; + } + + if (!bfd_malloc_and_get_section (abfd, section, &data)) + { + if (data != NULL) + free (data); + return FALSE; + } + + for (i = 0; i < size / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++) + { + struct external_IMAGE_DEBUG_DIRECTORY *ext + = &((struct external_IMAGE_DEBUG_DIRECTORY *)(data + dataoff))[i]; + struct internal_IMAGE_DEBUG_DIRECTORY idd; + + _bfd_XXi_swap_debugdir_in (abfd, ext, &idd); + + if (idd.Type == PE_IMAGE_DEBUG_TYPE_REPRO) + { + res = TRUE; + break; + } + } + + free(data); + + return res; +} + /* Print out the program headers. */ bfd_boolean @@ -2777,11 +2842,21 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile) PF (IMAGE_FILE_BYTES_REVERSED_HI, "big endian"); #undef PF - /* ctime implies '\n'. */ - { - time_t t = pe->coff.timestamp; - fprintf (file, "\nTime/Date\t\t%s", ctime (&t)); - } + /* + If a PE_IMAGE_DEBUG_TYPE_REPRO entry is present in the debug directory, the + timestamp is to be interpreted as the hash of a reproducible build. + */ + if (pe_is_repro (abfd)) + { + fprintf (file, "\nTime/Date\t\t%08lx", pe->coff.timestamp); + fprintf (file, "\t(This is a reproducible build file hash, not a timestamp)\n"); + } + else + { + /* ctime implies '\n'. */ + time_t t = pe->coff.timestamp; + fprintf (file, "\nTime/Date\t\t%s", ctime (&t)); + } #ifndef IMAGE_NT_OPTIONAL_HDR_MAGIC # define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b