Skip to content

Commit

Permalink
cmd/internal/buildid: update Mach-O code signature when rewriting bui…
Browse files Browse the repository at this point in the history
…ldid

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 <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
  • Loading branch information
cherrymui committed Dec 1, 2020
1 parent 6f84993 commit 8cd35e0
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/cmd/buildid/buildid.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/go/internal/work/buildid.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
39 changes: 30 additions & 9 deletions src/cmd/internal/buildid/rewrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}

0 comments on commit 8cd35e0

Please sign in to comment.