Blob Blame History Raw
From 658fff9445711b8402029bc2916fccbc5d6fd8fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
Date: Tue, 21 Jun 2016 19:16:43 +0200
Subject: [PATCH 1/2] Feature: conditional hardening, especially for daemons +
 libraries

So far the build system has not been concerned with run-time hardening
measures the typical toolchains provide (beside unconditional enforcing
of -fstack-protector-all).  Hence make a step in that direction,
enabling following if available and anticipating more to come:

[$LD -z relro]
- daemons incl. libs
- make some parts of Global Offset Table (GOT) read-only

[$CC -fPIE + ld -pie]
- daemons
- benefit from Address Space Layout Randomization (ASLR) for code
  areas

[$LD -z now]
- daemons incl. libs, only when the former two features are supported
- all symbols are resolved initially to that complete GOT is read-only

[$CC -fstack-protector-strong/-fstack-protector-all/-fstack-protector]
- universal
- extra run-time checks for buffer overflows
- NOTE:
  in case -fstack-protector-strong is supported, this is effectively
  a weakening of previously enforced -fstack-protector-all, but note
  that this variant comes with not entirely negligible performance
  penalty [1], making "strong" variant a reasonable tradeoff for
  something that is not in the prime line of possible attacks

For details on how to instruct configure script to do the right
thing (for when the default won't cut it), see detailed comment
in configure.ac under "Hardening flags" section.

[1] http://nvlpubs.nist.gov/nistpubs/TechnicalNotes/NIST.TN.1860.pdf
---
 acinclude.m4               |  25 +++++++++
 attrd/Makefile.am          |   3 +
 cib/Makefile.am            |   3 +
 configure.ac               | 135 +++++++++++++++++++++++++++++++++++++++++++--
 crmd/Makefile.am           |   3 +
 fencing/Makefile.am        |   3 +
 lib/cib/Makefile.am        |   3 +
 lib/cluster/Makefile.am    |   4 ++
 lib/common/Makefile.am     |   4 ++
 lib/fencing/Makefile.am    |   4 ++
 lib/lrmd/Makefile.am       |   4 ++
 lib/pengine/Makefile.am    |   8 +++
 lib/services/Makefile.am   |   3 +
 lib/transition/Makefile.am |   3 +
 lrmd/Makefile.am           |   6 ++
 mcp/Makefile.am            |   3 +
 pacemaker.spec.in          |  17 ++++++
 pengine/Makefile.am        |   6 ++
 18 files changed, 231 insertions(+), 6 deletions(-)
 create mode 100644 acinclude.m4

diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..ecaa1dd
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,25 @@
+dnl
+dnl local autoconf/automake macros for pacemaker
+dnl
+
+dnl Check if the flag is supported by linker (cacheable)
+dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
+dnl
+dnl Origin (declared license: GPLv2+ with less restrictive exception):
+dnl https://git.gnome.org/browse/glib/tree/m4macros/attributes.m4?h=2.49.1
+dnl (AC_LANG_PROGRAM substituted by Jan Pokorny <jpokorny@redhat.com>)
+
+AC_DEFUN([CC_CHECK_LDFLAGS], [
+  AC_CACHE_CHECK([if $CC supports $1 flag],
+    AS_TR_SH([cc_cv_ldflags_$1]),
+    [ac_save_LDFLAGS="$LDFLAGS"
+     LDFLAGS="$LDFLAGS $1"
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
+       [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
+       [eval "AS_TR_SH([cc_cv_ldflags_$1])="])
+     LDFLAGS="$ac_save_LDFLAGS"
+    ])
+
+  AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
+    [$2], [$3])
+])
diff --git a/attrd/Makefile.am b/attrd/Makefile.am
index a116e0e..6eaaae2 100644
--- a/attrd/Makefile.am
+++ b/attrd/Makefile.am
@@ -21,6 +21,9 @@ halibdir	= $(CRM_DAEMON_DIR)
 halib_PROGRAMS	= attrd
 ## SOURCES
 
