Commit Graph

46 Commits (master)

Author SHA1 Message Date
Daniel Martí d2beda1f00 switch frankban/quicktest for go-quicktest/qt
The latter is newer and uses generics.
3 months ago
Daniel Martí ad2ecc7f2f drop Go 1.21 and start using go/version
Needing to awkwardly treat Go versions as if they were semver
is no longer necessary thanks to go/version being in Go 1.22.0 now.
3 months ago
Daniel Martí b469dcaf9d
bump deps for the upcoming release
As usual, and this is also a good idea for the x repos to better
support Go 1.22.
3 months ago
Daniel Martí 126618a0d5 drop support for Go 1.20
Go 1.21.0 was released in August 2023, so our upcoming release
will no longer support the Go 1.20 release series.

The first Go 1.22 release candidate is also due in December 2023,
less than a month from now, so dropping 1.20 will simplify 1.22 work.
6 months ago
Daniel Martí c314fcb61c update deps
In particular, the x/tools update fixes support for Go 1.22,
due to https://go.dev/issue/62167 happening in August 2023.
6 months ago
Daniel Martí 3364c5c38f
update deps prior to release
Keeping x/tools up to date is particularly important.
12 months ago
Daniel Martí 7872177381 CI: try macos-latest again
And bump go-internal to its latest version, to include its fix
for those pesky "signal: killed" failures on macos.

While here, run the tests with -short on GOARCH=386,
and make our use of actions/setup-go a bit more consistent.
12 months ago
Daniel Martí 4a13321052 go.mod: bump deps 1 year ago
Daniel Martí e37f39054d update testscript to support code coverage with Go 1.20
See https://github.com/rogpeppe/go-internal/pull/201.
1 year ago
Daniel Martí b322876efe drop support for Go 1.19
Now that we're done with garble v0.9.x,
v0.10 will only support Go 1.20 as a minimum version.
1 year ago
Daniel Martí 99d30c033e go.mod: update dependencies before a release 1 year ago
pagran 6ace03322f
patch and rebuild cmd/link to modify the magic value in pclntab
This value is hard-coded in the linker and written in a header.
We could rewrite the final binary, like we used to do with import paths,
but that would require once again maintaining libraries to do so.

Instead, we're now modifying the linker to do what we want.
It's not particularly hard, as every Go install has its source code,
and rebuilding a slightly modified linker only takes a few seconds at most.

Thanks to `go build -overlay`, we only need to copy the files we modify,
and right now we're just modifying one file in the toolchain.
We use a git patch, as the change is fairly static and small,
and the patch is easier to understand and maintain.

The other side of this change is in the runtime,
as it also hard-codes the magic value when loading information.
We modify the code via syntax trees in that case, like `-tiny` does,
because the change is tiny (one literal) and the affected lines of code
are modified regularly between major Go releases.

Since rebuilding a slightly modified linker can take a few seconds,
and Go's build cache does not cache linked binaries,
we keep our own cached version of the rebuilt binary in `os.UserCacheDir`.

The feature isn't perfect, and will be improved in the future.
See the TODOs about the added dependency on `git`,
or how we are currently only able to cache one linker binary at once.

Fixes #622.
1 year ago
Daniel Martí 58b2d64784 drop support for Go 1.18.x
With Go 1.19 having been out for two months,
and Go 1.20's first beta coming out in two months,
it is now time to move forward again.
2 years ago
Daniel Martí fa35e6d81c bump dependencies and gotip version
No breaking changes in Go master so far.
2 years ago
Daniel Martí c9337022a0 bump gotip and x/exp, mention 1.19 in the changelog 2 years ago
Daniel Martí 61bd95bb89 add a test with generic code
This ensures that we support obfuscating builds containing the use of
type parameters, the new feature in Go 1.18.
The test is small for now, but we can extend it over time.

There was just one bug that kept the code from obfuscating properly;
that has been fixed in https://go.dev/cl/405194,
and we update x/tools to the latest master version to include it.

Fixes #414.
2 years ago
Daniel Martí 6118c795c6 various version bumps
Use a gotip version that's a month newer.

Update to the latest staticcheck version, which supports Go 1.18.

