Stop leaking Go build information

The Go programming language has the concept of a panic.

Panic is a built-in function that stops the ordinary flow of control and begins panicking. When the function F calls panic, execution of F stops, any deferred functions in F are executed normally, and then F returns to its caller. To the caller, F then behaves like a call to panic. The process continues up the stack until all functions in the current goroutine have returned, at which point the program crashes. Panics can be initiated by invoking panic directly. They can also be caused by runtime errors, such as out-of-bounds array accesses. - Andrew Gerrand. August 2010

Let’s see this in action with some code I’m building and running on my MacBook. Save this file as main.go

package main

// Adapted from https://gobyexample.com/regular-expressions

import (
	"fmt"
	"regexp"
)

func main() {
	r, _ := regexp.Compile("p([a-z]+)ch")

	fmt.Println(r.MatchString("peach"))

	// Too many ')' in the regex
	r, _ = regexp.Compile("p([a-z]+))ch")

	fmt.Println(r.MatchString("peach"))
}

We can build and test this from the command line (assuming you have Go installed).

go build main.go && ./main

On my machine I get the following output (I’ve deleted content not relevant to the discussion)

...
regexp.(*Regexp).doExecute(0x10462923b?, ...
   /opt/homebrew/Cellar/go/1.19.1/libexec/src/regexp/exec.go:527 +0x50
regexp.(*Regexp).doMatch(...)
   /opt/homebrew/Cellar/go/1.19.1/libexec/src/regexp/exec.go:514
regexp.(*Regexp).MatchString(...)
   /opt/homebrew/Cellar/go/1.19.1/libexec/src/regexp/regexp.go:533
main.main()
   /Users/alec/projects/NiceGoPanics/main.go:18 +0x114

You can see which version of Go I am using (1.19.1), that I’m building on macOS, and the project directory were my source code is located.

This will probably be confusing to any user reporting the problem, and could give a cracker information about potential attack vectors.

In Go 1.13 (September 2019) the -trimpath build flag was introduced. This strips out a lot of extraneous information.

The new go build flag -trimpath removes all file system paths from the compiled executable, to improve build reproducibility. - Go 1.13 release notes

Let’s see it in action

go build -trimpath main.go && ./main
...
regexp.(*Regexp).doExecute(0x100fd923b?, ...
   regexp/exec.go:527 +0x50
regexp.(*Regexp).doMatch(...)
   regexp/exec.go:514
regexp.(*Regexp).MatchString(...)
   regexp/regexp.go:533
main.main()
   ./main.go:18 +0x114

Much better. So make sure you add -trimpath to all your production builds.

Big thanks to my colleague, Tom Clift, who pointed out -trimpath to me.

However, this does not remove all the information. For example:

$ go version -m main
main: go1.19.1
        path    command-line-arguments
        build   -compiler=gc
        build   -trimpath=true
        build   CGO_ENABLED=1
        build   GOARCH=arm64
        build   GOOS=darwin
comments powered by Disqus