From 79c775e2187c686ae777f7d92bed96305fe8746f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Tue, 16 Feb 2021 11:20:51 +0000 Subject: [PATCH] obfuscate unexported names like exported ones (#227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 90fa325da7, the obfuscation logic was changed to use hashes for exported names, but incremental names starting at just one letter for unexported names. Presumably, this was done for the sake of binary size. I argue that this is not a good idea for the default mode for a number of reasons: 1) It makes reversing of stack traces nearly impossible for unexported names, since replacing an obfuscated name "c" with "originalName" would trigger too many false positives by matching single characters. 2) Exported and unexported names aren't different. We need to know how names were obfuscated at a later time in both cases, thanks to use cases like -ldflags=-X. Using short names for one but not the other doesn't make a lot of sense, and makes the logic inconsistent. 3) Shaving off three bytes for unexported names doesn't seem like a huge deal for the default mode, when we already have -tiny to optimize for size. This saves us a bit of work, but most importantly, simplifies the obfuscation state as we no longer need to carry privateNameMap between the compile and link stages. name old time/op new time/op delta Build-8 153ms ± 2% 150ms ± 2% ~ (p=0.065 n=6+6) name old bin-B new bin-B delta Build-8 7.09M ± 0% 7.08M ± 0% -0.24% (p=0.002 n=6+6) name old sys-time/op new sys-time/op delta Build-8 296ms ± 5% 277ms ± 6% -6.50% (p=0.026 n=6+6) name old user-time/op new user-time/op delta Build-8 562ms ± 1% 558ms ± 3% ~ (p=0.329 n=5+6) Note that I do not oppose using short names for both exported and unexported names in the future for -tiny, since reversing of stack traces will by design not work there. The code can be resurrected from the git history if we want to improve -tiny that way in the future, as we'd need to store state in header files again. Another major cleanup we can do here is to no longer use the garbledImports map. From a look at obfuscateImports, we hash a package's import path with its action ID, much like exported names, so we can simply re-do that hashing for the linker's -X flag. garbledImports does have some logic to handle duplicate package names, but it's worth noting that should not affect package paths, as they are always unique. That area of code could probably do with some simplification in the future, too. While at it, make hashWith panic if either parameter is empty. obfuscateImports was hashing the main package path without a salt due to a bug, so we want to catch those in the future. Finally, make some tiny spacing and typo tweaks to the README. --- README.md | 15 +++--- bench_test.go | 9 +++- hash.go | 41 +++------------ import_obfuscation.go | 100 ++++++++++++++--------------------- main.go | 104 ++++--------------------------------- testdata/scripts/basic.txt | 2 +- 6 files changed, 72 insertions(+), 199 deletions(-) diff --git a/README.md b/README.md index 7e8cbce..f195379 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ order to: * Strip filenames and shuffle position information * Strip debugging information and symbol tables * Obfuscate literals, if the `-literals` flag is given -* Removes [extra information](#tiny-mode) if the `-tiny` flag is given +* Remove [extra information](#tiny-mode) if the `-tiny` flag is given ### Options @@ -59,22 +59,23 @@ to document the current shortcomings of this tool. Command string Args string } - + // never obfuscate the Message type var _ = reflect.TypeOf(Message{}) ``` ### Tiny Mode -When the `-tiny` flag is passed, extra information is stripped from the resulting -Go binary. This includes line numbers, filenames, and code in the runtime the -prints panics, fatal errors, and trace/debug info. All in all this can make binaries +When the `-tiny` flag is passed, extra information is stripped from the resulting +Go binary. This includes line numbers, filenames, and code in the runtime the +prints panics, fatal errors, and trace/debug info. All in all this can make binaries 6-10% smaller in our testing. Note: if `-tiny` is passed, no panics, fatal errors will ever be printed, but they can -still be handled internally with `recover` as normal. In addition, the `GODEBUG` +still be handled internally with `recover` as normal. In addition, the `GODEBUG` environmental variable will be ignored. ### Contributing -We actively seek new contributors, if you would like to contribute to garble use the + +We actively seek new contributors, if you would like to contribute to garble use the [CONTRIBUTING.md](CONTRIBUTING.md) as a starting point. diff --git a/bench_test.go b/bench_test.go index ea22217..e89a9dc 100644 --- a/bench_test.go +++ b/bench_test.go @@ -45,8 +45,8 @@ func BenchmarkBuild(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { cmd := exec.Command(garbleBin, "build", "./testdata/bench") - if err := cmd.Run(); err != nil { - b.Fatal(err) + if out, err := cmd.CombinedOutput(); err != nil { + b.Fatalf("%v: %s", err, out) } atomic.AddInt64(&n, 1) @@ -56,4 +56,9 @@ func BenchmarkBuild(b *testing.B) { }) b.ReportMetric(float64(userTime)/float64(n), "user-ns/op") b.ReportMetric(float64(systemTime)/float64(n), "sys-ns/op") + info, err := os.Stat(garbleBin) + if err != nil { + b.Fatal(err) + } + b.ReportMetric(float64(info.Size()), "bin-B") } diff --git a/hash.go b/hash.go index e6312c0..729328a 100644 --- a/hash.go +++ b/hash.go @@ -13,7 +13,6 @@ import ( "os" "os/exec" "strings" - "unicode" ) const buildIDSeparator = "/" @@ -143,6 +142,12 @@ func buildidOf(path string) (string, error) { } func hashWith(salt []byte, name string) string { + if len(salt) == 0 { + panic("hashWith: empty salt") + } + if name == "" { + panic("hashWith: empty name") + } const length = 4 d := sha256.New() @@ -156,37 +161,3 @@ func hashWith(salt []byte, name string) string { } return "z" + sum[:length] } - -func buildNameCharset() []rune { - var charset []rune - - for _, r := range unicode.Letter.R16 { - for c := r.Lo; c <= r.Hi; c += r.Stride { - charset = append(charset, rune(c)) - } - } - - for _, r := range unicode.Digit.R16 { - for c := r.Lo; c <= r.Hi; c += r.Stride { - charset = append(charset, rune(c)) - } - } - - return charset -} - -var privateNameCharset = buildNameCharset() - -func encodeIntToName(i int) string { - builder := strings.Builder{} - for i > 0 { - charIdx := i % len(privateNameCharset) - i -= charIdx + 1 - c := privateNameCharset[charIdx] - if builder.Len() == 0 && !unicode.IsLetter(c) { - builder.WriteByte('_') - } - builder.WriteRune(c) - } - return builder.String() -} diff --git a/import_obfuscation.go b/import_obfuscation.go index 189232c..b6da4e6 100644 --- a/import_obfuscation.go +++ b/import_obfuscation.go @@ -8,7 +8,6 @@ import ( "bufio" "bytes" "compress/gzip" - "encoding/json" "fmt" "io" "io/ioutil" @@ -59,22 +58,6 @@ type privateName struct { seed []byte } -func appendPrivateNameMap(pkg *goobj2.Package, nameMap map[string]string) error { - for _, member := range pkg.ArchiveMembers { - if member.ArchiveHeader.Name != headerPrivateNameMap { - continue - } - - serializedMap := member.ArchiveHeader.Data - serializedMap = serializedMap[:bytes.IndexByte(serializedMap, 0x00)] - if err := json.Unmarshal(serializedMap, &nameMap); err != nil { - return err - } - return nil - } - return nil -} - // extractDebugObfSrc extracts obfuscated sources from object files if -debugdir flag is enabled. func extractDebugObfSrc(pkgPath string, pkg *goobj2.Package) error { if opts.DebugDir == "" { @@ -153,21 +136,20 @@ func extractDebugObfSrc(pkgPath string, pkg *goobj2.Package) error { // It returns the path to the modified main object file, to be used for linking. // We also return a map of how the imports were garbled, as well as the private // name map recovered from the archive files, so that we can amend -X flags. -func obfuscateImports(objPath string, importMap goobj2.ImportMap) (garbledObj string, garbledImports, privateNameMap map[string]string, _ error) { +func obfuscateImports(objPath string, importMap goobj2.ImportMap) (garbledObj string, _ error) { mainPkg, err := goobj2.Parse(objPath, "main", importMap) if err != nil { - return "", nil, nil, fmt.Errorf("error parsing main objfile: %v", err) + return "", fmt.Errorf("error parsing main objfile: %v", err) } if err := extractDebugObfSrc("main", mainPkg); err != nil { - return "", nil, nil, err + return "", err } pkgs := []pkgInfo{{mainPkg, objPath, true}} - privateNameMap = make(map[string]string) // build list of imported packages that are private importCfg, err := goobj2.ParseImportCfg(curImportCfg) if err != nil { - return "", nil, nil, err + return "", err } for pkgPath, info := range importCfg.Packages { // if the '-tiny' flag is passed, we will strip filename @@ -175,18 +157,15 @@ func obfuscateImports(objPath string, importMap goobj2.ImportMap) (garbledObj st if private := isPrivate(pkgPath); opts.Tiny || private { pkg, err := goobj2.Parse(info.Path, pkgPath, importMap) if err != nil { - return "", nil, nil, fmt.Errorf("error parsing objfile %s at %s: %v", pkgPath, info.Path, err) + return "", fmt.Errorf("error parsing objfile %s at %s: %v", pkgPath, info.Path, err) } pkgs = append(pkgs, pkgInfo{pkg, info.Path, private}) - if err := appendPrivateNameMap(pkg, privateNameMap); err != nil { - return "", nil, nil, fmt.Errorf("error parsing name map %s at %s: %v", pkgPath, info.Path, err) - } // Avoiding double extraction from main object file if objPath != info.Path { if err := extractDebugObfSrc(pkgPath, pkg); err != nil { - return "", nil, nil, err + return "", err } } } @@ -195,7 +174,6 @@ func obfuscateImports(objPath string, importMap goobj2.ImportMap) (garbledObj st var sb strings.Builder var buf bytes.Buffer - garbledImports = make(map[string]string) replacedFiles := make(map[string]string) for _, p := range pkgs { // log.Printf("++ Obfuscating object file for %s ++", p.pkg.ImportPath) @@ -233,7 +211,7 @@ func obfuscateImports(objPath string, importMap goobj2.ImportMap) (garbledObj st privImports.privatePaths = append(privImports.privatePaths, privPaths...) privImports.privateNames = append(privImports.privateNames, privNames...) - return hashImport(imp, nil, garbledImports) + return hashImport(imp, nil) } for i := range am.Imports { @@ -268,7 +246,7 @@ func obfuscateImports(objPath string, importMap goobj2.ImportMap) (garbledObj st // log.Printf("\t== Private imports: %v ==\n", privImports) // garble all private import paths in all symbol names - garbleSymbols(&am, privImports, garbledImports, &buf, &sb) + garbleSymbols(&am, privImports, &buf, &sb) } // An archive under the temporary file. Note that @@ -276,22 +254,22 @@ func obfuscateImports(objPath string, importMap goobj2.ImportMap) (garbledObj st // simply use its name after closing the file. tempObjFile, err := ioutil.TempFile(sharedTempDir, "pkg.*.a") if err != nil { - return "", nil, nil, fmt.Errorf("creating temp file: %v", err) + return "", fmt.Errorf("creating temp file: %v", err) } tempObj := tempObjFile.Name() tempObjFile.Close() if err := p.pkg.Write(tempObj); err != nil { - return "", nil, nil, fmt.Errorf("error writing objfile %s at %s: %v", p.pkg.ImportPath, p.path, err) + return "", fmt.Errorf("error writing objfile %s at %s: %v", p.pkg.ImportPath, p.path, err) } replacedFiles[p.path] = tempObj } // garble importcfg so the linker knows where to find garbled imports - if err := garbleImportCfg(curImportCfg, importCfg, garbledImports, replacedFiles); err != nil { - return "", nil, nil, err + if err := garbleImportCfg(curImportCfg, importCfg, replacedFiles); err != nil { + return "", err } - return replacedFiles[objPath], garbledImports, privateNameMap, nil + return replacedFiles[objPath], nil } // stripPCLinesAndNames removes all filename and position info @@ -446,23 +424,23 @@ func dedupPrivateNames(names []privateName) []privateName { return names[:j] } -func hashImport(pkg string, seed []byte, garbledImports map[string]string) string { - if seed == nil { - if garbledPkg, ok := garbledImports[pkg]; ok { - return garbledPkg +func hashImport(pkg string, seed []byte) string { + if len(seed) == 0 { + pkgPath := pkg + if pkgPath == "main" { + // The main package is known under its import path in + // the import config map. + pkgPath = buildInfo.firstImport } - seed = buildInfo.imports[pkg].actionID + seed = buildInfo.imports[pkgPath].actionID } - garbledPkg := hashWith(seed, pkg) - garbledImports[pkg] = garbledPkg - - return garbledPkg + return hashWith(seed, pkg) } // garbleSymbols replaces all private import paths/package names in symbol names // and data of an archive member. -func garbleSymbols(am *goobj2.ArchiveMember, privImports privateImports, garbledImports map[string]string, buf *bytes.Buffer, sb *strings.Builder) { +func garbleSymbols(am *goobj2.ArchiveMember, privImports privateImports, buf *bytes.Buffer, sb *strings.Builder) { lists := [][]*goobj2.Sym{am.SymDefs, am.NonPkgSymDefs, am.NonPkgSymRefs} for _, list := range lists { for _, s := range list { @@ -493,26 +471,26 @@ func garbleSymbols(am *goobj2.ArchiveMember, privImports privateImports, garbled } else if strings.HasPrefix(s.Name, "type..namedata.") { dataTyp = namedata } - s.Data = garbleSymData(s.Data, privImports, garbledImports, dataTyp, buf) + s.Data = garbleSymData(s.Data, privImports, dataTyp, buf) if s.Size != 0 { s.Size = uint32(len(s.Data)) } } - s.Name = garbleSymbolName(s.Name, privImports, garbledImports, sb) + s.Name = garbleSymbolName(s.Name, privImports, sb) for i := range s.Reloc { - s.Reloc[i].Name = garbleSymbolName(s.Reloc[i].Name, privImports, garbledImports, sb) + s.Reloc[i].Name = garbleSymbolName(s.Reloc[i].Name, privImports, sb) } if s.Type != nil { - s.Type.Name = garbleSymbolName(s.Type.Name, privImports, garbledImports, sb) + s.Type.Name = garbleSymbolName(s.Type.Name, privImports, sb) } if s.Func != nil { for i := range s.Func.FuncData { - s.Func.FuncData[i].Sym.Name = garbleSymbolName(s.Func.FuncData[i].Sym.Name, privImports, garbledImports, sb) + s.Func.FuncData[i].Sym.Name = garbleSymbolName(s.Func.FuncData[i].Sym.Name, privImports, sb) } for _, inl := range s.Func.InlTree { - inl.Func.Name = garbleSymbolName(inl.Func.Name, privImports, garbledImports, sb) + inl.Func.Name = garbleSymbolName(inl.Func.Name, privImports, sb) if opts.Tiny { inl.Line = 1 } @@ -533,7 +511,7 @@ func garbleSymbols(am *goobj2.ArchiveMember, privImports privateImports, garbled } } for i := range am.SymRefs { - am.SymRefs[i].Name = garbleSymbolName(am.SymRefs[i].Name, privImports, garbledImports, sb) + am.SymRefs[i].Name = garbleSymbolName(am.SymRefs[i].Name, privImports, sb) } // remove dwarf file list, it isn't needed as we pass "-w, -s" to the linker @@ -542,7 +520,7 @@ func garbleSymbols(am *goobj2.ArchiveMember, privImports privateImports, garbled // garbleSymbolName finds all private imports in a symbol name, garbles them, // and returns the modified symbol name. -func garbleSymbolName(symName string, privImports privateImports, garbledImports map[string]string, sb *strings.Builder) string { +func garbleSymbolName(symName string, privImports privateImports, sb *strings.Builder) string { prefix, name, skipSym := splitSymbolPrefix(symName) if skipSym { // log.Printf("\t\t? Skipped symbol: %s", symName) @@ -572,7 +550,7 @@ func garbleSymbolName(symName string, privImports privateImports, garbledImports } sb.WriteString(name[off : off+o]) - sb.WriteString(hashImport(name[off+o:off+o+l], privName.seed, garbledImports)) + sb.WriteString(hashImport(name[off+o:off+o+l], privName.seed)) off += o + l } @@ -748,7 +726,7 @@ func isSymbol(c byte) bool { // garbleSymData finds all private imports in a symbol's data blob, // garbles them, and returns the modified symbol data. -func garbleSymData(data []byte, privImports privateImports, garbledImports map[string]string, dataTyp dataType, buf *bytes.Buffer) []byte { +func garbleSymData(data []byte, privImports privateImports, dataTyp dataType, buf *bytes.Buffer) []byte { var symData []byte switch dataTyp { case importPath: @@ -772,11 +750,11 @@ func garbleSymData(data []byte, privImports privateImports, garbledImports map[s // there is only one import path in the symbol's data, garble it and return if dataTyp == importPath { - return createImportPathData(hashImport(string(symData[o:o+l]), privName.seed, garbledImports)) + return createImportPathData(hashImport(string(symData[o:o+l]), privName.seed)) } buf.Write(symData[off : off+o]) - buf.WriteString(hashImport(string(symData[off+o:off+o+l]), privName.seed, garbledImports)) + buf.WriteString(hashImport(string(symData[off+o:off+o+l]), privName.seed)) off += o + l } @@ -817,7 +795,7 @@ func patchReflectData(newName []byte, data []byte) []byte { } // garbleImportCfg writes a new importcfg with private import paths garbled. -func garbleImportCfg(path string, importCfg goobj2.ImportCfg, garbledImports, replacedFiles map[string]string) error { +func garbleImportCfg(path string, importCfg goobj2.ImportCfg, replacedFiles map[string]string) error { newCfg, err := os.Create(path) if err != nil { return fmt.Errorf("error creating importcfg: %v", err) @@ -827,10 +805,10 @@ func garbleImportCfg(path string, importCfg goobj2.ImportCfg, garbledImports, re for pkgPath, otherPath := range importCfg.ImportMap { if isPrivate(pkgPath) { - pkgPath = hashImport(pkgPath, nil, garbledImports) + pkgPath = hashImport(pkgPath, nil) } if isPrivate(otherPath) { - otherPath = hashImport(otherPath, nil, garbledImports) + otherPath = hashImport(otherPath, nil) } newCfgWr.WriteString("importmap ") newCfgWr.WriteString(pkgPath) @@ -841,7 +819,7 @@ func garbleImportCfg(path string, importCfg goobj2.ImportCfg, garbledImports, re for pkgPath, info := range importCfg.Packages { if isPrivate(pkgPath) { - pkgPath = hashImport(pkgPath, nil, garbledImports) + pkgPath = hashImport(pkgPath, nil) } if info.IsSharedLib { newCfgWr.WriteString("packageshlib ") diff --git a/main.go b/main.go index 73b5aa9..a11e3cf 100644 --- a/main.go +++ b/main.go @@ -128,8 +128,7 @@ var ( const ( // Note that these are capped at 16 bytes. - headerPrivateNameMap = "garble/privMap" - headerDebugSource = "garble/debugSrc" + headerDebugSource = "garble/debugSrc" ) func garbledImport(path string) (*types.Package, error) { @@ -465,8 +464,6 @@ func transformCompile(args []string) ([]string, func() error, error) { return nil, nil, fmt.Errorf("typecheck error: %v", err) } - tf.privateNameMap = make(map[string]string) - tf.existingNames = collectExistingNames(files) tf.recordReflectArgs(files) if opts.GarbleLiterals { @@ -583,19 +580,9 @@ func transformCompile(args []string) ([]string, func() error, error) { return err } - nameMap, err := json.Marshal(tf.privateNameMap) - if err != nil { - return err - } - // Adding an extra archive header is safe, // and shouldn't break other tools like the linker since our header name is unique pkg.ArchiveMembers = append(pkg.ArchiveMembers, - goobj2.ArchiveMember{ArchiveHeader: goobj2.ArchiveHeader{ - Name: headerPrivateNameMap, - Size: int64(len(nameMap)), - Data: nameMap, - }}, goobj2.ArchiveMember{ArchiveHeader: goobj2.ArchiveHeader{ Name: headerDebugSource, Size: int64(obfSrcArchive.Len()), @@ -657,14 +644,9 @@ func (tf *transformer) handleDirectives(comments []string) { // The name exists and was obfuscated; replace the // comment with the obfuscated name. - if token.IsExported(name) { - obfName := hashWith(listedPkg.actionID, name) - fields[2] = pkg + "." + obfName - comments[i] = strings.Join(fields, " ") - } else if obfName, ok := tf.privateNameMap[fields[2]]; ok { - fields[2] = pkg + "." + obfName - comments[i] = strings.Join(fields, " ") - } + obfName := hashWith(listedPkg.actionID, name) + fields[2] = pkg + "." + obfName + comments[i] = strings.Join(fields, " ") } } @@ -873,22 +855,6 @@ func (tf *transformer) recordReflectArgs(files []*ast.File) { } } -// collectExistingNames collects all names, including the names of local -// variables, functions, global fields, etc. -func collectExistingNames(files []*ast.File) map[string]bool { - names := make(map[string]bool) - visit := func(node ast.Node) bool { - if ident, ok := node.(*ast.Ident); ok { - names[ident.Name] = true - } - return true - } - for _, file := range files { - ast.Inspect(file, visit) - } - return names -} - // transformer holds all the information and state necessary to obfuscate a // single Go package. type transformer struct { @@ -896,17 +862,6 @@ type transformer struct { pkg *types.Package info *types.Info - // existingNames contains all the existing names in the current package, - // to avoid name collisions. - existingNames map[string]bool - - // privateNameMap records how unexported names were obfuscated. For - // example, "some/pkg.foo" could be mapped to "C" if it was one of the - // first private names to be obfuscated. - // TODO: why include the "some/pkg." prefix if it's always going to be - // the current package? - privateNameMap map[string]string - // ignoreObjects records all the objects we cannot obfuscate. An object // is any named entity, such as a declared variable or type. // @@ -918,11 +873,6 @@ type transformer struct { // * Types or variables from external packages which were not // obfuscated, for caching reasons; see transformGo. ignoreObjects map[types.Object]bool - - // nameCounter keeps track of how many unique identifier names we've - // obfuscated, so that the obfuscated names get assigned incrementing - // short names like "a", "b", "c", etc. - nameCounter int } // transformGo garbles the provided Go syntax node. @@ -1149,33 +1099,8 @@ func (tf *transformer) transformGo(file *ast.File) *ast.File { origName := node.Name _ = origName // used for debug prints below - // The exported names cannot be shortened as counter synchronization - // between packages is not currently implemented - if token.IsExported(node.Name) { - node.Name = hashWith(actionID, node.Name) - // log.Printf("%q hashed with %x to %q", origName, actionID, node.Name) - return true - } - - fullName := tf.pkg.Path() + "." + node.Name - if name, ok := tf.privateNameMap[fullName]; ok { - node.Name = name - // log.Printf("%q retrieved private name %q for %q", origName, name, path) - return true - } - - var name string - for { - tf.nameCounter++ - name = encodeIntToName(tf.nameCounter) - if !tf.existingNames[name] { - break - } - } - - tf.privateNameMap[fullName] = name - node.Name = name - // log.Printf("%q assigned private name %q for %q", origName, name, path) + node.Name = hashWith(actionID, node.Name) + // log.Printf("%q hashed with %x to %q", origName, actionID, node.Name) return true } return astutil.Apply(file, pre, nil).(*ast.File) @@ -1251,7 +1176,7 @@ func transformLink(args []string) ([]string, func() error, error) { importMap := func(importPath string) (objectPath string) { return buildInfo.imports[importPath].packagefile } - garbledObj, garbledImports, privateNameMap, err := obfuscateImports(paths[0], importMap) + garbledObj, err := obfuscateImports(paths[0], importMap) if err != nil { return nil, nil, err } @@ -1279,17 +1204,10 @@ func transformLink(args []string) ([]string, func() error, error) { // the import config map. pkgPath = buildInfo.firstImport } - if id := buildInfo.imports[pkgPath].actionID; len(id) > 0 { - // We use privateNameMap because unexported names are obfuscated - // to short names like "A", "B", "C" etc, which is not reproducible - // here. If the name isn't in the map, a hash will do. - newName, ok := privateNameMap[pkg+"."+name] - if !ok { - newName = hashWith(id, name) - } - garbledPkg := garbledImports[pkg] - flags = append(flags, fmt.Sprintf("-X=%s.%s=%s", garbledPkg, newName, str)) - } + id := buildInfo.imports[pkgPath].actionID + newName := hashWith(id, name) + garbledPkg := hashWith(id, pkg) + flags = append(flags, fmt.Sprintf("-X=%s.%s=%s", garbledPkg, newName, str)) }) // Ensure we strip the -buildid flag, to not leak any build IDs for the diff --git a/testdata/scripts/basic.txt b/testdata/scripts/basic.txt index 915ddad..ee2dbc2 100644 --- a/testdata/scripts/basic.txt +++ b/testdata/scripts/basic.txt @@ -23,7 +23,7 @@ stdout 'unknown' ! stdout $gofullversion # The binary can't contain the version string either. -! binsubstr main$exe ${WORK@R} 'main.go' 'globalVar' 'globalFunc' $gofullversion +! binsubstr main$exe ${WORK@R} 'main.go' 'globalVar' 'globalFunc' 'garble' $gofullversion [short] stop # checking that the build is reproducible is slow