From aa67c654dca2a3d0908bb97e62e22e9bd37e6e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Mon, 21 Apr 2025 17:50:38 +0200 Subject: [PATCH] refuse to obfuscate bytedance/sonic/loader Or any other package which uses a //go:linkname to the runtime names "lastmoduledatap" or "moduledataverify1". These are used by sonic to inject function headers to the runtime, which does not work as garble patches the runtime as part of obfuscation. The way it alters the magic number in function headers breaks this. Add a summary of this as a comment too. Fixes #898. --- main.go | 18 ++++++++++++++++-- testdata/script/linkname_forbid.txtar | 10 +++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 8ebd8ec..3e739ca 100644 --- a/main.go +++ b/main.go @@ -1054,7 +1054,9 @@ func (tf *transformer) transformCompile(args []string) ([]string, error) { updateEntryOffset(file, entryOffKey()) } } - tf.transformDirectives(file.Comments) + if err := tf.transformDirectives(file.Comments); err != nil { + return nil, err + } file = tf.transformGoFile(file) file.Name.Name = tf.curPkg.obfuscatedPackageName() @@ -1082,7 +1084,7 @@ func (tf *transformer) transformCompile(args []string) ([]string, error) { // transformDirectives rewrites //go:linkname toolchain directives in comments // to replace names with their obfuscated versions. -func (tf *transformer) transformDirectives(comments []*ast.CommentGroup) { +func (tf *transformer) transformDirectives(comments []*ast.CommentGroup) error { for _, group := range comments { for _, comment := range group.List { if !strings.HasPrefix(comment.Text, "//go:linkname ") { @@ -1104,6 +1106,17 @@ func (tf *transformer) transformDirectives(comments []*ast.CommentGroup) { if len(fields) == 3 { newName = fields[2] } + switch newName { + case "runtime.lastmoduledatap", "runtime.moduledataverify1": + // Linknaming to the var and function above is used by github.com/bytedance/sonic/loader + // to inject functions into the runtime, but that breaks as garble patches + // the runtime to change the function header magic number. + // + // Given that Go is locking down access to runtime internals via go:linkname, + // and what sonic does was never supported and is a hack, + // refuse to build before the user sees confusing run-time panics. + return fmt.Errorf("garble does not support packages with a //go:linkname to %s", newName) + } localName, newName = tf.transformLinkname(localName, newName) fields[1] = localName @@ -1117,6 +1130,7 @@ func (tf *transformer) transformDirectives(comments []*ast.CommentGroup) { comment.Text = strings.Join(fields, " ") } } + return nil } func (tf *transformer) transformLinkname(localName, newName string) (string, string) { diff --git a/testdata/script/linkname_forbid.txtar b/testdata/script/linkname_forbid.txtar index 2c2b95c..119645e 100644 --- a/testdata/script/linkname_forbid.txtar +++ b/testdata/script/linkname_forbid.txtar @@ -1,13 +1,17 @@ -# TODO: Disallow certain kinds of runtime linknaming which break with garble. +# Disallow certain kinds of runtime linknaming which break with garble. -exec garble build -exec ./main +! exec garble build +cmp stderr build.stderr [short] stop # no need to verify this with -short go build exec ./main +-- build.stderr -- +# test/main +garble does not support packages with a //go:linkname to runtime.lastmoduledatap +exit status 1 -- go.mod -- module test/main