From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30337 invoked by alias); 21 Jan 2020 15:53:34 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 30271 invoked by uid 89); 21 Jan 2020 15:53:34 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.7 required=5.0 tests=AWL,BAYES_00,FORGED_SPF_HELO,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS autolearn=ham version=3.3.1 spammy= X-HELO: sa-prd-fep-047.btinternet.com Received: from mailomta10-sa.btinternet.com (HELO sa-prd-fep-047.btinternet.com) (213.120.69.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 21 Jan 2020 15:53:23 +0000 Received: from sa-prd-rgout-004.btmx-prd.synchronoss.net ([10.2.38.7]) by sa-prd-fep-047.btinternet.com with ESMTP id <20200121155321.XNTS2831.sa-prd-fep-047.btinternet.com@sa-prd-rgout-004.btmx-prd.synchronoss.net>; Tue, 21 Jan 2020 15:53:21 +0000 Authentication-Results: btinternet.com; none X-OWM-Source-IP: 31.51.207.12 (GB) X-OWM-Env-Sender: jonturney@btinternet.com X-VadeSecure-score: verdict=clean score=0/300, class=clean Received: from localhost.localdomain (31.51.207.12) by sa-prd-rgout-004.btmx-prd.synchronoss.net (5.8.337) (authenticated as jonturney@btinternet.com) id 5E1A2CBA01996EE6; Tue, 21 Jan 2020 15:53:21 +0000 From: Jon Turney To: binutils@sourceware.org Cc: Jon Turney Subject: [PATCH 3/3] Identify reproducible builds in 'objdump -p' output for PE files Date: Tue, 21 Jan 2020 15:53:00 -0000 Message-Id: <20200121155212.12686-4-jon.turney@dronecode.org.uk> In-Reply-To: <20200121155212.12686-1-jon.turney@dronecode.org.uk> References: <20200121155212.12686-1-jon.turney@dronecode.org.uk> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SW-Source: 2020-01/txt/msg00303.txt.bz2 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. --- bfd/ChangeLog | 6 ++++ bfd/peXXigen.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index dc7951f8d9..f742375525 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 -- 2.21.0