+attrd_CFLAGS	= $(CFLAGS_HARDENED_EXE)
+attrd_LDFLAGS	= $(LDFLAGS_HARDENED_EXE)
+
 attrd_LDADD	= $(top_builddir)/lib/cluster/libcrmcluster.la	\
 		$(top_builddir)/lib/common/libcrmcommon.la	\
 		$(top_builddir)/lib/cib/libcib.la		\
diff --git a/cib/Makefile.am b/cib/Makefile.am
index fcb8ce9..4273191 100644
--- a/cib/Makefile.am
+++ b/cib/Makefile.am
@@ -32,6 +32,9 @@ halib_PROGRAMS	= cib cibmon
 ## SOURCES
 noinst_HEADERS	= callbacks.h cibio.h cibmessages.h common.h notify.h
 
+cib_CFLAGS	= $(CFLAGS_HARDENED_EXE)
+cib_LDFLAGS	= $(LDFLAGS_HARDENED_EXE)
+
 cib_LDADD	= $(top_builddir)/lib/cluster/libcrmcluster.la \
 		$(COMMONLIBS) $(CRYPTOLIB) $(CLUSTERLIBS)
 
diff --git a/configure.ac b/configure.ac
index c5b30dc..edf6a91 100644
--- a/configure.ac
+++ b/configure.ac
@@ -196,6 +196,13 @@ AC_ARG_ENABLE([systemd],
     [  --enable-systemd
        Do not build support for the Systemd init system [default=yes]])
 
+AC_ARG_ENABLE(hardening,
+    [  --with-hardening
+       Harden the resulting executables/libraries (best effort by default)],
+    [ HARDENING="${enableval}" ],
+    [ HARDENING=try ],
+)
+
 AC_ARG_WITH(ais,
     [  --with-ais
        Support the Corosync messaging and membership layer ],
@@ -1710,6 +1717,12 @@ if export | fgrep " CFLAGS=" > /dev/null; then
 	unset SAVED_CFLAGS
 fi
 
+AC_ARG_VAR([CFLAGS_HARDENED_LIB], [extra C compiler flags for hardened libraries])
+AC_ARG_VAR([LDFLAGS_HARDENED_LIB], [extra linker flags for hardened libraries])
+
+AC_ARG_VAR([CFLAGS_HARDENED_EXE], [extra C compiler flags for hardened executables])
+AC_ARG_VAR([LDFLAGS_HARDENED_EXE], [extra linker flags for hardened executables])
+
 CC_EXTRAS=""
 
 if test "$GCC" != yes; then
@@ -1785,12 +1798,6 @@ dnl otherwise none of both
 # Additional warnings it might be nice to enable one day
 #		-Wshadow
 #		-Wunreachable-code
-	case "$host_os" in
-	    *solaris*) ;;
-	    *) EXTRA_FLAGS="$EXTRA_FLAGS
-			-fstack-protector-all"
-		;;
-	esac
 	for j in $EXTRA_FLAGS
 	do
 	  if
@@ -1829,6 +1836,118 @@ dnl System specific options
   	AC_MSG_NOTICE(Activated additional gcc flags: ${CC_EXTRAS})
 fi
 
