Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/m4/hardening.m4
1532 views
dnl
dnl https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html
dnl
AC_DEFUN([SUDO_CHECK_HARDENING], [
    if test "$enable_hardening" != "no"; then
	#
	# Attempt to use _FORTIFY_SOURCE with sprintf.  If the headers support
	# it but libc does not, __sprintf_chk should be an undefined symbol.
	# Some systems warn about using a value of _FORTIFY_SOURCE > 2.
	#
	O_CPPFLAGS="$CPPFLAGS"
	AC_CACHE_CHECK([supported _FORTIFY_SOURCE level],
	    [sudo_cv_fortify_source_level],
	    [
		AX_APPEND_FLAG([-U_FORTIFY_SOURCE], [CPPFLAGS])
		AX_APPEND_FLAG([-D_FORTIFY_SOURCE=3], [CPPFLAGS])
		AC_LINK_IFELSE([
		    AC_LANG_PROGRAM(
			[[#include <stdio.h>]],
			[[char buf[4]; sprintf(buf, "%s", "foo"); return buf[0];]]
		    )], [
			sudo_cv_fortify_source_level=3
		    ], [
			# Try again with -D_FORTIFY_SOURCE=2
			CPPFLAGS="$O_CPPFLAGS"
			AX_APPEND_FLAG([-U_FORTIFY_SOURCE], [CPPFLAGS])
			AX_APPEND_FLAG([-D_FORTIFY_SOURCE=2], [CPPFLAGS])
			AC_LINK_IFELSE([
			    AC_LANG_PROGRAM(
				[[#include <stdio.h>]],
				[[char buf[4]; sprintf(buf, "%s", "foo"); return buf[0];]]
			    )], [
				sudo_cv_fortify_source_level=2
			    ], [
				sudo_cv_fortify_source_level=none
			    ]
			)
		    ]
		)
	    ]
	)
	CPPFLAGS="$O_CPPFLAGS"
	if test "$sudo_cv_fortify_source_level" != none; then
	    AX_APPEND_FLAG([-U_FORTIFY_SOURCE], [CPPFLAGS])
	    AX_APPEND_FLAG([-D_FORTIFY_SOURCE=$sudo_cv_fortify_source_level], [CPPFLAGS])
	fi

	dnl
	dnl The following tests rely on AC_LANG_WERROR.
	dnl
	if test -n "$GCC" -a "$enable_ssp" != "no"; then
	    AC_CACHE_CHECK([for compiler stack protector support],
		[sudo_cv_var_stack_protector],
		[
		    # Avoid CFLAGS since the compiler might optimize away our
		    # test.  We don't want CPPFLAGS or LIBS to interfere with
		    # the test but keep LDFLAGS as it may have an rpath needed
		    # to find the ssp lib.
		    _CPPFLAGS="$CPPFLAGS"
		    _CFLAGS="$CFLAGS"
		    _LDFLAGS="$LDFLAGS"
		    _LIBS="$LIBS"
		    CPPFLAGS=
		    LIBS=

		    sudo_cv_var_stack_protector="-fstack-protector-strong"
		    CFLAGS="$sudo_cv_var_stack_protector"
		    LDFLAGS="$_LDFLAGS $sudo_cv_var_stack_protector"
		    AC_LINK_IFELSE([
			AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
			[[char buf[1024]; buf[1023] = '\0';]])
		    ], [], [
			sudo_cv_var_stack_protector="-fstack-protector-all"
			CFLAGS="$sudo_cv_var_stack_protector"
			LDFLAGS="$_LDFLAGS $sudo_cv_var_stack_protector"
			AC_LINK_IFELSE([
			    AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
			    [[char buf[1024]; buf[1023] = '\0';]])
			], [], [
			    sudo_cv_var_stack_protector="-fstack-protector"
			    CFLAGS="$sudo_cv_var_stack_protector"
			    LDFLAGS="$_LDFLAGS $sudo_cv_var_stack_protector"
			    AC_LINK_IFELSE([
				AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
				[[char buf[1024]; buf[1023] = '\0';]])
			    ], [], [
				sudo_cv_var_stack_protector=no
			    ])
			])
		    ])
		    CPPFLAGS="$_CPPFLAGS"
		    CFLAGS="$_CFLAGS"
		    LDFLAGS="$_LDFLAGS"
		    LIBS="$_LIBS"
		]
	    )
	    if test X"$sudo_cv_var_stack_protector" != X"no"; then
		HARDENING_CFLAGS="$sudo_cv_var_stack_protector"
		HARDENING_LDFLAGS="-Wc,$sudo_cv_var_stack_protector"
	    fi
	fi

	# The gcc front-end may accept -fstack-clash-protection even if the
	# machine-specific code does not support it.  We use a test program
	# with a large stack allocation to try to cause the compiler to
	# insert the stack clash protection code, or fail if not supported.
	if test -n "$GCC"; then
	    AC_CACHE_CHECK([whether C compiler supports -fstack-clash-protection],
		[sudo_cv_check_cflags___fstack_clash_protection],
		[
		    _CFLAGS="$CFLAGS"
		    CFLAGS="$CFLAGS -fstack-clash-protection"
		    AC_COMPILE_IFELSE([
			AC_LANG_SOURCE([[int main(int argc, char *argv[]) { char buf[16384], *src = argv[0], *dst = buf; while ((*dst++ = *src++) != '\0') { continue; } return buf[argc]; }]])
		    ], [sudo_cv_check_cflags___fstack_clash_protection=yes], [sudo_cv_check_cflags___fstack_clash_protection=no])
		    CFLAGS="$_CFLAGS"
		]
	    )
	    if test X"$sudo_cv_check_cflags___fstack_clash_protection" = X"yes"; then
		AX_CHECK_LINK_FLAG([-fstack-clash-protection], [
		    AX_APPEND_FLAG([-fstack-clash-protection], [HARDENING_CFLAGS])
		    AX_APPEND_FLAG([-Wc,-fstack-clash-protection], [HARDENING_LDFLAGS])
		])
	    fi

	    # Check for control-flow transfer instrumentation (Intel CET).
	    # Do not enable branch protection for 32-bit, since no 32-bit
	    # OS supports it and the generated ENDBR32 instructions have
	    # compatibility issues with some older i586/i686 compatible
	    # processors (e.g. Geode or Vortex).
	    AS_CASE([$host_cpu], [x86_64], [
		AX_CHECK_COMPILE_FLAG([-fcf-protection=full], [
		    AX_CHECK_LINK_FLAG([-fcf-protection=full], [
			AX_APPEND_FLAG([-fcf-protection=full], [HARDENING_CFLAGS])
			AX_APPEND_FLAG([-Wc,-fcf-protection=full], [HARDENING_LDFLAGS])
		    ])
		])
	    ], [i*86], [
		AX_CHECK_COMPILE_FLAG([-fcf-protection=return], [
		    AX_CHECK_LINK_FLAG([-fcf-protection=return], [
			AX_APPEND_FLAG([-fcf-protection=return], [HARDENING_CFLAGS])
			AX_APPEND_FLAG([-Wc,-fcf-protection=return], [HARDENING_LDFLAGS])
		    ])
		])
	    ])

	    #
	    # Check for branch protection against ROP and JOP attacks on
	    # AArch64 by using PAC and BTI.
	    #
	    AS_IF([test "$host_cpu" = "aarch64"], [
		AX_CHECK_COMPILE_FLAG([-mbranch-protection=standard], [
		    AX_CHECK_LINK_FLAG([-mbranch-protection=standard], [
			AX_APPEND_FLAG([-mbranch-protection=standard], [HARDENING_CFLAGS])
			AX_APPEND_FLAG([-Wc,-mbranch-protection=standard], [HARDENING_LDFLAGS])
		    ])
		])
	    ])

	    # Force retention of null pointer checks.
	    AX_CHECK_COMPILE_FLAG([-fno-delete-null-pointer-checks], [AX_APPEND_FLAG([-fno-delete-null-pointer-checks], [HARDENING_CFLAGS])])

	    # Guarantee zero initialization of padding bits in
	    # all automatic variable initializers.
	    AX_CHECK_COMPILE_FLAG([-fzero-init-padding-bits=all], [AX_APPEND_FLAG([-fzero-init-padding-bits=all], [HARDENING_CFLAGS])])

	    # Define behavior for signed integer and pointer overflow.
	    AX_CHECK_COMPILE_FLAG([-fno-strict-overflow], [AX_APPEND_FLAG([-fno-strict-overflow], [HARDENING_CFLAGS])])

	    # Disable strict aliasing rules that allow the compiler to assume
	    # that two objects of different types may not use the same address.
	    AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing], [AX_APPEND_FLAG([-fno-strict-aliasing], [HARDENING_CFLAGS])])

	    # Initialize automatic variables without an assignment to zero.
	    # This prevents uninitialized variables from having stack garbage.
	    AX_CHECK_COMPILE_FLAG([-ftrivial-auto-var-init=zero], [AX_APPEND_FLAG([-ftrivial-auto-var-init=zero], [HARDENING_CFLAGS])])
	fi

	# Linker-specific hardening for GNU ld and similar (gold, lld, etc).
	if test X"$with_gnu_ld" = X"yes"; then
	    # Mark relocation table entries resolved at load-time as read-only.
	    AX_CHECK_LINK_FLAG([-Wl,-z,relro], [AX_APPEND_FLAG([-Wl,-z,relro], [HARDENING_LDFLAGS])])

	    # Resolve all symbols when the program is started.
	    AX_CHECK_LINK_FLAG([-Wl,-z,now], [AX_APPEND_FLAG([-Wl,-z,now], [HARDENING_LDFLAGS])])

	    # Mark stack memory as non-executable.
	    AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [AX_APPEND_FLAG([-Wl,-z,noexecstack], [HARDENING_LDFLAGS])])

	    # Only link libraries containing symbols that are actually used.
	    AX_CHECK_LINK_FLAG([-Wl,--as-needed], [AX_APPEND_FLAG([-Wl,--as-needed], [HARDENING_LDFLAGS])])

	    # Don't resolve symbols using transitive library dependencies.
	    # The binary must explicitly link against all of its dependencies.
	    AX_CHECK_LINK_FLAG([-Wl,--no-copy-dt-needed-entries], [AX_APPEND_FLAG([-Wl,--no-copy-dt-needed-entries], [HARDENING_LDFLAGS])])
	fi
    fi])