[pacman-dev] [PATCH] add support for PIE to makepkg

Daniel Micay danielmicay at gmail.com
Mon Jul 21 17:41:25 EDT 2014


A `pie` option is added for wrapping C and C++ compilers and passing the
correct options for building position independent executables. PIE is
required for full address space layout optimization (ASLR) and there is
little to no benefit from ASLR without it since global ELF tables
(GOT/PLT) and application code are at known locations.

A wrapper script is required in order to pass the correct flags for
executables without changing the flags for libraries. It adds `-pie`
when linking (no `-c` switch) if `-static` or `-shared` are not passed,
and `-fPIE` whenever `-fPIC` is not already there. This technique comes
from the Debian hardening wrappers.

Position independent code is expensive on i686, so it's only enabled by
default on x86_64 where the cost is negligible. It can be enabled on a
package-by-package basis on i686. The same cost already exists for any
code in a dynamic library.

Signed-off-by: Daniel Micay <danielmicay at gmail.com>
---
 configure.ac           |  4 ++++
 doc/makepkg.conf.5.txt |  4 ++++
 etc/Makefile.am        |  1 +
 etc/makepkg.conf.in    |  3 ++-
 scripts/Makefile.am    | 32 ++++++++++++++++++++++++++++++++
 scripts/cc-pie.sh      | 28 ++++++++++++++++++++++++++++
 scripts/makepkg.sh.in  |  7 ++++++-
 7 files changed, 77 insertions(+), 2 deletions(-)
 create mode 100755 scripts/cc-pie.sh

diff --git a/configure.ac b/configure.ac
index 45f40f0..a4378b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -322,6 +322,7 @@ INODECMD="stat -c '%i %n'"
 SIZECMD="stat -c %s"
 SEDINPLACE="sed --follow-symlinks -i"
 DUFLAGS="-sk --apparent-size"
+PIE="!pie"
 STRIP_BINARIES="--strip-all"
 STRIP_SHARED="--strip-unneeded"
 STRIP_STATIC="--strip-debug"
@@ -344,12 +345,15 @@ case "${host_os}" in
 		;;
 esac
 
+[[ $host_cpu == x86_64 ]] && PIE=pie
+
 AM_CONDITIONAL([DARWIN], test "x$host_os_darwin" = "xyes")
 AC_PATH_PROGS([DUPATH], [du], [du], [/usr/bin$PATH_SEPARATOR/bin] )
 AC_SUBST(INODECMD)
 AC_SUBST(SIZECMD)
 AC_SUBST(SEDINPLACE)
 AC_SUBST(DUFLAGS)
+AC_SUBST(PIE)
 AC_SUBST(STRIP_BINARIES)
 AC_SUBST(STRIP_SHARED)
 AC_SUBST(STRIP_STATIC)