+dnl
+dnl Hardening flags
+dnl
+dnl The prime control of whether to apply (targeted) hardening build flags and
+dnl which ones is --{enable,disable}-hardening option passed to ./configure:
+dnl
+dnl --enable-hardening=try (default):
+dnl     depending on whether any of CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE,
+dnl     CFLAGS_HARDENED_LIB or LDFLAGS_HARDENED_LIB environment variables
+dnl     (see below) is set and non-null, all these custom flags (even if not
+dnl     set) are used as are, otherwise the best effort is made to offer
+dnl     reasonably strong hardening in several categories (RELRO, PIE,
+dnl     "bind now", stack protector) according to what the selected toolchain
+dnl     can offer
+dnl
+dnl --enable-hardening:
+dnl     same effect as --enable-hardening=try when the environment variables
+dnl     in question are suppressed
+dnl
+dnl --disable-hardening:
+dnl     do not apply any targeted hardening measures at all
+dnl
+dnl The user-injected environment variables that regulate the hardening in
+dnl default case are as follows:
+dnl
+dnl * CFLAGS_HARDENED_EXE, LDFLAGS_HARDENED_EXE
+dnl    compiler and linker flags (respectively) for daemon programs
+dnl    (attrd, cib, crmd, lrmd, stonithd, pacemakerd, pacemaker_remoted,
+dnl    pengine)
+dnl
+dnl * CFLAGS_HARDENED_LIB, LDFLAGS_HARDENED_LIB
+dnl    compiler and linker flags (respectively) for libraries linked
+dnl    with the daemon programs
+dnl
+dnl Note that these are purposedly targeted variables (addressing particular
+dnl targets all over the scattered Makefiles) and have no effect outside of
+dnl the predestined scope (e.g., CLI utilities).  For a global reach,
+dnl use CFLAGS, LDFLAGS, etc. as usual.
+dnl
+dnl For guidance on the suitable flags consult, for instance:
+dnl https://fedoraproject.org/wiki/Changes/Harden_All_Packages#Detailed_Harden_Flags_Description
+dnl https://owasp.org/index.php/C-Based_Toolchain_Hardening#GCC.2FBinutils
+dnl
+
+if test "x${HARDENING}" != "xtry"; then
+	unset CFLAGS_HARDENED_EXE
+	unset CFLAGS_HARDENED_LIB
+	unset LDFLAGS_HARDENED_EXE
+	unset LDFLAGS_HARDENED_LIB
+fi
+if test "x${HARDENING}" = "xno"; then
+	AC_MSG_NOTICE([Hardening: explicitly disabled])
+elif test "x${HARDENING}" = "xyes" \
+    || test "$(env | grep -Ec '^(C|LD)FLAGS_HARDENED_(EXE|LIB)=.')" = 0; then
+	dnl We'll figure out on our own...
+	CFLAGS_HARDENED_EXE=
+	CFLAGS_HARDENED_LIB=
+	LDFLAGS_HARDENED_EXE=
+	LDFLAGS_HARDENED_LIB=
+	relro=0
+	pie=0
+	bindnow=0
+	# daemons incl. libs: partial RELRO
+	flag="-Wl,-z,relro"
+	CC_CHECK_LDFLAGS(["${flag}"],
+		[LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
+		 LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}";
+		 relro=1]
+	)
+	# daemons: PIE for both CFLAGS and LDFLAGS
+	if cc_supports_flag -fPIE; then
+		flag="-pie"
+		CC_CHECK_LDFLAGS(["${flag}"],
+			[CFLAGS_HARDENED_EXE="${CFLAGS_HARDENED_EXE} -fPIE";
+			 LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
+			 pie=1]
+		)
+	fi
+	# daemons incl. libs: full RELRO if sensible
+	if test "${relro}" = 1 && test "${pie}" = 1; then
+		flag="-Wl,-z,now"
+		CC_CHECK_LDFLAGS(["${flag}"],
+			[LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
+			 LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}";
+			 bindnow=1]
+		)
+	fi
+	# universal: prefer strong > all > default stack protector if possible
+	flag=
+	if cc_supports_flag -fstack-protector-strong; then
+		flag="-fstack-protector-strong"
+	elif cc_supports_flag -fstack-protector-all; then
+		flag="-fstack-protector-all"
+	elif cc_supports_flag -fstack-protector; then
+		flag="-fstack-protector"
+	fi
+	if test -n "${flag}"; then
+		CC_EXTRAS="${CC_EXTRAS} ${flag}"
+		stackprot=1
+	fi
+	if test "${relro}" = 1 \
+	|| test "${pie}" = 1 \
+	|| test "${stackprot}" = 1; then
+		AC_MSG_NOTICE(
+		[Hardening: relro=${relro} pie=${pie} bindnow=${bindnow} stackprot=${flag}])
+	else
+		AC_MSG_WARN([Hardening: no suitable features in the toolchain detected])
+	fi
+else
+	AC_MSG_NOTICE([Hardening: using custom flags])
+fi
+
 CFLAGS="$CFLAGS $CC_EXTRAS"
 
 NON_FATAL_CFLAGS="$CFLAGS"
