mirror of
https://github.com/golang/go
synced 2024-11-13 12:30:21 -07:00
cmd/internal/buildid: skip over Mach-O UUID from buildid computation
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>
This commit is contained in:
parent
f2d9f5ffca
commit
0bb2183d45
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user