diff --git a/doc/makepkg.conf.5.txt b/doc/makepkg.conf.5.txt
index b15f026..48d5b9d 100644
--- a/doc/makepkg.conf.5.txt
+++ b/doc/makepkg.conf.5.txt
@@ -180,6 +180,10 @@ Options
 		DEBUG_CXXFLAGS to their counterpart buildflags. Creates a separate
 		package containing the debug symbols when used with `strip'.
 
+	*pie*;;
+		Build position independent executables with C and C++ compilers. This
+		will wrap `clang` and `gcc` and pass in the correct switches.
+
 **INTEGRITY_CHECK=(**check1 ...**)**::
 	File integrity checks to use. Multiple checks may be specified; this
 	affects both generation and checking. The current valid options are:
diff --git a/etc/Makefile.am b/etc/Makefile.am
index 5363f42..c1ab91b 100644
--- a/etc/Makefile.am
+++ b/etc/Makefile.am
@@ -12,6 +12,7 @@ SED_PROCESS = \
 	-e 's|@prefix[@]|$(prefix)|g' \
 	-e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
 	-e 's|@PACKAGE_NAME[@]|$(PACKAGE_NAME)|g' \
+	-e 's|@PIE[@]|$(PIE)|g' \
 	-e 's|@PKGEXT[@]|$(PKGEXT)|g' \
 	-e 's|@SRCEXT[@]|$(SRCEXT)|g' \
 	-e 's|@STRIP_BINARIES[@]|$(STRIP_BINARIES)|g' \
diff --git a/etc/makepkg.conf.in b/etc/makepkg.conf.in
index 712ca60..9d3925d 100644
--- a/etc/makepkg.conf.in
+++ b/etc/makepkg.conf.in
@@ -76,8 +76,9 @@ BUILDENV=(!distcc color !ccache check !sign)
 #-- purge:      Remove files specified by PURGE_TARGETS
 #-- upx:        Compress binary executable files using UPX
 #-- debug:      Add debugging flags as specified in DEBUG_* variables
+#-- pie:        Build position independent executables with C and C++ compilers
 #
-OPTIONS=(strip docs libtool staticlibs emptydirs zipman purge !upx !debug)
+OPTIONS=(strip docs libtool staticlibs emptydirs zipman purge !upx !debug @PIE@)
 
 #-- File integrity checks to use. Valid: md5, sha1, sha256, sha384, sha512
 INTEGRITY_CHECK=(md5)
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 0b756ad..605601c 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -157,6 +157,38 @@ install-exec-hook:
 		( $(LN_S) repo-add repo-remove || \
 		ln repo-add repo-remove || \
 		cp repo-add repo-remove )
+	$(INSTALL) -Dm755 cc-pie.sh $(DESTDIR)$(libdir)/pacman/cc-pie.sh
+	$(MKDIR_P) $(DESTDIR)$(libdir)/pacman/cc-wrappers
+	cd $(DESTDIR)$(libdir)/pacman/cc-wrappers && \
+		$(RM) cc && \
+		( $(LN_S) ../cc-pie.sh cc || \
+		ln ../cc-pie.sh cc || \
+		cp ../cc-pie.sh cc )
+	cd $(DESTDIR)$(libdir)/pacman/cc-wrappers && \
+		$(RM) c++ && \
+		( $(LN_S) ../cc-pie.sh c++ || \
+		ln ../cc-pie.sh c++ || \
+		cp ../cc-pie.sh c++ )
+	cd $(DESTDIR)$(libdir)/pacman/cc-wrappers && \
+		$(RM) clang && \
+		( $(LN_S) ../cc-pie.sh clang || \
+		ln ../cc-pie.sh clang || \
+		cp ../cc-pie.sh clang )
+	cd $(DESTDIR)$(libdir)/pacman/cc-wrappers && \
+		$(RM) clang++ && \
+		( $(LN_S) ../cc-pie.sh clang++ || \
+		ln ../cc-pie.sh clang++ || \
+		cp ../cc-pie.sh clang++ )
+	cd $(DESTDIR)$(libdir)/pacman/cc-wrappers && \
+		$(RM) gcc && \
+		( $(LN_S) ../cc-pie.sh gcc || \
+		ln ../cc-pie.sh gcc || \
+		cp ../cc-pie.sh gcc )
+	cd $(DESTDIR)$(libdir)/pacman/cc-wrappers && \
+		$(RM) g++ && \
+		( $(LN_S) ../cc-pie.sh g++ || \
+		ln ../cc-pie.sh g++ || \
+		cp ../cc-pie.sh g++ )
 
 uninstall-hook:
 	cd $(DESTDIR)$(bindir) && \
diff --git a/scripts/cc-pie.sh b/scripts/cc-pie.sh
new file mode 100755
index 0000000..6bb79d2
--- /dev/null
+++ b/scripts/cc-pie.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+force_fPIE=1
+force_pie=1
+
+for opt; do
+	case "$opt" in
+		-fno-PIC|-fno-pic|-fno-PIE|-fno-pie|-nopie|-static|-shared|-D__KERNEL__|-nostdlib|-nostartfiles)
+			force_fPIE=0
+			force_pie=0
+			;;
+		-fPIC|-fpic)
+			force_fPIE=0
+			;;
+		-c)
+			force_pie=0
+			;;
+	esac
+done
+
+arguments=()
+(( $force_fPIE )) && arguments+=(-fPIE)
+(( $force_pie )) && arguments+=(-pie)
+
+command="${BASH_SOURCE##*/}"
+absolute="$(realpath -s "$BASH_SOURCE")"
+unwrapped=$(which -a "$command" | grep -m1 -v -x "$absolute")
+exec "$unwrapped" "${arguments[@]}" "$@"
diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in
index e20b707..a6710c8 100644
--- a/scripts/makepkg.sh.in
+++ b/scripts/makepkg.sh.in
@@ -50,7 +50,7 @@ LIBRARY=${LIBRARY:-'@libmakepkgdir@'}
 
 packaging_options=('strip' 'docs' 'libtool' 'staticlibs' 'emptydirs' 'zipman' \
                    'purge' 'upx' 'debug')
-other_options=('ccache' 'distcc' 'buildflags' 'makeflags')
+other_options=('ccache' 'distcc' 'buildflags' 'makeflags' 'pie')
 splitpkg_overrides=('pkgver' 'pkgrel' 'epoch' 'pkgdesc' 'arch' 'url' 'license' \
                     'groups' 'depends' 'optdepends' 'provides' 'conflicts' \
                     'replaces' 'backup' 'options' 'install' 'changelog')
@@ -1582,6 +1582,11 @@ run_build() {
 		[[ -d /usr/lib/ccache/bin ]] && export PATH="/usr/lib/ccache/bin:$PATH"
 	fi
 
+	# use PIE if it is requested
+	if check_option "pie" "y"; then
+		export PATH="/usr/lib/pacman/cc-wrappers:$PATH"
+	fi
+
 	run_function_safe "build"
 }
 
-- 
2.0.2


More information about the pacman-dev mailing list