@@ -1978,5 +2097,9 @@ AC_MSG_RESULT([  HA group name            = ${CRM_DAEMON_GROUP}])
 AC_MSG_RESULT([  HA user name             = ${CRM_DAEMON_USER}])
 AC_MSG_RESULT([])
 AC_MSG_RESULT([  CFLAGS                   = ${CFLAGS}])
+AC_MSG_RESULT([  CFLAGS_HARDENED_EXE      = ${CFLAGS_HARDENED_EXE}])
+AC_MSG_RESULT([  CFLAGS_HARDENED_LIB      = ${CFLAGS_HARDENED_LIB}])
+AC_MSG_RESULT([  LDFLAGS_HARDENED_EXE     = ${LDFLAGS_HARDENED_EXE}])
+AC_MSG_RESULT([  LDFLAGS_HARDENED_LIB     = ${LDFLAGS_HARDENED_LIB}])
 AC_MSG_RESULT([  Libraries                = ${LIBS}])
 AC_MSG_RESULT([  Stack Libraries          = ${CLUSTERLIBS}])
diff --git a/crmd/Makefile.am b/crmd/Makefile.am
index 979e266..6d5ee9a 100644
--- a/crmd/Makefile.am
+++ b/crmd/Makefile.am
@@ -28,6 +28,9 @@ noinst_HEADERS	= crmd.h crmd_fsa.h crmd_messages.h fsa_defines.h	\
 		fsa_matrix.h fsa_proto.h crmd_utils.h crmd_callbacks.h	\
 		crmd_lrm.h te_callbacks.h tengine.h
 
+crmd_CFLAGS	= $(CFLAGS_HARDENED_EXE)
+crmd_LDFLAGS	= $(LDFLAGS_HARDENED_EXE)
+
 crmd_LDADD	= $(top_builddir)/lib/fencing/libstonithd.la		\
 		$(top_builddir)/lib/transition/libtransitioner.la	\
 		$(top_builddir)/lib/pengine/libpe_rules.la		\
diff --git a/fencing/Makefile.am b/fencing/Makefile.am
index 1d591fc..c53ead6 100644
--- a/fencing/Makefile.am
+++ b/fencing/Makefile.am
@@ -52,6 +52,9 @@ stonith_admin_LDADD	= $(top_builddir)/lib/common/libcrmcommon.la	\
 stonithd_CPPFLAGS	= -I$(top_srcdir)/pengine $(AM_CPPFLAGS)
 stonithd_YFLAGS		= -d
 
+stonithd_CFLAGS		= $(CFLAGS_HARDENED_EXE)
+stonithd_LDFLAGS	= $(LDFLAGS_HARDENED_EXE)
+
 stonithd_LDADD		= $(top_builddir)/lib/common/libcrmcommon.la	\
 			$(top_builddir)/lib/cluster/libcrmcluster.la	\
 			$(top_builddir)/lib/fencing/libstonithd.la	\
diff --git a/lib/cib/Makefile.am b/lib/cib/Makefile.am
index e414a7f..637ea8c 100644
--- a/lib/cib/Makefile.am
+++ b/lib/cib/Makefile.am
@@ -27,6 +27,9 @@ libcib_la_SOURCES	+= cib_file.c cib_remote.c
 libcib_la_LDFLAGS	= -version-info 5:1:1
 libcib_la_CPPFLAGS	= -I$(top_srcdir) $(AM_CPPFLAGS)
 
+libcib_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+libcib_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libcib_la_LIBADD	= $(CRYPTOLIB) $(top_builddir)/lib/pengine/libpe_rules.la $(top_builddir)/lib/common/libcrmcommon.la
 
 clean-generic:
diff --git a/lib/cluster/Makefile.am b/lib/cluster/Makefile.am
index 06d7066..9a57bbb 100644
--- a/lib/cluster/Makefile.am
+++ b/lib/cluster/Makefile.am
@@ -21,6 +21,10 @@ include $(top_srcdir)/Makefile.common
 lib_LTLIBRARIES	= libcrmcluster.la 
 
 libcrmcluster_la_LDFLAGS = -version-info 6:0:2
