From 8cd35e00bd413e68e6b9ae6403aa4209fc89b90f Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 21 Nov 2020 21:24:57 -0500 Subject: [PATCH] cmd/internal/buildid: update Mach-O code signature when rewriting buildid As the code signature contains hashes of the entire file (except the signature itself), rewriting buildid will invalidate the signature. This CL makes it regenerate the signature when rewriting the buildid. It only does it when the file already has a code signature, with proper size (darwin/arm64 binaries generated by the Go linker should have). Updates #38485, #42684. Change-Id: I082d9e5808b0ee6a35f9c362d7262aadd9113c81 Reviewed-on: https://go-review.googlesource.com/c/go/+/272257 Trust: Cherry Zhang Run-TryBot: Cherry Zhang TryBot-Result: Go Bot Reviewed-by: Austin Clements Reviewed-by: Than McIntosh --- src/cmd/buildid/buildid.go | 2 +- src/cmd/go/internal/work/buildid.go | 2 +- src/cmd/internal/buildid/rewrite.go | 39 ++++++++++++++++++++++------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/cmd/buildid/buildid.go b/src/cmd/buildid/buildid.go index 699d977950..8e02a7ae10 100644 --- a/src/cmd/buildid/buildid.go +++ b/src/cmd/buildid/buildid.go @@ -62,7 +62,7 @@ func main() { return } - f, err = os.OpenFile(file, os.O_WRONLY, 0) + f, err = os.OpenFile(file, os.O_RDWR, 0) if err != nil { log.Fatal(err) } diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index a88544e1af..3c7be5a3e3 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -647,7 +647,7 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { } if rewrite { - w, err := os.OpenFile(target, os.O_WRONLY, 0) + w, err := os.OpenFile(target, os.O_RDWR, 0) if err != nil { return err } diff --git a/src/cmd/internal/buildid/rewrite.go b/src/cmd/internal/buildid/rewrite.go index d3d2009d1c..a7928959c4 100644 --- a/src/cmd/internal/buildid/rewrite.go +++ b/src/cmd/internal/buildid/rewrite.go @@ -94,19 +94,27 @@ func Rewrite(w io.WriterAt, pos []int64, id string) error { return err } } + + // Update Mach-O code signature, if any. + if f, cmd, ok := findMachoCodeSignature(w); ok { + if codesign.Size(int64(cmd.Dataoff), "a.out") == int64(cmd.Datasize) { + // Update the signature if the size matches, so we don't need to + // fix up headers. Binaries generated by the Go linker should have + // the expected size. Otherwise skip. + text := f.Segment("__TEXT") + cs := make([]byte, cmd.Datasize) + codesign.Sign(cs, w.(io.Reader), "a.out", int64(cmd.Dataoff), int64(text.Offset), int64(text.Filesz), f.Type == macho.TypeExec) + if _, err := w.WriteAt(cs, int64(cmd.Dataoff)); err != nil { + return err + } + } + } + return nil } func excludeMachoCodeSignature(r io.Reader) io.Reader { - ra, ok := r.(io.ReaderAt) - if !ok { - return r - } - f, err := macho.NewFile(ra) - if err != nil { - return r - } - cmd, ok := codesign.FindCodeSigCmd(f) + _, cmd, ok := findMachoCodeSignature(r) if !ok { return r } @@ -139,3 +147,16 @@ func (r *excludedReader) Read(p []byte) (int, error) { r.off += int64(n) return n, err } + +func findMachoCodeSignature(r interface{}) (*macho.File, codesign.CodeSigCmd, bool) { + ra, ok := r.(io.ReaderAt) + if !ok { + return nil, codesign.CodeSigCmd{}, false + } + f, err := macho.NewFile(ra) + if err != nil { + return nil, codesign.CodeSigCmd{}, false + } + cmd, ok := codesign.FindCodeSigCmd(f) + return f, cmd, ok +} -- 2.48.1