Browse Source

Dpkg::Vendor::Debian: Improve PIE flags support

Fix changelog for dpkg 1.18.11 to mention PIE got enabled by default for
all architectures, not just the ones where gcc does that itself.

When emitting PIE flags on architectures where gcc does not inject those
itself, do it via a specs file too, so that maintainers can use them
unconditionally regardless of the object being compiled or linked.

When injecting -no-pie for linking via gcc specs also inject -fno-PIE.

Update the documentation to make the current situation more clear.
Guillem Jover 4 years ago
parent
commit
cf7f30aeba
7 changed files with 47 additions and 24 deletions
  1. 2 0
      Makefile.am
  2. 1 1
      data/no-pie-link.specs
  3. 2 0
      data/pie-compile.specs
  4. 2 0
      data/pie-link.specs
  5. 16 4
      debian/changelog
  6. 18 13
      man/dpkg-buildflags.man
  7. 6 6
      scripts/Dpkg/Vendor/Debian.pm

+ 2 - 0
Makefile.am

@@ -20,6 +20,8 @@ ACLOCAL_AMFLAGS = -I m4
 
 
 dist_pkgdata_DATA = \
+	data/pie-compile.specs \
+	data/pie-link.specs \
 	data/no-pie-compile.specs \
 	data/no-pie-link.specs \
 	data/cputable \

+ 1 - 1
data/no-pie-link.specs

@@ -1,2 +1,2 @@
 *self_spec:
-+ %{!shared:%{!r:-no-pie}}
++ %{!shared:%{!r:-fno-PIE -no-pie}}

+ 2 - 0
data/pie-compile.specs

@@ -0,0 +1,2 @@
+*cc1_options:
++ %{!r:%{!fpie:%{!fPIE:%{!fpic:%{!fPIC:%{!fno-pic:-fPIE}}}}}}

+ 2 - 0
data/pie-link.specs

@@ -0,0 +1,2 @@
+*self_spec:
++ %{!shared:%{!r:-fPIE -pie}}

+ 16 - 4
debian/changelog

@@ -1,5 +1,16 @@
 dpkg (1.18.13) UNRELEASED; urgency=medium
 
+  * Improve PIE flags support:
+    - Retroactively document in the changelog that PIE is enabled by default
+      on all supported architectures regardless of gcc doing so itself on a
+      subset of them.
+    - When emitting PIE flags on architectures where gcc does not inject
+      those itself, do it via a specs file too, so that maintainers can
+      use them unconditionally regardless of the object being compiled
+      or linked.
+    - When injecting -no-pie for linking via the gcc specs file also
+      inject -fno-PIE.
+    - Update the documentation.
   * Perl modules:
     - Do not try to load non-files in Dpkg::Dist::Files load_dir method.
       Fixes test failures on non-Linux architectures. Closes: #843436
@@ -97,10 +108,11 @@ dpkg (1.18.11) unstable; urgency=medium
   * Enable dpkg-buildpackage -Jauto by default. Closes: #842845
   * Fix dpkg to not fail when removing non-existent backup files on read-only
     filesystems. Closes: #838877
-  * Handle PIE enabled by default in gcc. On achitectures where gcc enables
-    them by default, stop setting -fPIE and -pie, and set -fno-PIE and
-    -no-pie when disabling «pie» via gcc specs files, so that we do not
-    emit them on situations where it would be inappropriate. Closes: #835149
+  * Enable PIE on all supported architectures and handle PIE enabled by
+    default in gcc. On achitectures where gcc enables them by default,
+    stop setting -fPIE and -pie, and set -fno-PIE and -no-pie when disabling
+    «pie» via gcc specs files, so that we do not emit them on situations
+    where it would be inappropriate. Closes: #835149
     Based on a patch by Bálint Réczey <balint@balintreczey.hu>.
   * Architecture support:
     - Add support for AIX operating system.

+ 18 - 13
man/dpkg-buildflags.man

@@ -347,30 +347,32 @@ above). The option cannot become enabled if \fBrelro\fP is not enabled.
 .
 .TP
 .B pie
-This setting (enabled and injected by default by gcc on the amd64,
-arm64, armel, armhf, i386, mips, mipsel, mips64el, ppc64el and s390x
-architectures, since dpkg 1.18.11) adds the required options if needed
-to enable or disable PIE. When enabled and injected by gcc,
+This setting (enabled by default since dpkg 1.18.11, and injected by default
+by gcc on the amd64, arm64, armel, armhf, i386, mips, mipsel, mips64el,
+ppc64el and s390x Debian architectures) adds the required options if
+needed to enable or disable PIE. When enabled and injected by gcc,
 adds nothing. When enabled and not injected by gcc, adds \fB\-fPIE\fP
 to \fBCFLAGS\fP, \fBCXXFLAGS\fP, \fBOBJCFLAGS\fP, \fBOBJCXXFLAGS\fP,
 \fBGCJFLAGS\fP, \fBFFLAGS\fP and \fBFCFLAGS\fP, and \fB\-fPIE \-pie\fP
 to \fBLDFLAGS\fP. When disabled and injected by gcc, adds \fB\-fno\-PIE\fP
 to \fBCFLAGS\fP, \fBCXXFLAGS\fP, \fBOBJCFLAGS\fP, \fBOBJCXXFLAGS\fP,
 \fBGCJFLAGS\fP, \fBFFLAGS\fP and \fBFCFLAGS\fP, and
