]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/buildid: skip over Mach-O UUID from buildid computation
authorCherry Mui <cherryyz@google.com>
Tue, 8 Oct 2024 16:42:33 +0000 (12:42 -0400)
committerCherry Mui <cherryyz@google.com>
Mon, 21 Oct 2024 17:56:28 +0000 (17:56 +0000)
With the "-B gobuildid" linker option (which will be the default
on some platforms), the host build ID (GNU build ID, Mach-O UUID)
depends on the Go buildid. If the host build ID is included in the
Go buildid computation, it will lead to convergence problem for
the toolchain binaries. So ignore the host build ID in the buildid
computation.

This CL only handles Mach-O UUID. ELF GNU build ID will be handled
later.

For #68678.
For #63934.

Cq-Include-Trybots: luci.golang.try:gotip-darwin-amd64_14,gotip-darwin-arm64_13
Change-Id: Ie8ff20402a1c6083246d25dea391140c75be40d0
Reviewed-on: https://go-review.googlesource.com/c/go/+/618597
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Than McIntosh <thanm@golang.org>
src/cmd/internal/buildid/rewrite.go

index becc0782424ea054d61486ef2bd5979c5499124a..26720afef4c9dbe6c5c9f7f8341b13357c9b11e2 100644 (file)
@@ -7,6 +7,7 @@ package buildid
 import (
        "bytes"
        "cmd/internal/codesign"
+       imacho "cmd/internal/macho"
        "crypto/sha256"
        "debug/macho"
        "fmt"
@@ -31,11 +32,18 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32
        zeros := make([]byte, len(id))
        idBytes := []byte(id)
 
+       r0 := r // preserve original type of r
+
        // For Mach-O files, we want to exclude the code signature.
        // The code signature contains hashes of the whole file (except the signature
        // itself), including the buildid. So the buildid cannot contain the signature.
        r = excludeMachoCodeSignature(r)
 
+       // With the "-B gobuildid" linker option (which will be the default on some
+       // platforms), the host build ID (GNU build ID, Mach-O UUID) depends on the
+       // Go buildid. So ignore the host build ID, to avoid convergence problem.
+       r = excludeHostBuildID(r, r0)
+
        // The strategy is to read the file through buf, looking for id,
        // but we need to worry about what happens if id is broken up
        // and returned in parts by two different reads.
@@ -124,6 +132,14 @@ func excludeMachoCodeSignature(r io.Reader) io.Reader {
        return &excludedReader{r, 0, int64(cmd.Dataoff), int64(cmd.Dataoff + cmd.Datasize)}
 }
 
+func excludeHostBuildID(r, r0 io.Reader) io.Reader {
+       off, sz, ok := findHostBuildID(r0)
+       if !ok {
+               return r
+       }
+       return &excludedReader{r, 0, off, off + sz}
+}
+
 // excludedReader wraps an io.Reader. Reading from it returns the bytes from
 // the underlying reader, except that when the byte offset is within the
 // range between start and end, it returns zero bytes.
@@ -163,3 +179,29 @@ func findMachoCodeSignature(r any) (*macho.File, codesign.CodeSigCmd, bool) {
        cmd, ok := codesign.FindCodeSigCmd(f)
        return f, cmd, ok
 }
+
+func findHostBuildID(r io.Reader) (offset int64, size int64, ok bool) {
+       ra, ok := r.(io.ReaderAt)
+       if !ok {
+               return 0, 0, false
+       }
+       // TODO: handle ELF GNU build ID.
+       f, err := macho.NewFile(ra)
+       if err != nil {
+               return 0, 0, false
+       }
+
+       reader := imacho.NewLoadCmdReader(io.NewSectionReader(ra, 0, 1<<63-1), f.ByteOrder, imacho.FileHeaderSize(f))
+       for i := uint32(0); i < f.Ncmd; i++ {
+               cmd, err := reader.Next()
+               if err != nil {
+                       break
+               }
+               if cmd.Cmd == imacho.LC_UUID {
+                       // The UUID is the data in the LC_UUID load command,
+                       // skipping over the 8-byte command header.
+                       return int64(reader.Offset() + 8), int64(cmd.Len - 8), true
+               }
+       }
+       return 0, 0, false
+}