#821454 dh-golang: Position-independent executables (PIE)

Package:
dh-golang
Source:
dh-golang
Submitter:
Peter Colberg
Date:
2021-09-06 16:09:04 UTC
Severity:
normal
Tags:
#821454#5
Date:
2016-04-18 19:06:11 UTC
From:
To:
Dear Debian Go team,

In response to the lintian warning hardening-no-pie, I am trying to
build acmetool (#817091) as a position-independent executable (PIE).

The Go compiler supports a -buildmode=pie since version 1.5.

Building the package with this flag produces the following errror:

  dpkg-buildpackage: source package acmetool
  dpkg-buildpackage: source version 0.0.49-1
  dpkg-buildpackage: source distribution unstable
   dpkg-source --before-build acmetool-0.0.49
  dpkg-buildpackage: host architecture amd64
   fakeroot debian/rules clean
  dh clean --buildsystem=golang --with=golang
     dh_testdir -O--buildsystem=golang
     dh_auto_clean -O--buildsystem=golang
     dh_clean -O--buildsystem=golang
   dpkg-source -b acmetool-0.0.49
  dpkg-source: info: using source format '3.0 (quilt)'
  dpkg-source: info: building acmetool using existing ./acmetool_0.0.49.orig.tar.gz
  dpkg-source: info: building acmetool in acmetool_0.0.49-1.debian.tar.xz
  dpkg-source: info: building acmetool in acmetool_0.0.49-1.dsc
   debian/rules build
  dh build --buildsystem=golang --with=golang
     dh_testdir -O--buildsystem=golang
     dh_update_autotools_config -O--buildsystem=golang
     dh_auto_configure -O--buildsystem=golang
     debian/rules override_dh_auto_build
  make[1]: Entering directory '/<<PKGBUILDDIR>>'
  dh_auto_build -O--buildsystem=golang -- -buildmode=pie -ldflags "-X github.com/hlandau/acme/hooks.DefaultPath=/etc/ac
+me
          go install -v -buildmode=pie -ldflags "-X github.com/hlandau/acme/hooks.DefaultPath=/etc/acme/hooks -X github
+.ci github.com/hlandau/acme/acmeapi/acmeendpoints github.com/hlandau/acme/acmeapi/acmeutils
+github.com/hlandau/acme/cmd/a/acme/redirector github.com/hlandau/acme/responder github.com/hlandau/acme/solver
+github.com/hlandau/acme/storage githu
  runtime/internal/sys
  go install runtime/internal/sys: mkdir /usr/lib/go/pkg/linux_amd64_shared: permission denied
  dh_auto_build: go install -v -buildmode=pie -ldflags -X github.com/hlandau/acme/hooks.DefaultPath=/etc/acme/hooks -X
+gicmeapi github.com/hlandau/acme/acmeapi/acmeendpoints github.com/hlandau/acme/acmeapi/acmeutils
+github.com/hlandau/acme/andau/acme/redirector github.com/hlandau/acme/responder github.com/hlandau/acme/solver
+github.com/hlandau/acme/storage
  debian/rules:14: recipe for target 'override_dh_auto_build' failed
  make[1]: *** [override_dh_auto_build] Error 1
  make[1]: Leaving directory '/<<PKGBUILDDIR>>'
  debian/rules:11: recipe for target 'build' failed
  make: *** [build] Error 2
  dpkg-buildpackage: error: debian/rules build gave error exit status 2

Any ideas what is going wrong?

It works fine if I compile from upstream:

  git clone https://github.com/hlandau/acme github.com/hlandau/acme
  cd github.com/hlandau/acme/cmd/acmetool
  export GOPATH=$PWD
  go get -v
  go build -v -buildmode=pie

Regards,
Peter

#821454#12
Date:
2016-04-19 00:17:33 UTC
From:
To:
This is like the cross-compilation / CGO_ENABLED=0 situations:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=818651#10
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=776401#27

I still don't really know of a good answer. I've been meaning to ask
upstream if they have any ideas about this, maybe I'll get around to
this today :-)

Cheers,
mwh

#821454#27
Date:
2016-04-26 10:29:51 UTC
From:
To:
I finally asked on golang-dev and Russ Cox pointed out the -pkgdir
argument to go install. This patch:

diff -Nru acmetool-0.0.49/debian/changelog acmetool-0.0.49/debian/changelog
--- acmetool-0.0.49/debian/changelog 2016-04-26 22:15:04.000000000 +1200
+++ acmetool-0.0.49/debian/changelog 2016-04-26 22:18:51.000000000 +1200
@@ -1,3 +1,9 @@
+acmetool (0.0.49-2) UNRELEASED; urgency=medium
+
+  * Everyone loves PIE
+
+ -- Michael Hudson-Doyle <michael.hudson@ubuntu.com>  Tue, 26 Apr
2016 22:18:34 +1200
+
 acmetool (0.0.49-1) unstable; urgency=medium

   * Initial release (Closes: #817091)
diff -Nru acmetool-0.0.49/debian/rules acmetool-0.0.49/debian/rules
--- acmetool-0.0.49/debian/rules 2016-04-26 22:15:04.000000000 +1200
+++ acmetool-0.0.49/debian/rules 2016-04-26 22:22:42.000000000 +1200
@@ -11,7 +11,7 @@
  dh $@ --buildsystem=golang --with=golang

 override_dh_auto_build:
- dh_auto_build -O--buildsystem=golang -- -ldflags "$(GO_LDFLAGS)"
+ dh_auto_build -O--buildsystem=golang -- -buildmode=pie
-pkgdir=$$(mktemp -d -p $(CURDIR)) -ldflags "$(GO_LDFLAGS)"

 override_dh_auto_install:
  dh_auto_install -O--buildsystem=golang

is obviously a bit of a hack but it seems to do approximately the right thing:

(master *)mwhudson@aeglos:/opt/opensource/deb/acmetool$ mkdir x
(master *)mwhudson@aeglos:/opt/opensource/deb/acmetool$ dpkg-deb -x
../acmetool_0.0.49-2_amd64.deb x
(master *)mwhudson@aeglos:/opt/opensource/deb/acmetool$
hardening-check x/usr/bin/acmetool
x/usr/bin/acmetool:
 Position Independent Executable: yes
 Stack protected: no, not found!
 Fortify Source functions: no, only unprotected functions found!
 Read-only relocations: no, not found!
 Immediate binding: no, not found!

(we could probably make dh-golang do something like this by default...)

Cheers,
mwh

On 19 April 2016 at 12:17, Michael Hudson-Doyle <michael.hudson@canonical.com> wrote:

#821454#32
Date:
2016-04-26 16:53:21 UTC
From:
To:
Hi Michael,

I am wondering if dh-golang could set -pkgdir by default. Does it have
to be a random path? dh-golang could set a fixed path that is cleaned
up with dh_auto_clean.

Ideally dh-golang would support dpkg hardening flags such as

  export DEB_BUILD_MAINT_OPTIONS = hardening=+all

  export DEB_BUILD_MAINT_OPTIONS = hardening=+pie

Another issue is that when using -buildmode=pie as above, the standard
library is rebuilt, which increases compile time if enabled for every
package. golang-go should provide the -buildmode=pie variant of the
standard and runtime libraries out of the box.

https://github.com/golang/go/issues/15433#issuecomment-214529771

Peter

#821454#43
Date:
2016-04-27 01:35:30 UTC
From:
To:
That's a reasonable thing to wonder :-)

No.

Yes, having it be cleaned up is obviously a requirement for a real
use... Probably just using a directory inside the builddir would make
most sense.

Yeah, that seems reasonable. I think only pie, bindnow and relro make
sense for Go.

If you use -pkgdir, the standard library is rebuilt whatever you do.
But yeah, that's not ideal. We could (presumably) symlink-mirror
$GOROOT/pkg into the gopkg directory before building to alleviate
this.

Yes, probably.

The performance and binary size hit of PIE on i386 in particular is
likely to be large. Do you care at all about that?

Cheers,
mwh

#821454#48
Date:
2016-04-29 00:40:58 UTC
From:
To:
Hi Michael,

I figured out how to link with BINDNOW and RELRO using -extldflags:

# Pass hardening flags to linker
GO_LDFLAGS += -extldflags=-Wl,-z,now,-z,relro

# hardening-check acmetool
acmetool:
 Position Independent Executable: yes
 Stack protected: no, not found!
 Fortify Source functions: no, only unprotected functions found!
 Read-only relocations: yes
 Immediate binding: yes

I think -pkgdir is not needed at all for building with -buildmode=pie.

I suggest the following path going forward:

 * Ship the -buildmode=pie std library in a separate package
   golang-std-pie-dev as part of the golang source package.

 * Extend dh-golang to translate the dpkg hardening flags into
   -buildmode=pie and -extldflags=-Wl,-z,now,-z,relro as needed.

I am filing a separate bug to implement the first change.

The second change need not happen right away; since it only affects
packages that build executables, which are very few among the many
golang packages, this can also be implemented on a case-by-case
basis for now.

I noticed for amd64 that the size of the stripped acmetool executable
increases from 10 to 15 MB, which is significant but not dramatic
compared to the overall bloat of Go executables. The size of the
compressed Debian package increases from 2.2 to 2.7 MB. (That is
a compression ratio of 5:1 in both cases.)

Is this not a general issue that affects all Debian packages compiled
with hardening flags? Or do you potentially see Go-specific size and
performance issues?

Regards,
Peter

#821454#53
Date:
2016-04-29 01:17:51 UTC
From:
To:
Ah yes, makes sense. TBH, I wonder about changing Go to always pass
those flags...

So long as we add the golang-std-pie-dev flag, yeah.

So we'll leave this bug for that bit?

That's not too bad. It will be better in Go 1.7!
extremely stupid (I should know, I wrote it). For other architectures
it should not be nearly so bad. So if you care about performance at
all on 386, you might not want to build PIE there. But I'm not sure
anyone does any more?

Cheers,
mwh

#821454#58
Date:
2016-04-29 01:30:52 UTC
From:
To:
On 29 April 2016 at 13:17, Michael Hudson-Doyle <michael.hudson@canonical.com> wrote:
https://github.com/golang/go/issues/15485

Cheers,
mwh

#821454#67
Date:
2016-05-15 21:04:25 UTC
From:
To:
Hi Michael,

I noticed that you are now an Uploader for golang-go.

What are your thoughts on https://bugs.debian.org/823014 ?

Regards,
Peter