Update all direct dependencies as well.
2 years ago
Daniel Martí 1c564ef091 slightly improve code thanks to Go 1.18 APIs
strings.Cut makes some string handling code more intuitive.
Note that we can't use it everywhere, as some places need LastIndexByte.

Start using x/exp/slices, too, which is our first use of generics.
Note that its API is experimental and may still change,
but since we are not a library, we can control its version updates.

I also noticed that we were using TrimSpace for importcfg files.
It's actually unnecessary if we swap strings.SplitAfter for Split,
as the only whitespace present was the trailing newline.

While here, I noticed an unused copy of printfWithoutPackage.
2 years ago
lu4p 1a0b028db7 all: drop support for Go 1.17
Now that we've released v0.6.0, that will be the last feature release to
feature support for Go 1.17. The upcoming v0.7.0 will be Go 1.18+.

Code-wise, the cleanup here isn't super noticeable,
but it will be easier to work on features like VCS-aware version
information and generics support without worrying about Go 1.17.
Plus, now CI is back to being much faster.

Note how "go 1.18" in go.mod makes "go mod tidy" more aggressive.
2 years ago
Daniel Martí 1db12b7118 update Go module deps
Mainly for the x/tools update before the upcoming release,
and for Go 1.18 support.
2 years ago
Daniel Martí f497821174 redesign benchmark to be more useful and realistic
First, join the two benchmarks into one.
The previous "cached" benchmark was borderline pointless,
as it built the same package with the existing output binary,
so it would quickly realise it had nothing to do and take ~100ms.

The previous "noncached" benchmark input had no dependencies,
so it was only really benchmarking the non-obfuscation of the runtime.
All in all, neither benchmark measured obfuscating multiple packages.

The new benchmark reuses the "cached" input, but with GOCACHE="*",
meaning that we now obfuscate dozens of standard library packages.

Each iteration first does a built from scratch, the worst case scenario,
and then does an incremental rebuild of just the main package,
which is the closest to a best case scenario without being a no-op.

Since each iteration now performs both kinds of builds,
we include a new "cached-time" metric to report what portion of the
"time" metric corresponds to the incremental build.
Thus, we can see a clean build takes ~11s, and a cached takes ~0.3s:

	name      time/op
	Build-16      11.6s ± 1%

	name      bin-B
	Build-16      5.34M ± 0%

	name      cached-time/op
	Build-16      326ms ± 5%

	name      sys-time/op
	Build-16      184ms ±13%

	name      user-time/op
	Build-16      611ms ± 5%

The benchmark is also no logner parallel; see the docs.

Note that the old benchmark also reported bin-B incorrectly,
as it looked at the binary size of garble itself, not the input program.
2 years ago
Daniel Martí f7ed99aa25 mod: update dependencies
Now that we've done the bugfix release.
2 years ago
lu4p a645929151
obfuscate literals via constant folding
Constants don't need to be added to ignoreObjs anymore,
because go/types now does this work for us.

Fixes #360
3 years ago
Dan Kortschak d92e63365b fix runtime stripping for Go 1.18
In Go 1.18 runtime/internal/sys is replaced with internal/goarch. This
change makes sure that when running garble after the runtime package
change, runtime stripping correctly removes the unused import.

Also bump go-internal version to work with go1.18, but disable go1.18 in
CI tests.
3 years ago
Daniel Martí 7ede21c981 drop support for Go 1.16.x
We can now use pruned module graphs in go.mod files,
and we no longer need to worry about runtime/internal/sys.

Note that I had to update testdata/mod slightly,
as the new pruned module graphs algorithm downloads an extra go.mod file.

This change also paves the way towards future Go 1.18 support.

Thanks to lu4p for cleaning up two TODOs as well.

Co-Authored-By: lu4p <lu4p@pm.me>
3 years ago
Daniel Martí 816954b9ba mod: update direct deps 3 years ago
Daniel Martí c2a75d09d5 test against a newer tip
We're just a couple of weeks away from the final release, so
double-check that we still work well with tip.

