Skip to content

Commit 0bb2183

Browse files
committed
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent f2d9f5f commit 0bb2183

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

src/cmd/internal/buildid/rewrite.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package buildid
77
import (
88
"bytes"
99
"cmd/internal/codesign"
10+
imacho "cmd/internal/macho"
1011
"crypto/sha256"
1112
"debug/macho"
1213
"fmt"
@@ -31,11 +32,18 @@ func FindAndHash(r io.Reader, id string, bufSize int) (matches []int64, hash [32
3132
zeros := make([]byte, len(id))
3233
idBytes := []byte(id)
3334

35+
r0 := r // preserve original type of r
36+
3437
// For Mach-O files, we want to exclude the code signature.
3538
// The code signature contains hashes of the whole file (except the signature
3639
// itself), including the buildid. So the buildid cannot contain the signature.
3740
r = excludeMachoCodeSignature(r)
3841

42+
// With the "-B gobuildid" linker option (which will be the default on some
43+
// platforms), the host build ID (GNU build ID, Mach-O UUID) depends on the
44+
// Go buildid. So ignore the host build ID, to avoid convergence problem.
45+
r = excludeHostBuildID(r, r0)
46+
3947
// The strategy is to read the file through buf, looking for id,
4048
// but we need to worry about what happens if id is broken up
4149
// and returned in parts by two different reads.
@@ -124,6 +132,14 @@ func excludeMachoCodeSignature(r io.Reader) io.Reader {
124132
return &excludedReader{r, 0, int64(cmd.Dataoff), int64(cmd.Dataoff + cmd.Datasize)}
125133
}
126134

135+
func excludeHostBuildID(r, r0 io.Reader) io.Reader {
136+
off, sz, ok := findHostBuildID(r0)
137+
if !ok {
138+
return r
139+
}
140+
return &excludedReader{r, 0, off, off + sz}
141+
}
142+
127143
// excludedReader wraps an io.Reader. Reading from it returns the bytes from
128144
// the underlying reader, except that when the byte offset is within the
129145
// range between start and end, it returns zero bytes.
@@ -163,3 +179,29 @@ func findMachoCodeSignature(r any) (*macho.File, codesign.CodeSigCmd, bool) {
163179
cmd, ok := codesign.FindCodeSigCmd(f)
164180
return f, cmd, ok
165181
}
182+
183+
func findHostBuildID(r io.Reader) (offset int64, size int64, ok bool) {
184+
ra, ok := r.(io.ReaderAt)
185+
if !ok {
186+
return 0, 0, false
187+
}
188+
// TODO: handle ELF GNU build ID.
189+
f, err := macho.NewFile(ra)
190+
if err != nil {
191+
return 0, 0, false
192+
}
193+
194+
reader := imacho.NewLoadCmdReader(io.NewSectionReader(ra, 0, 1<<63-1), f.ByteOrder, imacho.FileHeaderSize(f))
195+
for i := uint32(0); i < f.Ncmd; i++ {
196+
cmd, err := reader.Next()
197+
if err != nil {
198+
break
199+
}
200+
if cmd.Cmd == imacho.LC_UUID {
201+
// The UUID is the data in the LC_UUID load command,
202+
// skipping over the 8-byte command header.
203+
return int64(reader.Offset() + 8), int64(cmd.Len - 8), true
204+
}
205+
}
206+
return 0, 0, false
207+
}

0 commit comments

Comments
 (0)