+
+libcrmcluster_la_CFLAGS  = $(CFLAGS_HARDENED_LIB)
+libcrmcluster_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB)
+
 libcrmcluster_la_LIBADD  = $(top_builddir)/lib/common/libcrmcommon.la $(top_builddir)/lib/fencing/libstonithd.la $(CLUSTERLIBS)
 
 libcrmcluster_la_SOURCES = election.c cluster.c membership.c
diff --git a/lib/common/Makefile.am b/lib/common/Makefile.am
index 7550ec1..0e1ad29 100644
--- a/lib/common/Makefile.am
+++ b/lib/common/Makefile.am
@@ -32,6 +32,10 @@ lib_LTLIBRARIES	= libcrmcommon.la
 CFLAGS		= $(CFLAGS_COPY:-Wcast-qual=) -fPIC
 
 libcrmcommon_la_LDFLAGS	= -version-info 9:0:6
+
+libcrmcommon_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+libcrmcommon_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libcrmcommon_la_LIBADD	= @LIBADD_DL@ $(GNUTLSLIBS) -lm
 
 libcrmcommon_la_SOURCES	= compat.c digest.c ipc.c io.c procfs.c utils.c xml.c \
diff --git a/lib/fencing/Makefile.am b/lib/fencing/Makefile.am
index 85ae40a..dc15799 100644
--- a/lib/fencing/Makefile.am
+++ b/lib/fencing/Makefile.am
@@ -21,5 +21,9 @@ include $(top_srcdir)/Makefile.common
 lib_LTLIBRARIES		= libstonithd.la
 
 libstonithd_la_LDFLAGS	= -version-info 4:1:2
+
+libstonithd_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+libstonithd_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libstonithd_la_LIBADD	= $(top_builddir)/lib/common/libcrmcommon.la
 libstonithd_la_SOURCES	= st_client.c
diff --git a/lib/lrmd/Makefile.am b/lib/lrmd/Makefile.am
index 25f3d55..611675e 100644
--- a/lib/lrmd/Makefile.am
+++ b/lib/lrmd/Makefile.am
@@ -19,6 +19,10 @@ include $(top_srcdir)/Makefile.common
 lib_LTLIBRARIES		= liblrmd.la
 
 liblrmd_la_LDFLAGS	= -version-info 4:0:3
+
+liblrmd_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+liblrmd_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 liblrmd_la_LIBADD	= $(top_builddir)/lib/common/libcrmcommon.la	\
 			$(top_builddir)/lib/services/libcrmservice.la	\
 			$(top_builddir)/lib/fencing/libstonithd.la
diff --git a/lib/pengine/Makefile.am b/lib/pengine/Makefile.am
index de760c3..ad5c5c3 100644
--- a/lib/pengine/Makefile.am
+++ b/lib/pengine/Makefile.am
@@ -24,10 +24,18 @@ lib_LTLIBRARIES		= libpe_rules.la libpe_status.la
 noinst_HEADERS		= unpack.h variant.h
 
 libpe_rules_la_LDFLAGS	= -version-info 2:6:0
+
+libpe_rules_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+libpe_rules_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libpe_rules_la_LIBADD	= $(top_builddir)/lib/common/libcrmcommon.la
 libpe_rules_la_SOURCES	= rules.c common.c
 
 libpe_status_la_LDFLAGS	= -version-info 11:0:1
+
+libpe_status_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+libpe_status_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libpe_status_la_LIBADD	= @CURSESLIBS@ $(top_builddir)/lib/common/libcrmcommon.la
 libpe_status_la_SOURCES	= status.c unpack.c utils.c complex.c native.c \
 			group.c clone.c rules.c common.c remote.c
diff --git a/lib/services/Makefile.am b/lib/services/Makefile.am
index c789fbd..b3208c2 100644
--- a/lib/services/Makefile.am
+++ b/lib/services/Makefile.am
@@ -27,6 +27,9 @@ libcrmservice_la_LDFLAGS	= -version-info 4:1:1
 libcrmservice_la_CPPFLAGS	= -DOCF_ROOT_DIR=\"@OCF_ROOT_DIR@\" $(AM_CPPFLAGS)
 libcrmservice_la_CFLAGS		= $(GIO_CFLAGS)
 