Update x/tools as well, as it has had some minor fixes for Go 1.17.
3 years ago
Daniel Martí ff361f6b15 mod: update direct deps
Via: go get -t -u ./...
3 years ago
Daniel Martí 140de22f87 update direct deps 3 years ago
Daniel Martí ff0bea73b5
all: drop support for Go 1.15.x (#265)
This mainly cleans up the few bits of code where we explicitly kept
support for Go 1.15.x. With v0.1.0 released, we can drop support now,
since the next v0.2.0 release will only support Go 1.16.x.

Also updates all modules, including test ones, to 'go 1.16'.

Note that the TOOLEXEC_IMPORTPATH refactor is not done here, despite all
the TODOs about doing so when we drop 1.15 support. This is because that
refactor needs to be done carefully and might have side effects, so it's
best to keep it to a separate commit.

Finally, update the deps.
3 years ago
Daniel Martí 05d0dd1801
reimplement import path obfuscation without goobj2 (#242)
We used to rely on a parallel implementation of an object file parser
and writer to be able to obfuscate import paths. After compiling each
package, we would parse the object file, replace the import paths, and
write the updated object file in-place.

That worked well, in most cases. Unfortunately, it had some flaws:

* Complexity. Even when most of the code is maintained in a separate
  module, the import_obfuscation.go file was still close to a thousand
  lines of code.

* Go compatibility. The object file format changes between Go releases,
  so we were supporting Go 1.15, but not 1.16. Fixing the object file
  package to work with 1.16 would probably break 1.15 support.

* Bugs. For example, we recently had to add a workaround for #224, since
  import paths containing dots after the domain would end up escaped.
  Another example is #190, which seems to be caused by the object file
  parser or writer corrupting the compiled code and causing segfaults in
  some rare edge cases.

Instead, let's drop that method entirely, and force the compiler and
linker to do the work for us. The steps necessary when compiling a
package to obfuscate are:

1) Replace its "package foo" lines with the obfuscated package path. No
   need to separate the package path and name, since the obfuscated path
   does not contain slashes.

2) Replace the "-p pkg/foo" flag with the obfuscated path.

3) Replace the "import" spec lines with the obfuscated package paths,
   for those dependencies which were obfuscated.

4) Replace the "-importcfg [...]" file with a version that uses the
   obfuscated paths instead.

The linker also needs that last step, since it also uses an importcfg
file to find object files.

There are three noteworthy drawbacks to this new method:

1) Since we no longer write object files, we can't use them to store
   data to be cached. As such, the -debugdir flag goes back to using the
   "-a" build flag to always rebuild all packages. On the plus side,
   that caching didn't work very well; see #176.

2) The package name "main" remains in all declarations under it, not
   just "func main", since we can only rename entire packages. This
   seems fine, as it gives little information to the end user.

3) The -tiny mode no longer sets all lines to 0, since it did that by
   modifying object files. As a temporary measure, we instead set all
   top-level declarations to be on line 1. A TODO is added to hopefully
   improve this again in the near future.

The upside is that we get rid of all the issues mentioned before. Plus,
garble now nearly works with Go 1.16, with the exception of two very
minor bugs that look fixable. A follow-up PR will take care of that and
start testing on 1.16.

