diff options
author | Jon Turney <jon.turney@dronecode.org.uk> | 2020-01-15 17:03:48 +0000 |
---|---|---|
committer | Jon Turney <jon.turney@dronecode.org.uk> | 2020-01-30 13:06:27 +0000 |
commit | b5d36aaa8ad9b0aee720b7a6b3270d561a27cb6f (patch) | |
tree | 7c7a97fac1c81463e4494077c15cd5ed8e5882fe /bfd/peXXigen.c | |
parent | 1957ab1030b40939544c88c1c4eb1b8a62bd0b5d (diff) | |
download | binutils-b5d36aaa8ad9b0aee720b7a6b3270d561a27cb6f.zip binutils-b5d36aaa8ad9b0aee720b7a6b3270d561a27cb6f.tar.gz binutils-b5d36aaa8ad9b0aee720b7a6b3270d561a27cb6f.tar.bz2 |
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 <jon.turney@dronecode.org.uk>
* 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.
Diffstat (limited to 'bfd/peXXigen.c')
-rw-r--r-- | bfd/peXXigen.c | 85 |
1 files changed, 80 insertions, 5 deletions
diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index dc7951f..d9bf0e4 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 |