-\fB\-no\-pie\fP to \fBLDFLAGS\fP.
+\fB\-fno\-PIE \-no\-pie\fP to \fBLDFLAGS\fP.
 
 Position Independent
 Executable are needed to take advantage of Address Space Layout
 Randomization, supported by some kernel versions. While ASLR can already
 be enforced for data areas in the stack and heap (brk and mmap), the code
 areas must be compiled as position-independent. Shared libraries already
-do this (\-fPIC), so they gain ASLR automatically, but binary .text
+do this (\fB\-fPIC\fP), so they gain ASLR automatically, but binary .text
 regions need to be build PIE to gain ASLR. When this happens, ROP (Return
 Oriented Programming) attacks are much harder since there are no static
 locations to bounce off of during a memory corruption attack.
 
-This is not compatible with \fB\-fPIC\fP so care must be taken when
-building shared objects.
+PIE is not compatible with \fB\-fPIC\fP, so in general care must be taken
+when building shared objects. But because the PIE flags emitted get injected
+via gcc specs files, it should always be safe to unconditionally set them
+regardless of the object type being compiled or linked.
 
 Static libraries can be used by programs or other shared libraries.
 Depending on the flags used to compile all the objects within a static
@@ -382,22 +384,25 @@ none
 Cannot be linked into a PIE program, nor a shared library.
 .TP
 .B \-fPIE
-Can be linked into any program, but not a shared library.
+Can be linked into any program, but not a shared library (recommended).
 .TP
 .B \-fPIC
 Can be linked into any program and shared library.
 .RE
 
 .IP
-Unconditionally passing \fB\-fPIE\fP, \fB\-fpie\fP or \fB\-pie\fP to a
-build-system using libtool is safe as these flags will get stripped when
-building shared libraries.
+If there is a need to set these flags manually, bypassing the gcc specs
+injection, there are several things to take into account. Unconditionally
+and explicitly passing \fB\-fPIE\fP, \fB\-fpie\fP or \fB\-pie\fP to a
+build-system using libtool is safe as these flags will get stripped
+when building shared libraries.
 Otherwise on projects that build both programs and shared libraries you
 might need to make sure that when building the shared libraries \fB\-fPIC\fP
 is always passed last (so that it overrides any previous \fB\-PIE\fP) to
 compilation flags such as \fBCFLAGS\fP, and \fB\-shared\fP is passed last
 (so that it overrides any previous \fB\-pie\fP) to linking flags such as
-\fBLDFLAGS\fP.
+\fBLDFLAGS\fP. \fBNote:\fP This should not be needed with the default
+gcc specs machinery.
 
 .IP
 Additionally, since PIE is implemented via a general register, some

+ 6 - 6
scripts/Dpkg/Vendor/Debian.pm

@@ -293,14 +293,14 @@ sub _add_hardening_flags {
         pie => 1,
     );
 
-    # Adjust features based on user or maintainer's desires.
-    $self->_parse_feature_area('hardening', \%use_feature);
-
-    # Mask features that are not enabled by default in the compiler.
+    # Mask builtin features that are not enabled by default in the compiler.
     if ($arch !~ /^(?:amd64|arm64|armel|armhf|i386|mips|mipsel|mips64el|ppc64el|s390x)$/) {
         $builtin_feature{pie} = 0;
     }
 
+    # Adjust features based on user or maintainer's desires.
+    $self->_parse_feature_area('hardening', \%use_feature);
+
     # Mask features that are not available on certain architectures.
     if ($os !~ /^(?:linux|kfreebsd|knetbsd|hurd)$/ or
 	$cpu =~ /^(?:hppa|avr32)$/) {
@@ -340,7 +340,7 @@ sub _add_hardening_flags {
 
     # PIE
     if ($use_feature{pie} and not $builtin_feature{pie}) {
-	my $flag = '-fPIE';
+	my $flag = "-specs=$Dpkg::DATADIR/pie-compile.specs";
 	$flags->append('CFLAGS', $flag);
 	$flags->append('OBJCFLAGS',  $flag);
 	$flags->append('OBJCXXFLAGS', $flag);
@@ -348,7 +348,7 @@ sub _add_hardening_flags {
 	$flags->append('FCFLAGS', $flag);
 	$flags->append('CXXFLAGS', $flag);
 	$flags->append('GCJFLAGS', $flag);
-	$flags->append('LDFLAGS', '-fPIE -pie');
+	$flags->append('LDFLAGS', "-specs=$Dpkg::DATADIR/pie-link.specs");
     } elsif (not $use_feature{pie} and $builtin_feature{pie}) {
 	my $flag = "-specs=$Dpkg::DATADIR/no-pie-compile.specs";
 	$flags->append('CFLAGS', $flag);