diff --git a/internal/linker/patches/go1.23/0001-add-custom-magic-value.patch b/internal/linker/patches/go1.23/0001-add-custom-magic-value.patch new file mode 100644 index 00000000..12abd2c2 --- /dev/null +++ b/internal/linker/patches/go1.23/0001-add-custom-magic-value.patch @@ -0,0 +1,47 @@ +From a67db18d018b3626e80190cf33b5e7582b6e63cf Mon Sep 17 00:00:00 2001 +From: pagran +Date: Mon, 9 Jan 2023 13:30:00 +0100 +Subject: [PATCH 1/3] add custom magic value + +--- + cmd/link/internal/ld/pcln.go | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go +index 57c88c03af..c09ae07e33 100644 +--- a/cmd/link/internal/ld/pcln.go ++++ b/cmd/link/internal/ld/pcln.go +@@ -4,6 +4,10 @@ + + package ld + ++import ( ++ "os" ++) ++ + import ( + "cmd/internal/goobj" + "cmd/internal/objabi" +@@ -262,6 +266,19 @@ func (state *pclntab) generatePCHeader(ctxt *Link) { + if off != size { + panic(fmt.Sprintf("pcHeader size: %d != %d", off, size)) + } ++ ++ // Use garble prefix in variable names to minimize collision risk ++ garbleMagicStr := os.Getenv("GARBLE_LINK_MAGIC") ++ if garbleMagicStr == "" { ++ panic("[garble] magic value must be set") ++ } ++ var garbleMagicVal uint32 ++ // Use fmt package instead of strconv to avoid importing a new package ++ if _, err := fmt.Sscan(garbleMagicStr, &garbleMagicVal); err != nil { ++ panic(fmt.Errorf("[garble] invalid magic value %s: %v", garbleMagicStr, err)) ++ } ++ ++ header.SetUint32(ctxt.Arch, 0, garbleMagicVal) + } + + state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader) +-- +2.46.0 + diff --git a/internal/linker/patches/go1.23/0002-add-unexported-function-name-removing.patch b/internal/linker/patches/go1.23/0002-add-unexported-function-name-removing.patch new file mode 100644 index 00000000..9cb8373b --- /dev/null +++ b/internal/linker/patches/go1.23/0002-add-unexported-function-name-removing.patch @@ -0,0 +1,85 @@ +From 05b8be787564fdcd9532e1aac5eca3ef41d4e0a1 Mon Sep 17 00:00:00 2001 +From: pagran +Date: Mon, 9 Jan 2023 13:30:36 +0100 +Subject: [PATCH 2/3] add unexported function name removing + +--- + cmd/link/internal/ld/pcln.go | 43 +++++++++++++++++++++++++++++++++++- + 1 file changed, 42 insertions(+), 1 deletion(-) + +diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go +index c09ae07e33..056a1d3a72 100644 +--- a/cmd/link/internal/ld/pcln.go ++++ b/cmd/link/internal/ld/pcln.go +@@ -8,6 +8,10 @@ import ( + "os" + ) + ++import ( ++ "unicode" ++) ++ + import ( + "cmd/internal/goobj" + "cmd/internal/objabi" +@@ -318,19 +322,56 @@ func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) { + func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 { + nameOffsets := make(map[loader.Sym]uint32, state.nfunc) + ++ garbleTiny := os.Getenv("GARBLE_LINK_TINY") == "true" ++ + // Write the null terminated strings. + writeFuncNameTab := func(ctxt *Link, s loader.Sym) { + symtab := ctxt.loader.MakeSymbolUpdater(s) ++ if garbleTiny { ++ symtab.AddStringAt(0, "") ++ } ++ + for s, off := range nameOffsets { ++ if garbleTiny && off == 0 { ++ continue ++ } + symtab.AddCStringAt(int64(off), ctxt.loader.SymName(s)) + } + } + + // Loop through the CUs, and calculate the size needed. + var size int64 ++ ++ if garbleTiny { ++ size = 1 // first byte is reserved for empty string used for all non-exportable method names ++ } ++ // Kinds of SymNames found in the wild: ++ // ++ // * reflect.Value.CanAddr ++ // * reflect.(*Value).String ++ // * reflect.w6cEoKc ++ // * internal/abi.(*RegArgs).IntRegArgAddr ++ // * type:.eq.runtime.special ++ // * runtime/internal/atomic.(*Pointer[go.shape.string]).Store ++ // ++ // Checking whether the first rune after the last dot is uppercase seems enough. ++ isExported := func(name string) bool { ++ for _, r := range name[strings.LastIndexByte(name, '.')+1:] { ++ return unicode.IsUpper(r) ++ } ++ return false ++ } ++ + walkFuncs(ctxt, funcs, func(s loader.Sym) { ++ name := ctxt.loader.SymName(s) ++ ++ if garbleTiny && !isExported(name) { ++ nameOffsets[s] = 0 // redirect name to empty string ++ return ++ } ++ + nameOffsets[s] = uint32(size) +- size += int64(len(ctxt.loader.SymName(s)) + 1) // NULL terminate ++ size += int64(len(name) + 1) // NULL terminate + }) + + state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab) +-- +2.46.0 + diff --git a/internal/linker/patches/go1.23/0003-add-entryOff-encryption.patch b/internal/linker/patches/go1.23/0003-add-entryOff-encryption.patch new file mode 100644 index 00000000..83b02b6c --- /dev/null +++ b/internal/linker/patches/go1.23/0003-add-entryOff-encryption.patch @@ -0,0 +1,43 @@ +From 6bb03c1a0c523530b29fe6fdc48ca8f24f0bb13c Mon Sep 17 00:00:00 2001 +From: pagran +Date: Sat, 14 Jan 2023 21:36:16 +0100 +Subject: [PATCH 3/3] add entryOff encryption + +--- + cmd/link/internal/ld/pcln.go | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go +index 056a1d3a72..37226d0327 100644 +--- a/cmd/link/internal/ld/pcln.go ++++ b/cmd/link/internal/ld/pcln.go +@@ -806,6 +806,26 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym + sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase)) + } + } ++ ++ // Moving next code higher is not recommended. ++ // Only at the end of the current function no edits between go versions ++ garbleEntryOffKeyStr := os.Getenv("GARBLE_LINK_ENTRYOFF_KEY") ++ if garbleEntryOffKeyStr == "" { ++ panic("[garble] entryOff key must be set") ++ } ++ var garbleEntryOffKey uint32 ++ // Use fmt package instead of strconv to avoid importing a new package ++ if _, err := fmt.Sscan(garbleEntryOffKeyStr, &garbleEntryOffKey); err != nil { ++ panic(fmt.Errorf("[garble] invalid entryOff key %s: %v", garbleEntryOffKeyStr, err)) ++ } ++ ++ garbleData := sb.Data() ++ for _, off := range startLocations { ++ entryOff := ctxt.Arch.ByteOrder.Uint32(garbleData[off:]) ++ nameOff := ctxt.Arch.ByteOrder.Uint32(garbleData[off+4:]) ++ ++ sb.SetUint32(ctxt.Arch, int64(off), entryOff^(nameOff*garbleEntryOffKey)) ++ } + } + + // pclntab initializes the pclntab symbol with +-- +2.46.0 + diff --git a/main.go b/main.go index cf68659f..cc84aff1 100644 --- a/main.go +++ b/main.go @@ -270,7 +270,7 @@ func (e errJustExit) Error() string { return fmt.Sprintf("exit: %d", e) } func goVersionOK() bool { const ( minGoVersion = "go1.22" // the first major version we support - maxGoVersion = "go1.23" // the first major version we don't support + maxGoVersion = "go1.24" // the first major version we don't support ) // rxVersion looks for a version like "go1.2" or "go1.2.3" in `go env GOVERSION`. diff --git a/testdata/script/goversion.txtar b/testdata/script/goversion.txtar index fb07ae2b..51e294f9 100644 --- a/testdata/script/goversion.txtar +++ b/testdata/script/goversion.txtar @@ -37,7 +37,7 @@ stderr 'Go version "go1\.14" is too old; please upgrade to go1\.22 or newer' env GARBLE_TEST_GOVERSION='go1.28.2' env TOOLCHAIN_GOVERSION='go1.28.2' ! exec garble build -stderr 'Go version "go1\.28\.2" is too new; Go linker patches aren''t available for go1\.23 or later yet' +stderr 'Go version "go1\.28\.2" is too new; Go linker patches aren''t available for go1\.24 or later yet' # We should accept custom devel strings. env TOOLCHAIN_GOVERSION='devel go1.22-somecustomversion'