Skip to content

Commit

Permalink
cmd/go/internal/work: allow @ character in some -Wl, linker flags on …
Browse files Browse the repository at this point in the history
…darwin

The GNU linker interprets @file as "read command-line options from file".
Thus, we forbid values starting with @ on linker flags. However, this
causes a problem when targeting Darwin. @executable_path, @loader_path, and
@rpath are special values used in Mach-O to change the library search path
and can be used in conjunction with the -install_name and -rpath linker
flags. Since the GNU linker does not support Mach-O, targeting Darwin
implies not using the GNU linker. Therefore, we allow @ in the linker flags
if and only if cfg.Goos == "darwin".

Fixes #40559

Change-Id: I0896758f0835e444ea0d501ea3fd8423cff97a27
GitHub-Last-Rev: 2b81dcd
GitHub-Pull-Request: #70939
Reviewed-on: https://go-review.googlesource.com/c/go/+/638075
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
  • Loading branch information
t0rr3sp3dr0 authored and gopherbot committed Dec 27, 2024
1 parent 3979481 commit e3cd55e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
22 changes: 21 additions & 1 deletion src/cmd/go/internal/work/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,21 @@ var validLinkerFlags = []*lazyregexp.Regexp{
re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
}

var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{
// The GNU linker interprets `@file` as "read command-line options from
// file". Thus, we forbid values starting with `@` on linker flags.
// However, this causes a problem when targeting Darwin.
// `@executable_path`, `@loader_path`, and `@rpath` are special values
// used in Mach-O to change the library search path and can be used in
// conjunction with the `-install_name` and `-rpath` linker flags.
// Since the GNU linker does not support Mach-O, targeting Darwin
// implies not using the GNU linker. Therefore, we allow @ in the linker
// flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios".
re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`),
re(`-Wl,-install_name,@rpath(/[^,]*)?`),
re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`),
}

var validLinkerFlagsWithNextArg = []string{
"-arch",
"-F",
Expand All @@ -249,8 +264,13 @@ func checkCompilerFlags(name, source string, list []string) error {
}

func checkLinkerFlags(name, source string, list []string) error {
validLinkerFlagsForPlatform := validLinkerFlags
if cfg.Goos == "darwin" || cfg.Goos == "ios" {
validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...)
}

checkOverrides := true
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides)
}

// checkCompilerFlagsForInternalLink returns an error if 'list'
Expand Down
44 changes: 44 additions & 0 deletions src/cmd/go/internal/work/security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"os"
"strings"
"testing"

"cmd/go/internal/cfg"
)

var goodCompilerFlags = [][]string{
Expand Down Expand Up @@ -245,6 +247,8 @@ var badLinkerFlags = [][]string{
{"-Wl,--hash-style=foo"},
{"-x", "--c"},
{"-x", "@obj"},
{"-Wl,-dylib_install_name,@foo"},
{"-Wl,-install_name,@foo"},
{"-Wl,-rpath,@foo"},
{"-Wl,-R,foo,bar"},
{"-Wl,-R,@foo"},
Expand All @@ -261,6 +265,21 @@ var badLinkerFlags = [][]string{
{"./-Wl,--push-state,-R.c"},
}

var goodLinkerFlagsOnDarwin = [][]string{
{"-Wl,-dylib_install_name,@rpath"},
{"-Wl,-dylib_install_name,@rpath/"},
{"-Wl,-dylib_install_name,@rpath/foo"},
{"-Wl,-install_name,@rpath"},
{"-Wl,-install_name,@rpath/"},
{"-Wl,-install_name,@rpath/foo"},
{"-Wl,-rpath,@executable_path"},
{"-Wl,-rpath,@executable_path/"},
{"-Wl,-rpath,@executable_path/foo"},
{"-Wl,-rpath,@loader_path"},
{"-Wl,-rpath,@loader_path/"},
{"-Wl,-rpath,@loader_path/foo"},
}

func TestCheckLinkerFlags(t *testing.T) {
for _, f := range goodLinkerFlags {
if err := checkLinkerFlags("test", "test", f); err != nil {
Expand All @@ -272,6 +291,31 @@ func TestCheckLinkerFlags(t *testing.T) {
t.Errorf("missing error for %q", f)
}
}

goos := cfg.Goos

cfg.Goos = "darwin"
for _, f := range goodLinkerFlagsOnDarwin {
if err := checkLinkerFlags("test", "test", f); err != nil {
t.Errorf("unexpected error for %q: %v", f, err)
}
}

cfg.Goos = "ios"
for _, f := range goodLinkerFlagsOnDarwin {
if err := checkLinkerFlags("test", "test", f); err != nil {
t.Errorf("unexpected error for %q: %v", f, err)
}
}

cfg.Goos = "linux"
for _, f := range goodLinkerFlagsOnDarwin {
if err := checkLinkerFlags("test", "test", f); err == nil {
t.Errorf("missing error for %q", f)
}
}

cfg.Goos = goos
}

func TestCheckFlagAllowDisallow(t *testing.T) {
Expand Down

0 comments on commit e3cd55e

Please sign in to comment.