+libcrmservice_la_CFLAGS		+= $(CFLAGS_HARDENED_LIB)
+libcrmservice_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libcrmservice_la_LIBADD		= $(GIO_LIBS) $(top_builddir)/lib/common/libcrmcommon.la $(DBUS_LIBS)
 
 libcrmservice_la_SOURCES	= services.c services_linux.c
diff --git a/lib/transition/Makefile.am b/lib/transition/Makefile.am
index 9bc039e..4d6cd23 100644
--- a/lib/transition/Makefile.am
+++ b/lib/transition/Makefile.am
@@ -25,6 +25,9 @@ lib_LTLIBRARIES			= libtransitioner.la
 libtransitioner_la_LDFLAGS	= -version-info 2:5:0
 libtransitioner_la_CPPFLAGS	= -I$(top_builddir) $(AM_CPPFLAGS)
 
+libtransitioner_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+libtransitioner_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libtransitioner_la_LIBADD	= $(top_builddir)/lib/common/libcrmcommon.la
 libtransitioner_la_SOURCES	= unpack.c graph.c utils.c
 
diff --git a/lrmd/Makefile.am b/lrmd/Makefile.am
index 64df105..5846503 100644
--- a/lrmd/Makefile.am
+++ b/lrmd/Makefile.am
@@ -30,6 +30,9 @@ if BUILD_SYSTEMD
 systemdunit_DATA	= pacemaker_remote.service
 endif
 
+lrmd_CFLAGS		= $(CFLAGS_HARDENED_EXE)
+lrmd_LDFLAGS		= $(LDFLAGS_HARDENED_EXE)
+
 lrmd_LDADD		= $(top_builddir)/lib/common/libcrmcommon.la	\
 			$(top_builddir)/lib/services/libcrmservice.la	\
 			$(top_builddir)/lib/lrmd/liblrmd.la		\
@@ -38,6 +41,9 @@ lrmd_SOURCES		= main.c lrmd.c
 
 pacemaker_remoted_CPPFLAGS	= -DSUPPORT_REMOTE $(AM_CPPFLAGS)
 
+pacemaker_remoted_CFLAGS	= $(CFLAGS_HARDENED_EXE)
+pacemaker_remoted_LDFLAGS	= $(LDFLAGS_HARDENED_EXE)
+
 pacemaker_remoted_LDADD		= $(lrmd_LDADD)
 pacemaker_remoted_SOURCES	= main.c lrmd.c tls_backend.c ipc_proxy.c
 
diff --git a/mcp/Makefile.am b/mcp/Makefile.am
index 195530a..074d251 100644
--- a/mcp/Makefile.am
+++ b/mcp/Makefile.am
@@ -31,6 +31,9 @@ endif
 
 noinst_HEADERS		= pacemaker.h
 
+pacemakerd_CFLAGS	= $(CFLAGS_HARDENED_EXE)
+pacemakerd_LDFLAGS	= $(LDFLAGS_HARDENED_EXE)
+
 pacemakerd_LDADD	= $(top_builddir)/lib/cluster/libcrmcluster.la $(top_builddir)/lib/common/libcrmcommon.la
 pacemakerd_LDADD	+= $(CLUSTERLIBS)
 pacemakerd_SOURCES	= pacemaker.c corosync.c
diff --git a/pacemaker.spec.in b/pacemaker.spec.in
index 6024514..a607588 100644
--- a/pacemaker.spec.in
+++ b/pacemaker.spec.in
@@ -63,6 +63,9 @@
 # Turn off cman support on platforms that normally ship with it
 %bcond_without cman
 
+# Turn off hardening of libraries and daemon executables
+%bcond_without hardening
+
 %if %{with profiling}
 # This disables -debuginfo package creation and also the stripping binaries/libraries
 # Useful if you want sane profiling data
@@ -168,6 +171,7 @@ resource health.
 
 Available rpmbuild rebuild options:
   --with(out) : cman stonithd doc coverage profiling pre_release upstart_job
+                hardening
 
 %package cli
 License:       GPLv2+ and LGPLv2+
@@ -301,6 +305,18 @@ find . -exec touch \{\} \;
 # Early versions of autotools (e.g. RHEL <= 5) do not support --docdir
 export docdir=%{pcmk_docdir}
 
