golang/go

cmd/link: LC_UUID not generated by go linker, resulting in failure to access local network on macOS 15

torarnv opened this issue · 4 comments

Go version

go version go1.22.5 darwin/arm64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/torarne/Library/Caches/go-build'
GOENV='/Users/torarne/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/var/folders/7w/09x_jw654938vd439254v6r80000gn/T//gomodcache'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/torarne/.go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.22.5/libexec'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.22.5/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.22.5'
GCCGO='gccgo'
AR='ar'
CC='cc'
CXX='c++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/7w/09x_jw654938vd439254v6r80000gn/T/go-build1376446515=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

Go binaries built with the default linker for macOS do not have a LC_UUID load command. This UUID seems important to the network privacy machinery on macOS, that in macOS 15 now includes local network access.

Running a small go binary that does a HTTP request to a local network HTTP server results in a permission request from the OS, but accepting this does not result in the go process being able to access the server.

The logs show:
nehelper +[NEProcessInfo copyUUIDsForExecutable:]_block_invoke: failed to get UUIDs for /Users/foo/FetchGo

So it seems the nehelper relies on the binary having a UUID to allow network requests through.

I can work around this by passing -ldflags="-linkmode=external" when building the go binary, which does produce a UUID:

❯ dwarfdump -u FetchGo
UUID: C7B47B23-54A7-3F52-837D-E455B57855A1 (arm64) FetchGo

And in this case the HTTP request works after accepting the privacy dialog. But I don't think this will work when cross-compiling darwin binaries on Linux e.g.

Note that for testing this, the binary must be run as an app bundle, or launch agent -- not via SSH/Terminal, as in the latter case the permission to access the network is inherited by those processes, and they have an UUID.

What did you see happen?

Network request fails to route

What did you expect to see?

Network request succeeds

Thanks @seankhliao :)

Sample reproducer. Change plist files to point to web server running in local network. Loading the launch agents should bring up permission dialogs.

missing-lc-uuid.zip

See also https://forums.developer.apple.com/forums/thread/737416 for a description of the UUID mechanism.