Fixes #176.
Fixes #190.
3 years ago
Daniel Martí 1db6e1e230
make -coverprofile include toolexec processes (#216)
testscript already included magic to also account for commands in the
total code coverage. That does not happen with plain tests, since those
only include coverage from the main test process.

The main problem was that, before, indirectly executed commands did not
properly save their coverage profile anywhere for testscript to collect
it at the end. In other words, we only collected coverage from direct
garble executions like "garble -help", but not indirect ones like "go
build -toolexec=garble".

	$ go test -coverprofile=cover.out
	PASS
	coverage: 3.6% of statements
	total coverage: 16.6% of statements
	ok  	mvdan.cc/garble	6.453s

After the delicate changes to testscript, any direct or indirect
executions of commands all go through $PATH and properly count towards
the total coverage:

	$ go test -coverprofile=cover.out
	PASS
	coverage: 3.6% of statements
	total coverage: 90.5% of statements
	ok  	mvdan.cc/garble	33.258s

Note that we can also get rid of our code to set up $PATH, since
testscript now does it for us.

goversion.txt needed minor tweaks, since we no longer set up $WORK/.bin.

Finally, note that we disable the reuse of $GOCACHE when collecting
coverage information. This is to do "full builds", as otherwise the
cached package builds would result in lower coverage.

Fixes #35.
3 years ago
Daniel Martí 8cae98ca1b
mod: bump dependencies (#207)
Nothing too special, as all tests pass the same.
3 years ago
Andrew LeFevre 8c03afee95
Use latest Binject/debug version to support importmap directives, fixes #146 (#189)
* Use latest Binject/debug version to support importmap directives in the importcfg file

* Uncomment line in goprivate testscript to test ImportMap

* Fixed issue where a package in specified in importmap would be hashed differently in a package that imported it, due to the mapping of import paths.

Also commented out the 'net' import in the goprivate testscript (again) due to cgo compile errors
4 years ago
pagran 803c1d9439
Store obfuscated sources in object files (#158)
Now the flag "-debugdir" does not trigger a full recompilation.
Obfuscated source files are saved to object files and are extracted during linking.
4 years ago
Daniel Martí 1e19d136c7 testdata: make syntax.txt pass when offline
The test intended to use an extra module to be obfuscated, rsc.io/quote,
which we were bundling in the local proxy as well. Unfortunately, the
use of GOPRIVATE also meant that we did not actually fetch the module
from the proxy, and we would instead do a full roundtrip to the internet
to "git clone" the actual upstream repository.

To prevent that roundtrip, instead use a locally replaced module. This
fits the syntax.txt test too, since it's one more edge case that we want
to make sure works well with garble. Since rsc.io/quote is used in
another test, simply make up our own tiny module.

Reduces a 'go test -run Syntax/syntax' run with warm cache from ~5s to
~0.5s, thanks to removing the multiple roundtrips. A warm 'go test' run
still sits at ~6s, since we still need that much CPU time in total.

While at it, fix a staticcheck warning and fix inconsistent indentation
in a couple of tests.
4 years ago
Daniel Martí 88450a2cbc
update Binject/debug dependency to get its license file (#148)
See https://github.com/Binject/debug/issues/12.

Also update x/tools, while at it.
4 years ago
Andrew LeFevre c8d61c772f
Garble imports and package paths in GOPRIVATE (#116)
Finally, finally this is done. This allows import paths to be obfuscated by modifying
object/archive files and garbling import paths contained within. The bulk of the
code that makes parsing and writing Go object/archive files possible lives at
https://github.com/Binject/debug/tree/master/goobj2, which I wrote as well.

I have tested by garbling and checking for import paths via strings and grep
(in order of difficulty) https://github.com/lu4p/binclude, garble itself, and
https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck.

This only supports object/archive files produced from the Go 1.15 compiler.
The object file format changed at 1.15, and 1.14 and earlier is not supported.

Fixes #13.
4 years ago
Daniel Martí 1bff68d8c8 update go-internal to fix go 1.16
CI's gotip job should now succeed.
4 years ago
Daniel Martí b250b64d2c
update dependency versions, drop Go 1.14
Most notably, x/mod now includes the GOPRIVATE pattern-matching API we
were copying before, so we can use it directly.

Also bump the Go version requirement to 1.15, in preparation for the
import path obfuscation PR, and don't let the gotip job fail the entire
workflow.
4 years ago
Daniel Martí 65461aabce reuse a single 'go list -json -export -deps' call
Instead of doing a 'go list' call every time we need to fetch a
dependency's export file, we now do a single 'go list' call before the
build begins. With the '-deps' flag, it gives us all the dependency
packages recursively.

We store that data in the gob format in a temporary file, and share it
with the future garble sub-processes via an env var.

This required lazy parsing of flags for the 'build' and 'test' commands,
since now we need to run 'go list' with the same package pattern
arguments.

Fixes #63.
4 years ago
lu4p 44f638e84d
upgrade dependencies 4 years ago
Daniel Martí b8aec97e86 don't garble any embedded fields
In the added test case, we'd see a failure, since we garbled the name of
the "Embedded" type but not its use as an anonymous field. Garble both.

This might possibly break some reflect code, but it doesn't seem like we
have an option. When we garble a type, it's impossible to tell if it's
going to be used as an anonymous field later.

Updates #9.
4 years ago
Daniel Martí 39802aae19 update deps 4 years ago
Daniel Martí aba66758ca support type switches with symbolic vars 5 years ago
Daniel Martí f5f72ef626 initial commit 5 years ago