+%if %{with hardening}
+# prefer distro-provided hardening flags in case they are defined
+# through _hardening_{c,ld}flags macros, configure script will
+# use its own defaults otherwise; if such hardenings are completely
+# undesired, rpmbuild using "--without hardening"
+# (or "--define '_without_hardening 1'")
+export CFLAGS_HARDENED_EXE="%{?_hardening_cflags}"
+export CFLAGS_HARDENED_LIB="%{?_hardening_cflags}"
+export LDFLAGS_HARDENED_EXE="%{?_hardening_ldflags}"
+export LDFLAGS_HARDENED_LIB="%{?_hardening_ldflags}"
+%endif
+
 ./autogen.sh
 
 %{configure}                                       \
@@ -309,6 +325,7 @@ export docdir=%{pcmk_docdir}
         %{!?with_cman:       --without-cman}       \
         --without-heartbeat                        \
         %{!?with_doc:        --with-brand=}        \
+        %{!?with_hardening:  --disable-hardening}  \
         --with-initdir=%{_initrddir}               \
         --localstatedir=%{_var}                    \
         --with-version=%{version}-%{release}
diff --git a/pengine/Makefile.am b/pengine/Makefile.am
index 96c914f..d4dbfb9 100644
--- a/pengine/Makefile.am
+++ b/pengine/Makefile.am
@@ -61,12 +61,18 @@ endif
 noinst_HEADERS	= allocate.h utils.h pengine.h
 
 libpengine_la_LDFLAGS	= -version-info 11:0:1
+
+libpengine_la_CFLAGS	= $(CFLAGS_HARDENED_LIB)
+libpengine_la_LDFLAGS	+= $(LDFLAGS_HARDENED_LIB)
+
 libpengine_la_LIBADD	= $(top_builddir)/lib/pengine/libpe_status.la \
 			$(top_builddir)/lib/cib/libcib.la
 # -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version
 libpengine_la_SOURCES	= pengine.c allocate.c utils.c constraints.c
 libpengine_la_SOURCES	+= native.c group.c clone.c master.c graph.c utilization.c
 
+pengine_CFLAGS	= $(CFLAGS_HARDENED_EXE)
+pengine_LDFLAGS	= $(LDFLAGS_HARDENED_EXE)
 pengine_LDADD	= $(top_builddir)/lib/cib/libcib.la $(COMMONLIBS)
 # libcib for get_object_root()
 #		$(top_builddir)/lib/hbclient/libhbclient.la
-- 
1.8.3.1


From 35ec27112452f2bd06ae8b395d8543db935e2b05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
Date: Wed, 22 Jun 2016 15:18:00 +0200
Subject: [PATCH 2/2] Build: configure.ac: prefer as-needed linking in case of
 "-z now"

Slight optimization of a default toolchain-flags-based hardening.
---
 configure.ac | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index edf6a91..4beb877 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1914,7 +1914,10 @@ elif test "x${HARDENING}" = "xyes" \
 			 pie=1]
 		)
 	fi
-	# daemons incl. libs: full RELRO if sensible
+	# daemons incl. libs: full RELRO if sensible + as-needed linking
+	#                     so as to possibly mitigate startup performance
+	#                     hit caused by excessive linking with unneeded
+	#                     libraries
 	if test "${relro}" = 1 && test "${pie}" = 1; then
 		flag="-Wl,-z,now"
 		CC_CHECK_LDFLAGS(["${flag}"],
@@ -1923,6 +1926,13 @@ elif test "x${HARDENING}" = "xyes" \
 			 bindnow=1]
 		)
 	fi
+	if test "${bindnow}" = 1; then
+		flag="-Wl,--as-needed"
+		CC_CHECK_LDFLAGS(["${flag}"],
+			[LDFLAGS_HARDENED_EXE="${LDFLAGS_HARDENED_EXE} ${flag}";
+			 LDFLAGS_HARDENED_LIB="${LDFLAGS_HARDENED_LIB} ${flag}"]
+		)
+	fi
 	# universal: prefer strong > all > default stack protector if possible
 	flag=
 	if cc_supports_flag -fstack-protector-strong; then
-- 
1.8.3.1