Skip to content

Commit

Permalink
default to GOGARBLE=*, stop using GOPRIVATE
Browse files Browse the repository at this point in the history
We can drop the code that kicked in when GOGARBLE was empty.
We can also add the value in addGarbleToHash unconditionally,
as we never allow it to be empty.

In the tests, remove all GOGARBLE lines where it just meant "obfuscate
everything" or "obfuscate the entire main module".

cgo.txtar had "obfuscate everything" as a separate step,
so remove it entirely.

linkname.txtar started failing because the imported package did not
import strings, so listPackage errored out. This wasn't a problem when
strings itself wasn't obfuscated, as transformLinkname silently left
strings.IndexByte untouched. It is a problem when IndexByte does get
obfuscated. Make that kind of listPackage error visible, and fix it.

reflect.txtar started failing with "unreachable method" runtime throws.
It's not clear to me why; it appears that GOGARBLE=* makes the linker
think that ExportedMethodName is suddenly unreachable.
Work around the problem by making the method explicitly reachable,
and leave a TODO as a reminder to investigate.

Finally, gogarble.txtar no longer needs to test for GOPRIVATE.
The rest of the test is left the same, as we still want the various
values for GOGARBLE to continue to work just like before.

Fixes burrowers#594.
  • Loading branch information
mvdan committed Dec 5, 2022
1 parent ec32030 commit 86e40b7
Show file tree
Hide file tree
Showing 29 changed files with 38 additions and 90 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and adds initial support for the upcoming Go 1.20.

Noteworthy changes include:

