-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/go: go tool rejects #cgo LDFLAGS: -Wl,-rpath,@executable_path/../Frameworks #40559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
What does Any fix for this will have to be very careful. For the GNU tools, among others, starting a parameter with |
@exexutable_path is like the MacOS version of $ORIGIN on Linux i.e. it is the path that the binary is in at runtime to be able to dynamically link to a library using a relative path. |
Here's some more info: https://wincent.com/wiki/@executable_path,_@load_path_and_@rpath |
It looks like
That would still be an issue here. Perhaps we could support specifically |
Yes, that sounds like the ideal solution! |
If someone can point me to where I need to look I'm happy to have a bash at a PR. |
security.go contains regular expressions for allowed flags.
cgo_bad_directives.txt tests this filtering, so that would need to be expanded. See README.txt in that directory for information on the test format. |
Actually I'm evaluating go for a project on mac and i've a poc that needs to load an external Any suggestions would be great, I really would like to use go for the project, but we need to load external C libraries that are not installed in any of the OS search paths. Update:
package native
/*
#cgo LDFLAGS: -L../path/to/libs -Wl,-rpath,./libs -lgreeter
#include "path/to/libs/include/greeter.h"
#include <stdlib.h>
*/
import "C"
// Rest of code omitted for brevity
# You can check the correct name for change with otool -L mybinary
install_name_tool -change @rpath/libgreeter.dylib @executable_path/libs/x64/libgreeter.dylib mybinary I'm not sure if this would break anything else, but so far everything is working as expected. I still hope that the go tooling will allow the |
@snmed I'm glad you found a way. You can also set set the |
@ianlancetaylor Thanks for your advice, that worked very well with |
on Linux search relative to $ORIGIN (see https://stackoverflow.com/a/72577483/1009546 ) on macOS it should search relative to @executable_path, but Go doesn't support it: golang/go#40559
on Linux search relative to $ORIGIN (see https://stackoverflow.com/a/72577483/1009546 ) on macOS it should search relative to @executable_path, but Go doesn't support it: golang/go#40559
I've just hit this issue and the Since |
Some people do use the GNU tools on Darwin, and those tools do read files when they see an If the specific string |
For |
The only other argument that I’m aware of that can receive a value starting with |
More info about these 3 special values at the very bottom of this man page: https://www.unix.com/man-page/osx/1/dyld/. |
I did some extra research and it looks like the GNU ld doesn't support Darwin as a target. The only way to use it on macOS is by targeting another platform to produce an ELF file. You cannot use it to produce a Mach-O file. See Homebrew/homebrew-core#17794. Since |
Change https://go.dev/cl/638075 mentions this issue: |
Reopen as the CL is reverted (#71476). Thanks. |
@cherrymui, do you have a PoC of the exploit? If it’s not under an embargo, could you share it? I’m very curious to know how these flags lead to ACE. I hope we can fix this issue again in a safe way. |
We received a security report saying "On Darwin, the ld64 linker handles the |
@ianlancetaylor, was this ever actually verified? I'm unable to reproduce the issue as reported. If the report is correct, the following should cause the compiled binary to have paths $ cat ./loader_path
. -rpath ..
$ cat ./main.go
package main
// #cgo LDFLAGS: -Wl,-rpath,@loader_path
import "C"
func main() {}
$ go1.24rc2 build -a -x ./main.go 2>&1 | grep 'rpath'
TERM='dumb' CGO_LDFLAGS='' $HOME/sdk/go1.24rc2/pkg/tool/darwin_amd64/cgo -objdir $WORK/b001/ -importpath command-line-arguments "-ldflags=\"-O2\" \"-g\" \"-Wl,-rpath,@loader_path\"" -- -I $WORK/b001/ -O2 -g ./main.go
TERM='dumb' clang -I . -fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -fno-common -o $WORK/b001/_cgo_.o $WORK/b001/_cgo_main.o $WORK/b001/_x001.o $WORK/b001/_x002.o -O2 -g -Wl,-rpath,@loader_path
clang -I $TMPDIR/tmp.iqG7vQcTi9 -fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -fno-common -o $WORK/b001/_cgo_.o $WORK/b001/_cgo_main.o $WORK/b001/_x001.o $WORK/b001/_x002.o -O2 -g -Wl,-rpath,@loader_path # test for internal linking errors (succeeded)
$ otool -l ./main | grep -B '1' -A '2' 'cmd LC_RPATH'
Load command 15
cmd LC_RPATH
cmdsize 32
path @loader_path (offset 12) The same happens when calling $ cat ./loader_path
. -rpath ..
$ cat ./main.c
int main() {
return 0;
}
$ clang -c ./main.c
$ clang -c ./main.c
$ ld -L '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib' -l 'System' -rpath '@loader_path' ./main.o
$ otool -l ./a.out | grep -B '1' -A '2' 'cmd LC_RPATH'
Load command 14
cmd LC_RPATH
cmdsize 32
path @loader_path (offset 12) It's true that $ cat ./loader_path
-rpath . -rpath ..
$ ld -L '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib' -l 'System' '@loader_path' ./main.o
$ otool -l ./a.out | grep -B '1' -A '2' 'cmd LC_RPATH'
Load command 14
cmd LC_RPATH
cmdsize 16
path . (offset 12)
Load command 15
cmd LC_RPATH
cmdsize 16
path .. (offset 12) However, it seems to reject it whenever paired with an argument that expects some value. $ cat ./loader_path
. -rpath ..
$ ld -L '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib' -l 'System' -F '@loader_path' ./main.o
ld: warning: search path '@loader_path' not found I may not be understanding the vulnerability here. A reproducible example would be great to diagnose the problem and propose a solution. If there's indeed a security vulnerability in my original patch, a possible fix would be to look for files named |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I tried to build a MacOS bundle using dynamically linked libraries. As per convention these are stored in
MyApp.app/Contents/Frameworks
which requiresLC_RPATH
to point there.I added the following flag:
What did you expect to see?
go build
builds binary withLC_RPATH
set to@executable_path/../Frameworks
What did you see instead?
I got an
invalid flag
error upon runninggo build
.I also tried replacing
@executable_path
for$ORIGIN
as I would in Linux but then I got animage not found
error when running the resulting binary (I assume this isn't supported on MacOS).The text was updated successfully, but these errors were encountered: