rewrite private name map storage to support build caching

We now store how we obfuscated unexported names in the object file
itself, not a separate file. This means that the data can survive in the
build cache, whereas the separate file was being lost. Luckily, we can
just add an extra header to the archive, and other programs like the Go
linker will just ignore it.
pull/145/head
pagran 4 years ago committed by GitHub
parent 5c6fa4575f
commit 406036d433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,10 +7,8 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath"
"sort" "sort"
"strings" "strings"
@ -47,18 +45,18 @@ type privateImports struct {
privateNames []string privateNames []string
} }
func appendPrivateNameMap(nameMap map[string]string, packageDirectory string) error { func appendPrivateNameMap(pkg *goobj2.Package, nameMap map[string]string) error {
file, err := os.Open(filepath.Join(packageDirectory, garbleMapFile)) for _, member := range pkg.ArchiveMembers {
if errors.Is(err, os.ErrNotExist) { if member.ArchiveHeader.Name != garbleMapHeaderName {
return nil continue
} }
if err != nil {
return err
}
defer file.Close()
if err := json.NewDecoder(file).Decode(&nameMap); err != nil { serializedMap := member.ArchiveHeader.Data
return err serializedMap = serializedMap[:bytes.IndexByte(serializedMap, 0x00)]
if err := json.Unmarshal(serializedMap, &nameMap); err != nil {
return err
}
return nil
} }
return nil return nil
} }
@ -87,8 +85,7 @@ func obfuscateImports(objPath, importCfgPath string) (garbledImports, privateNam
pkgs = append(pkgs, pkgInfo{pkg, info.Path, private}) pkgs = append(pkgs, pkgInfo{pkg, info.Path, private})
packageDir := filepath.Dir(info.Path) if err := appendPrivateNameMap(pkg, privateNameMap); err != nil {
if err := appendPrivateNameMap(privateNameMap, packageDir); err != nil {
return nil, nil, fmt.Errorf("error parsing name map %s at %s: %v", pkgPath, info.Path, err) return nil, nil, fmt.Errorf("error parsing name map %s at %s: %v", pkgPath, info.Path, err)
} }
} }

@ -31,6 +31,7 @@ import (
"time" "time"
"unicode" "unicode"
"github.com/Binject/debug/goobj2"
"golang.org/x/mod/module" "golang.org/x/mod/module"
"golang.org/x/mod/semver" "golang.org/x/mod/semver"
"golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/ast/astutil"
@ -115,7 +116,7 @@ var (
seed []byte seed []byte
) )
const garbleMapFile = "garble.map" const garbleMapHeaderName = "garble/nameMap"
func saveListedPackages(w io.Writer, flags, patterns []string) error { func saveListedPackages(w io.Writer, flags, patterns []string) error {
args := []string{"list", "-json", "-deps", "-export"} args := []string{"list", "-json", "-deps", "-export"}
@ -664,17 +665,36 @@ func transformCompile(args []string) ([]string, error) {
} }
if len(privateNameMap) > 0 { if len(privateNameMap) > 0 {
outputDirectory := filepath.Dir(flagValue(flags, "-o")) objPath := flagValue(flags, "-o")
importcfg := flagValue(flags, "-importcfg")
deferred = append(deferred, func() error {
importCfg, err := goobj2.ParseImportCfg(importcfg)
if err != nil {
return err
}
file, err := os.Create(filepath.Join(outputDirectory, garbleMapFile)) pkg, err := goobj2.Parse(objPath, pkgPath, importCfg)
if err != nil { if err != nil {
return nil, err return err
} }
defer file.Close()
if err := json.NewEncoder(file).Encode(privateNameMap); err != nil { data, err := json.Marshal(privateNameMap)
return nil, err 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: garbleMapHeaderName,
Size: int64(len(data)),
Data: data,
},
})
return pkg.Write(objPath)
})
} }
return append(flags, newPaths...), nil return append(flags, newPaths...), nil

Loading…
Cancel
Save