Skip to content
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

cmd/link: building static pie binaries using gcc -static-pie #41944

Closed
Sigurthorb opened this issue Oct 12, 2020 · 6 comments
Closed

cmd/link: building static pie binaries using gcc -static-pie #41944

Sigurthorb opened this issue Oct 12, 2020 · 6 comments

Comments

@Sigurthorb
Copy link

@Sigurthorb Sigurthorb commented Oct 12, 2020

What version of Go are you using (go version)?

$ go version
go version go1.15.2 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/root/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/root/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="/usr/local/bin/gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build263333751=/tmp/go-build -gno-record-gcc-switches"
$ gcc --version
gcc (GCC) 8.4.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ ldd --version
ldd (Debian GLIBC 2.28-10) 2.28
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

What did you do?

echo "package main;import \"fmt\";func main() {fmt.Println(\"Simple Example\")}" > main.go
$ go build  -ldflags '-linkmode external -s -w -extldflags "--static-pie"' -buildmode=pie -tags 'osusergo,netgo,static_build' -o test main.go

What did you expect to see?

$ ldd test
	not a dynamic executable
$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, Go BuildID=rgOI4PF0l9yAZphAtOJL/nTfXugdTh0K2yBsPc4vL/dZrjeEP8xFOA48kNl0QR/E7SFPeLbC53R9vOOwxl-, stripped

What did you see instead?

$ ldd test
	statically linked
$ file test
test: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux), dynamically linked, for GNU/Linux 3.2.0, Go BuildID=KlBdGD6KKDb0nsMB-ZpA/oWNK5CknauZx0-fEHthH/_Vh9asqCv-E1YHUvcHKH/IKKlrfpfXPf56OE5mX8v, stripped

I tried also to use buildmode=exe but this gave me a relocation warning:

$ /go/src/main# go build  -ldflags '-linkmode external -s -w -extldflags "--static-pie"' -buildmode=exe -tags 'osusergo,netgo,static_build' -o test main.go
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: /tmp/go-link-150358325/go.o: warning: relocation in read-only section `.gopclntab'
/usr/bin/ld: read-only segment has dynamic relocations
collect2: error: ld returned 1 exit status

Is there any way to create a static pie binary? If not, is there any plan to support this in go?

@ianlancetaylor ianlancetaylor changed the title cmd/build: Building static pie binaries using gcc -static-pie cmd/link: building static pie binaries using gcc -static-pie Oct 12, 2020
@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Oct 12, 2020

When I build a simple C program with -static-pie, I get

> ldd ./hello
	statically linked
> file hello
hello: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=d0bee136c72cf79b539b0f2bf4032d54a3692f9a, for GNU/Linux 3.2.0, not stripped

That seems consistent with what I get using -extldflags=-static-pie.

@Sigurthorb
Copy link
Author

@Sigurthorb Sigurthorb commented Oct 12, 2020

I did not try the -static-pie on a simple c program, my bad.
Is there any way to get a static binary with PIE in go?
I've tried musl and upgraded gcc/libc to get a static binary that does not have dependency on ld at runtime without any progress. I've found examples for this working in rust using musl but I have not found anything about this in go.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Oct 12, 2020

In general we don't use the issue tracker for questions. See https://golang.org/wiki/Questions.

I'm not sure what you mean by static PIE if that is not the same as what GCC produces with the -static-pie option. I don't know what Rust does.

@Sigurthorb
Copy link
Author

@Sigurthorb Sigurthorb commented Oct 13, 2020

I already tried stack overflow and feel like I've exhausted other avenues of trying to figure out the feasibility of this. The reason I decided to bring this here was that I found that this is actually possible with rust and musl.

@haraldh
Copy link

@haraldh haraldh commented Oct 16, 2020

Hello... author of the the rust and musl article you linked here.

You already figured it out!

$ go build  -ldflags '-linkmode external -s -w -extldflags "--static-pie"' -buildmode=pie -tags 'osusergo,netgo,static_build' -o test main.go

The test binary looks good:

$ readelf -l test
[…]
  DYNAMIC        0x000000000028bd18 0x000000000028cd18 0x000000000028cd18
[…]

and without the INTERP section. So all should be fine, I guess.

and it runs correctly:

$ test
Simple Example

So, I don't see a problem here.

@Sigurthorb
Copy link
Author

@Sigurthorb Sigurthorb commented Oct 17, 2020

I don't know what went wrong on my side but you are right, I did solve this! I think I was stuck on getting a statically linked binary from the 'file' output.

What I was really trying to accomplish was to have a PIE binary that could execute inside a scratch container. After trying again a binary using this build command it does run in a scratch container!

go build  -ldflags '-linkmode external -s -w -extldflags "--static-pie"' -buildmode=pie -tags 'osusergo,netgo,static_build' -o test main.go

edit: Figured out the issue, I was using other conflicting gcc flags -Wl,-z,now,-z,relro,-z,defs resulting in a LSB shared object instead of LSB executable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.