* `GOGARBLE=*` is now the default to obfuscate all packages - [#594]
* `GOPRIVATE` is no longer used, being deprecated in [v0.5.0]
* Obfuscate assembly source code filenames - [#605]
* Randomize the lengths of obfuscated names
* Support obfuscating `time` and `syscall`
Expand Down Expand Up @@ -157,6 +159,7 @@ Known bugs:
* obfuscating the standard library with `GOPRIVATE=*` is not well supported yet
* `garble test` is temporarily disabled, as it is currently broken

[#594]: https://github.com/burrowers/garble/issues/594
[#605]: https://github.com/burrowers/garble/issues/605

[v0.7.2]: https://github.com/burrowers/garble/releases/tag/v0.7.2
Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ order to:
* [Obfuscate literals](#literal-obfuscation), if the `-literals` flag is given
* Remove [extra information](#tiny-mode), if the `-tiny` flag is given

The tool obfuscates the packages matching `GOGARBLE`, a comma-separated list of
glob patterns of module path prefixes, as documented in `go help private`.
To obfuscate all the packages in a build, use `GOGARBLE=*`.
When `GOGARBLE` is empty, it assumes the value of `GOPRIVATE`.
When `GOPRIVATE` is also empty, then `GOGARBLE` assumes the value of the current
module path, to obfuscate all packages under the current module.
By default, the tool obfuscates all the packages being built.
You can manually specify which packages to obfuscate via `GOGARBLE`,
a comma-separated list of glob patterns matching package path prefixes.
This format is borrowed from `GOPRIVATE`; see `go help private`.

Note that commands like `garble build` will use the `go` version found in your
`$PATH`. To use different versions of Go, you can
Expand Down
1 change: 0 additions & 1 deletion bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ func BenchmarkBuild(b *testing.B) {
gocache, err := os.MkdirTemp(b.TempDir(), "gocache-*")
qt.Assert(b, err, qt.IsNil)
env := append(os.Environ(),
"GOGARBLE=*",
"GOCACHE="+gocache,
"GARBLE_WRITE_ALLOCS=true",
)
Expand Down
4 changes: 1 addition & 3 deletions hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ func addGarbleToHash(inputHash []byte) []byte {
// We also need to add the selected options to the full version string,
// because all of them result in different output. We use spaces to
// separate the env vars and flags, to reduce the chances of collisions.
if cache.GOGARBLE != "" {
fmt.Fprintf(hasher, " GOGARBLE=%s", cache.GOGARBLE)
}
fmt.Fprintf(hasher, " GOGARBLE=%s", cache.GOGARBLE)
appendFlags(hasher, true)
// addGarbleToHash returns the sum buffer, so we need a new copy.
// Otherwise the next use of the global sumBuffer would conflict.
Expand Down
38 changes: 18 additions & 20 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import (

"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
"golang.org/x/tools/go/ast/astutil"
Expand Down Expand Up @@ -998,7 +997,20 @@ func (tf *transformer) transformLinkname(localName, newName string) (string, str

lpkg, err := listPackage(pkgPath)
if err != nil {
// Probably a made up name like above, but with a dot.
// TODO(mvdan): use errors.As or errors.Is instead
if strings.Contains(err.Error(), "path not found") {
// Probably a made up name like above, but with a dot.
return localName, newName
}
if strings.Contains(err.Error(), "refusing to list") {
fmt.Fprintf(os.Stderr,
"//go:linkname refers to %s - add `import _ %q` so garble can find the package",
newName, pkgPath)
return localName, newName
}
if err != nil {
panic(err) // shouldn't happen
}
return localName, newName
}
if lpkg.ToObfuscate {
Expand Down Expand Up @@ -2185,7 +2197,8 @@ func flagSetValue(flags []string, name, value string) []string {

func fetchGoEnv() error {
out, err := exec.Command("go", "env", "-json",
"GOOS", "GOPRIVATE", "GOMOD", "GOVERSION", "GOCACHE",
// Keep in sync with sharedCache.GoEnv.
"GOOS", "GOMOD", "GOVERSION",
).CombinedOutput()
if err != nil {
// TODO: cover this in the tests.
Expand All @@ -2201,23 +2214,8 @@ To install Go, see: https://go.dev/doc/install
return fmt.Errorf(`cannot unmarshal from "go env -json": %w`, err)
}
cache.GOGARBLE = os.Getenv("GOGARBLE")
if cache.GOGARBLE != "" {
// GOGARBLE is non-empty; nothing to do.
} else if cache.GoEnv.GOPRIVATE != "" {
// GOGARBLE is empty and GOPRIVATE is non-empty.
// Set GOGARBLE to GOPRIVATE's value.
cache.GOGARBLE = cache.GoEnv.GOPRIVATE
} else {
// If GOPRIVATE isn't set and we're in a module, use its module
// path as a GOPRIVATE default. Include a _test variant too.
// TODO(mvdan): we shouldn't need the _test variant here,
// as the import path should not include it; only the package name.
if mod, err := os.ReadFile(cache.GoEnv.GOMOD); err == nil {
modpath := modfile.ModulePath(mod)
if modpath != "" {
cache.GOGARBLE = modpath + "," + modpath + "_test"
}
}
if cache.GOGARBLE == "" {
cache.GOGARBLE = "*" // we default to obfuscating everything
}
return nil
}
2 changes: 0 additions & 2 deletions scripts/check-third-party.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ modules=(

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

export GOGARBLE="*"

exit_code=0

show() {
Expand Down
4 changes: 1 addition & 3 deletions shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,12 @@ type sharedCache struct {
GOGARBLE string

// Filled directly from "go env".
// Remember to update the exec call when adding or removing names.
// Keep in sync with fetchGoEnv.
GoEnv struct {
GOOS string // i.e. the GOOS build target

GOPRIVATE string
GOMOD string
GOVERSION string
GOCACHE string
}
}

Expand Down
2 changes: 0 additions & 2 deletions testdata/script/asm.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
# TODO: support arm64, at least
[!amd64] skip 'the assembly is only written for amd64'

env GOGARBLE=test/main

garble build
exec ./main
cmp stderr main.stderr
Expand Down
8 changes: 0 additions & 8 deletions testdata/script/cgo.txtar
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
[!cgo] skip 'this test requires cgo to be enabled'

env GOGARBLE=test/main

garble build
! stderr 'warning' # check that the C toolchain is happy
exec ./main
Expand All @@ -19,12 +17,6 @@ garble reverse .
cmp stdout reversed.stdout
env GARBLE_TEST_REVERSING=false

env GOGARBLE=*
garble build
exec ./main
cmp stdout main.stdout
env GOGARBLE=test/main

garble -tiny build
exec ./main
cmp stdout main.stdout
Expand Down
1 change: 0 additions & 1 deletion testdata/script/crossbuild.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
[arm] env GOARCH=arm64

# A fairly average Go build, importing some std libraries.
env GOGARBLE='*'
garble build
-- go.mod --
module test/main
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/debugdir.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=*

garble -debugdir ./debug1 build
exists 'debug1/test/main/imported/imported.go' 'debug1/test/main/main.go' 'debug1/reflect/type.go'
exists 'debug1/runtime/map.go' 'debug1/runtime/funcdata.h' 'debug1/runtime/asm.s'
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/embed.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=*

garble build

exec ./main
Expand Down
8 changes: 2 additions & 6 deletions testdata/script/gogarble.txtar
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# Ensure that "does not match any packages" works with GOPRIVATE and GOGARBLE.
# Ensure that "does not match any packages" works.
env GOGARBLE=match-absolutely/nothing
! garble build -o=out ./standalone
stderr '^GOGARBLE="match-absolutely/nothing" does not match any packages to be built$'

env GOGARBLE=
env GOPRIVATE=match-absolutely/nothing
! garble build -o=out ./standalone
stderr '^GOGARBLE="match-absolutely/nothing" does not match any packages to be built$'

# A build where just some packages are obfuscated.
env GOGARBLE=test/main/imported
garble -literals build -o=out ./importer
Expand All @@ -23,6 +18,7 @@ garble build -o=out ./stdimporter

[short] stop # rebuilding std is slow

# Go back to the default of obfuscating all packages.
env GOGARBLE='*'

# Try garbling all of std, given some std packages.
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/help.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=*

! garble
stderr 'Garble obfuscates Go code'
stderr 'garble \[garble flags\] command'
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/implement.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main

garble build
exec ./main
cmp stdout main.stdout
Expand Down
6 changes: 2 additions & 4 deletions testdata/script/imports.txtar
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Note that this is the only test with a module where we rely on the detection
# of GOGARBLE.
# Also note that, since this is the only test using "real" external modules
# fetched via GOPROXY, go.mod and go.sum should declare the dependencies.
# Since this is the only test using "real" external modules fetched via GOPROXY,
# go.mod and go.sum should declare the dependencies.

# For now, use a throwaway module download cache instead of the host machine's.
# Usually it would be fine to reuse the host's, since we expose exact copies of
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/ldflags.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=*

# Note the proper domain, since the dot adds an edge case.
#
# Also note that there are three forms of -X allowed:
Expand Down
3 changes: 1 addition & 2 deletions testdata/script/linkname.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main,big.chungus/meme

garble build
exec ./main
cmp stderr main.stderr
Expand Down Expand Up @@ -76,6 +74,7 @@ func main() {
package imported

import (
_ "strings"
_ "unsafe"
)

Expand Down
3 changes: 0 additions & 3 deletions testdata/script/literals.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=*

garble -literals build
exec ./main$exe
cmp stderr main.stderr
Expand Down Expand Up @@ -52,7 +50,6 @@ grep '^\s+\w+ = .*\bappend\(\w+,(\s+\w+\[\d+\][\^\-+]\w+\[\d+\],?)+\)$' debug1/t

# Finally, sanity check that we can build all of std with -literals.
# Analogous to gogarble.txt.
env GOGARBLE='*'
garble -literals build std
-- go.mod --
module test/main
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/modinfo.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main

[exec:git] exec git init -q
[exec:git] exec git config user.name "name"
[exec:git] exec git config user.email "[email protected]"
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/plugin.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ skip # TODO: get plugins working properly. See issue #87

[windows] skip 'Go plugins are not supported on Windows'

env GOGARBLE=test/main

garble build -buildmode=plugin ./plugin
binsubstr plugin.so 'PublicVar' 'PublicFunc'
! binsubstr plugin.so 'privateFunc'
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/position.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main

garble build
exec ./main
! stdout 'garble_main\.go|garble_other_filename|is sorted'
Expand Down
8 changes: 6 additions & 2 deletions testdata/script/reflect.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main

garble build
exec ./main
cmp stdout main.stdout
Expand Down Expand Up @@ -32,6 +30,8 @@ import (
"test/main/importedpkg2"
)

var Sink interface{}

func main() {
// Fields still work fine when they are not obfuscated.
fmt.Println(importedpkg.ReflectInDefinedVar.ExportedField2)
Expand All @@ -41,9 +41,13 @@ func main() {
printfWithoutPackage("%T\n", importedpkg.ReflectTypeOf(2))
printfWithoutPackage("%T\n", importedpkg.ReflectTypeOfIndirect(4))


// More complex use of reflect.
v := importedpkg.ReflectValueOfVar
printfWithoutPackage("%#v\n", v)
// Keep the method from being unreachable, otherwise Call below may panic.
// TODO(mvdan): This only started being necessary with GOGARBLE=*. Why?
Sink = v.ExportedMethodName
method := reflect.ValueOf(&v).MethodByName("ExportedMethodName")
if method.IsValid() {
fmt.Println(method.Call(nil))
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/reverse.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main

# Unknown build flags should result in errors.
! garble reverse -badflag=foo .
stderr 'flag provided but not defined'
Expand Down
1 change: 0 additions & 1 deletion testdata/script/seed-cache.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
# In the past, this threw off garble's extra cached gob files.

env SEED1=OQg9kACEECQ
env GOGARBLE=*

# First, ensure that mod1's garbletest.v2 is in the cache.
cd mod1
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/seed.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main

# Note that in this test we use "! bincmp" on plaintext output files,
# as a workaround for "cmp" not supporting "! cmp".
# TODO: now that obfuscation with -seed is deterministic,
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/syntax.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE='test/main,private.source'

garble build
exec ./main$exe
cmp stderr main.stderr
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/tiny.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=test/main

# Tiny mode
garble -tiny build
! binsubstr main$exe 'garble_main.go' 'fmt/print.go'
Expand Down
2 changes: 0 additions & 2 deletions testdata/script/typeparams.txtar
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
env GOGARBLE=*

garble build
! binsubstr main$exe ${WORK} 'garble_main.go' 'GenericFunc' 'GenericVector' 'PredeclaredSignedInteger' 'StringableSignedInteger' 'CombineEmbeds' 'GenericParam'
-- go.mod --
Expand Down

0 comments on commit 86e40b7

Please sign in to comment.