diff mbox series

[v6,01/14] Allow glibc to be built with _FORTIFY_SOURCE

Message ID 20230705143822.275049-2-fberat@redhat.com
State New
Headers show
Series Allow glibc to be built with _FORTIFY_SOURCE | expand

Commit Message

Frederic Berat July 5, 2023, 2:38 p.m. UTC
Add --enable-fortify-source option.

It is now possible to enable fortification through a configure option.
The level may be given as parameter, if none is provided, the configure
script will determine what is the highest level possible that can be set
considering GCC built-ins availability and set it.
If level is explicitly set to 3, configure checks if the compiler
supports the built-in function necessary for it or raise an error if it
isn't.

If the configure option isn't explicitly enabled, it _FORTIFY_SOURCE is
forcibly undefined (and therefore disabled).

The result of the configure checks are new variables, ${fortify_source}
and ${no_fortify_source} that can be used to appropriately populate
CFLAGS.

A dedicated patch will follow to make use of this variable in Makefiles
when necessary.

Updated NEWS and INSTALL.

Adding dedicated x86_64 variant that enables the configuration.
---
 INSTALL                      |  8 ++++
 Makeconfig                   | 35 +++++++++++++--
 NEWS                         |  6 +++
 config.make.in               |  3 +-
 configure                    | 83 ++++++++++++++++++++++++++++--------
 configure.ac                 | 60 ++++++++++++++++++--------
 elf/rtld-Rules               |  2 +-
 manual/install.texi          |  8 ++++
 scripts/build-many-glibcs.py |  4 +-
 9 files changed, 167 insertions(+), 42 deletions(-)

Comments

Siddhesh Poyarekar July 5, 2023, 2:41 p.m. UTC | #1
On 2023-07-05 10:38, Frédéric Bérat wrote:
> Add --enable-fortify-source option.
> 
> It is now possible to enable fortification through a configure option.
> The level may be given as parameter, if none is provided, the configure
> script will determine what is the highest level possible that can be set
> considering GCC built-ins availability and set it.
> If level is explicitly set to 3, configure checks if the compiler
> supports the built-in function necessary for it or raise an error if it
> isn't.
> 
> If the configure option isn't explicitly enabled, it _FORTIFY_SOURCE is
> forcibly undefined (and therefore disabled).
> 
> The result of the configure checks are new variables, ${fortify_source}
> and ${no_fortify_source} that can be used to appropriately populate
> CFLAGS.
> 
> A dedicated patch will follow to make use of this variable in Makefiles
> when necessary.
> 
> Updated NEWS and INSTALL.
> 
> Adding dedicated x86_64 variant that enables the configuration.
> ---
>   INSTALL                      |  8 ++++
>   Makeconfig                   | 35 +++++++++++++--
>   NEWS                         |  6 +++
>   config.make.in               |  3 +-
>   configure                    | 83 ++++++++++++++++++++++++++++--------
>   configure.ac                 | 60 ++++++++++++++++++--------
>   elf/rtld-Rules               |  2 +-
>   manual/install.texi          |  8 ++++
>   scripts/build-many-glibcs.py |  4 +-
>   9 files changed, 167 insertions(+), 42 deletions(-)

LGTM.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

> 
> diff --git a/INSTALL b/INSTALL
> index fe591c7dae..51297189c0 100644
> --- a/INSTALL
> +++ b/INSTALL
> @@ -276,6 +276,14 @@ if ‘CFLAGS’ is specified it must enable optimization.  For example:
>        the GNU C Library.  The default value refers to the main
>        bug-reporting information for the GNU C Library.
>   
> +‘--enable-fortify-source’
> +‘--enable-fortify-source=LEVEL’
> +     Use -D_FORTIFY_SOURCE=‘LEVEL’ to control hardening in the GNU C
> +     Library.  If not provided, ‘LEVEL’ defaults to highest possible
> +     value supported by the build compiler.
> +
> +     Default is to disable fortification.
> +
>      To build the library and related programs, type ‘make’.  This will
>   produce a lot of output, some of which may look like errors from ‘make’
>   but aren’t.  Look for error messages from ‘make’ containing ‘***’.
> diff --git a/Makeconfig b/Makeconfig
> index 2514db35f6..77d7fd14df 100644
> --- a/Makeconfig
> +++ b/Makeconfig
> @@ -543,12 +543,13 @@ endif  # +link
>   # ARM, gcc always produces different debugging symbols when invoked with
>   # a -O greater than 0 than when invoked with -O0, regardless of anything else
>   # we're using to suppress optimizations.  Therefore, we need to explicitly pass
> -# -O0 to it through CFLAGS.
> +# -O0 to it through CFLAGS. As a result, any fortification needs to be disabled
> +# as it needs -O greater than 0.
>   # Additionally, the build system will try to -include $(common-objpfx)/config.h
>   # when compiling the tests, which will throw an error if some special macros
>   # (such as __OPTIMIZE__ and IS_IN_build) aren't defined.  To avoid this, we
>   # tell gcc to define IS_IN_build.
> -CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build
> +CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build $(no-fortify-source)
>   
>   ifeq (yes,$(build-shared))
>   # These indicate whether to link using the built ld.so or the installed one.
> @@ -901,6 +902,16 @@ define elide-stack-protector
>   $(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-stack-protector))
>   endef
>   
> +# We might want to compile with fortify-source
> +ifneq ($(fortify-source),)
> ++fortify-source=$(fortify-source)
> +endif
> +
> +# Some routine can't be fortified like the ones used by fortify
> +define elide-fortify-source
> +$(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-fortify-source))
> +endef
> +
>   # The program that makes Emacs-style TAGS files.
>   ETAGS	:= etags
>   
> @@ -961,6 +972,18 @@ endif	# $(+cflags) == ""
>   	   $(+stack-protector) -fno-common
>   +gcc-nowarn := -w
>   
> +# We must filter out elf because the early bootstrap of the dynamic loader
> +# cannot be fortified. Likewise we exclude dlfcn because it is entangled
> +# with the loader. We must filter out csu because early startup, like the
> +# loader, cannot be fortified. Lastly debug is the fortification routines
> +# themselves and they cannot be fortified.
> +do-fortify = $(filter-out elf dlfcn csu debug,$(subdir))
> +ifeq ($(do-fortify),$(subdir))
> ++cflags += $(+fortify-source)
> +else
> ++cflags += $(no-fortify-source)
> +endif
> +
>   # Each sysdeps directory can contain header files that both will be
>   # used to compile and will be installed.  Each can also contain an
>   # include/ subdirectory, whose header files will be used to compile
> @@ -1010,7 +1033,7 @@ module-cppflags = $(if $(filter %.mk.i %.v.i,$(@F)),,$(module-cppflags-real))
>   # Note that we can't use -std=* in CPPFLAGS, because it overrides
>   # the implicit -lang-asm and breaks cpp behavior for .S files--notably
>   # it causes cpp to stop predefining __ASSEMBLER__.
> -CPPFLAGS = $(config-extra-cppflags) $(CPPUNDEFS) $(CPPFLAGS-config) \
> +CPPFLAGS = $(config-extra-cppflags) $(CPPFLAGS-config) \
>   	   $($(subdir)-CPPFLAGS) \
>   	   $(+includes) $(defines) $(module-cppflags) \
>   	   -include $(..)include/libc-symbols.h $(sysdep-CPPFLAGS) \
> @@ -1049,6 +1072,8 @@ object-suffixes :=
>   CPPFLAGS-.o = $(pic-default)
>   # libc.a must be compiled with -fPIE/-fpie for static PIE.
>   CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) $(pie-default)
> +CFLAGS-.o += $(call elide-fortify-source,.o,$(routines_no_fortify))
> +CFLAGS-.o += $(call elide-fortify-source,_chk.o,$(routines_no_fortify))
>   libtype.o := lib%.a
>   object-suffixes += .o
>   ifeq (yes,$(build-shared))
> @@ -1058,6 +1083,8 @@ object-suffixes += .os
>   pic-cppflags = -DPIC -DSHARED
>   CPPFLAGS-.os = $(pic-cppflags)
>   CFLAGS-.os = $(filter %frame-pointer,$(+cflags)) $(pic-ccflag)
> +CFLAGS-.os += $(call elide-fortify-source,.os,$(routines_no_fortify))
> +CFLAGS-.os += $(call elide-fortify-source,_chk.os,$(routines_no_fortify))
>   libtype.os := lib%_pic.a
>   # This can be changed by a sysdep makefile
>   pic-ccflag = -fPIC
> @@ -1077,6 +1104,8 @@ object-suffixes += .op
>   CPPFLAGS-.op = -DPROF $(pic-default)
>   # libc_p.a must be compiled with -fPIE/-fpie for static PIE.
>   CFLAGS-.op = -pg $(pie-default)
> +CFLAGS-.op += $(call elide-fortify-source,.op,$(routines_no_fortify))
> +CFLAGS-.op += $(call elide-fortify-source,_chk.op,$(routines_no_fortify))
>   libtype.op = lib%_p.a
>   endif
>   
> diff --git a/NEWS b/NEWS
> index 709ee40e50..f976abccbd 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -48,6 +48,12 @@ Major new features:
>   * The strlcpy and strlcat functions have been added.  They are derived
>     from OpenBSD, and are expected to be added to a future POSIX version.
>   
> +* A new configure option, "--enable-fortify-source", can be used to build the
> +  GNU C Library with _FORTIFY_SOURCE. The level of fortification can either be
> +  provided, or is set to the highest value supported by the compiler. If not
> +  explicitly enabled, then fortify source is forcibly disabled so to keep
> +  original behavior unchanged.
> +
>   Deprecated and removed features, and other changes affecting compatibility:
>   
>   * In the Linux kernel for the hppa/parisc architecture some of the
> diff --git a/config.make.in b/config.make.in
> index 4afd37feaf..d487a4f4e9 100644
> --- a/config.make.in
> +++ b/config.make.in
> @@ -64,6 +64,8 @@ have-fpie = @libc_cv_fpie@
>   have-ssp = @libc_cv_ssp@
>   stack-protector = @stack_protector@
>   no-stack-protector = @no_stack_protector@
> +fortify-source = @fortify_source@
> +no-fortify-source = @no_fortify_source@
>   have-selinux = @have_selinux@
>   have-libaudit = @have_libaudit@
>   have-libcap = @have_libcap@
> @@ -101,7 +103,6 @@ CXX = @CXX@
>   BUILD_CC = @BUILD_CC@
>   CFLAGS = @CFLAGS@
>   CPPFLAGS-config = @CPPFLAGS@
> -CPPUNDEFS = @CPPUNDEFS@
>   extra-nonshared-cflags = @extra_nonshared_cflags@
>   rtld-early-cflags = @rtld_early_cflags@
>   ASFLAGS-config = @ASFLAGS_config@
> diff --git a/configure b/configure
> index f84040644b..1833a4ce66 100755
> --- a/configure
> +++ b/configure
> @@ -611,7 +611,10 @@ libc_cv_gcc_unwind_find_fde
>   libc_extra_cppflags
>   libc_extra_cflags
>   libc_cv_cxx_thread_local
> -CPPUNDEFS
> +fortify_source
> +no_fortify_source
> +libc_cv_fortify_source
> +enable_fortify_source
>   have_selinux
>   have_libcap
>   have_libaudit
> @@ -782,6 +785,7 @@ enable_pt_chown
>   enable_mathvec
>   enable_cet
>   enable_scv
> +enable_fortify_source
>   with_cpu
>   '
>         ac_precious_vars='build_alias
> @@ -1452,6 +1456,10 @@ Optional Features:
>                             (CET), x86 only
>     --disable-scv           syscalls will not use scv instruction, even if the
>                             kernel supports it, powerpc only
> +  --enable-fortify-source[=1|2|3]
> +                          Use -D_FORTIFY_SOURCE=[1|2|3] to control code
> +                          hardening, defaults to highest possible value
> +                          supported by the build compiler.
>   
>   Optional Packages:
>     --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
> @@ -3717,6 +3725,18 @@ if test "$use_scv" != "no"; then :
>   
>   fi
>   
> +# Check whether --enable-fortify-source was given.
> +if test "${enable_fortify_source+set}" = set; then :
> +  enableval=$enable_fortify_source; enable_fortify_source=$enableval
> +else
> +  enable_fortify_source=no
> +fi
> +
> +case "$enable_fortify_source" in
> +1|2|3|no|yes) ;;
> +*) as_fn_error $? "Not a valid argument for --enable-fortify-source: \"$enable_fortify_source\"" "$LINENO" 5;;
> +esac
> +
>   # We keep the original values in `$config_*' and never modify them, so we
>   # can write them unchanged into config.make.  Everything else uses
>   # $machine, $vendor, and $os, and changes them whenever convenient.
> @@ -6353,40 +6373,67 @@ $as_echo "#define HAVE_LIBCAP 1" >>confdefs.h
>   fi
>   
>   
> -CPPUNDEFS=
> -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FORTIFY_SOURCE predefine" >&5
> -$as_echo_n "checking for _FORTIFY_SOURCE predefine... " >&6; }
> -if ${libc_cv_predef_fortify_source+:} false; then :
> +no_fortify_source="-Wp,-U_FORTIFY_SOURCE"
> +fortify_source="${no_fortify_source}"
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_dynamic_object_size" >&5
> +$as_echo_n "checking for __builtin_dynamic_object_size... " >&6; }
> +if ${libc_cv___builtin_dynamic_object_size+:} false; then :
>     $as_echo_n "(cached) " >&6
>   else
> -  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> +
> +    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
>   /* end confdefs.h.  */
>   
>   int
>   main ()
>   {
> -
> -#ifdef _FORTIFY_SOURCE
> -# error bogon
> -#endif
> +__builtin_dynamic_object_size("", 0)
>     ;
>     return 0;
>   }
>   _ACEOF
> -if ac_fn_c_try_compile "$LINENO"; then :
> -  libc_cv_predef_fortify_source=no
> +if ac_fn_c_try_link "$LINENO"; then :
> +  libc_cv___builtin_dynamic_object_size=yes
> +         if test "$enable_fortify_source" = yes; then :
> +  enable_fortify_source=3
> +fi
>   else
> -  libc_cv_predef_fortify_source=yes
> +  libc_cv___builtin_dynamic_object_size=no
> +         if test "$enable_fortify_source" = yes; then :
> +  enable_fortify_source=2
>   fi
> -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
>   fi
> -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_predef_fortify_source" >&5
> -$as_echo "$libc_cv_predef_fortify_source" >&6; }
> -if test $libc_cv_predef_fortify_source = yes; then
> -  CPPUNDEFS="${CPPUNDEFS:+$CPPUNDEFS }-U_FORTIFY_SOURCE"
> +rm -f core conftest.err conftest.$ac_objext \
> +    conftest$ac_exeext conftest.$ac_ext
> +
> +fi
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv___builtin_dynamic_object_size" >&5
> +$as_echo "$libc_cv___builtin_dynamic_object_size" >&6; }
> +
> +case $enable_fortify_source in #(
> +  1|2) :
> +    libc_cv_fortify_source=yes ;; #(
> +  3) :
> +    if test "$libc_cv___builtin_dynamic_object_size" = yes; then :
> +  libc_cv_fortify_source=yes
> +else
> +  as_fn_error $? "Compiler doesn't provide necessary support for _FORTIFY_SOURCE=3" "$LINENO" 5
> +fi ;; #(
> +  *) :
> +    libc_cv_fortify_source=no ;;
> +esac
> +
> +if test "$libc_cv_fortify_source" = yes; then :
> +  fortify_source="${fortify_source},-D_FORTIFY_SOURCE=${enable_fortify_source}"
> +
>   fi
>   
>   
> +
> +
> +
> +
>   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the assembler requires one version per symbol" >&5
>   $as_echo_n "checking whether the assembler requires one version per symbol... " >&6; }
>   if ${libc_cv_symver_needs_alias+:} false; then :
> diff --git a/configure.ac b/configure.ac
> index 21879c933c..860109e60a 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -466,6 +466,17 @@ AC_ARG_ENABLE([scv],
>   
>   AS_IF([[test "$use_scv" != "no"]],[AC_DEFINE(USE_PPC_SCV)])
>   
> +dnl Build glibc with _FORTIFY_SOURCE
> +AC_ARG_ENABLE(fortify-source,
> +              AS_HELP_STRING([--enable-fortify-source@<:@=1|2|3@:>@],
> +                             [Use -D_FORTIFY_SOURCE=[1|2|3] to control code hardening, defaults to highest possible value supported by the build compiler.]),
> +              [enable_fortify_source=$enableval],
> +              [enable_fortify_source=no])
> +case "$enable_fortify_source" in
> +1|2|3|no|yes) ;;
> +*) AC_MSG_ERROR([Not a valid argument for --enable-fortify-source: "$enable_fortify_source"]);;
> +esac
> +
>   # We keep the original values in `$config_*' and never modify them, so we
>   # can write them unchanged into config.make.  Everything else uses
>   # $machine, $vendor, and $os, and changes them whenever convenient.
> @@ -1559,24 +1570,37 @@ if test "x$have_selinux" = xyes; then
>   fi
>   AC_SUBST(have_selinux)
>   
> -CPPUNDEFS=
> -dnl Check for silly hacked compilers predefining _FORTIFY_SOURCE.
> -dnl Since we are building the implementations of the fortified functions here,
> -dnl having the macro defined interacts very badly.
> -dnl _FORTIFY_SOURCE requires compiler optimization level 1 (gcc -O1)
> -dnl and above (see "man FEATURE_TEST_MACROS").
> -dnl So do NOT replace AC_COMPILE_IFELSE with AC_PREPROC_IFELSE.
> -AC_CACHE_CHECK([for _FORTIFY_SOURCE predefine], libc_cv_predef_fortify_source,
> -[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
> -#ifdef _FORTIFY_SOURCE
> -# error bogon
> -#endif]])],
> -		[libc_cv_predef_fortify_source=no],
> -		[libc_cv_predef_fortify_source=yes])])
> -if test $libc_cv_predef_fortify_source = yes; then
> -  CPPUNDEFS="${CPPUNDEFS:+$CPPUNDEFS }-U_FORTIFY_SOURCE"
> -fi
> -AC_SUBST(CPPUNDEFS)
> +dnl Check if we support the requested _FORTIFY_SOURCE level
> +dnl If not, then don't use it.
> +dnl Note that _FORTIFY_SOURCE may have been set through FLAGS too.
> +dnl _FORTIFY_SOURCE value will be selectively disabled for function that can't
> +dnl support it
> +no_fortify_source="-Wp,-U_FORTIFY_SOURCE"
> +fortify_source="${no_fortify_source}"
> +
> +AC_CACHE_CHECK([for __builtin_dynamic_object_size], [libc_cv___builtin_dynamic_object_size], [
> +    AC_LINK_IFELSE([AC_LANG_PROGRAM([], [__builtin_dynamic_object_size("", 0)])],
> +        [libc_cv___builtin_dynamic_object_size=yes
> +         AS_IF([test "$enable_fortify_source" = yes], [enable_fortify_source=3])],
> +        [libc_cv___builtin_dynamic_object_size=no
> +         AS_IF([test "$enable_fortify_source" = yes], [enable_fortify_source=2])])
> +])
> +
> +AS_CASE([$enable_fortify_source],
> +        [1|2], [libc_cv_fortify_source=yes],
> +        [3], [AS_IF([test "$libc_cv___builtin_dynamic_object_size" = yes],
> +                    [libc_cv_fortify_source=yes],
> +                    [AC_MSG_ERROR([Compiler doesn't provide necessary support for _FORTIFY_SOURCE=3])])],
> +        [libc_cv_fortify_source=no])
> +
> +AS_IF([test "$libc_cv_fortify_source" = yes],
> +      [fortify_source="${fortify_source},-D_FORTIFY_SOURCE=${enable_fortify_source}"]
> +      )
> +
> +AC_SUBST(enable_fortify_source)
> +AC_SUBST(libc_cv_fortify_source)
> +AC_SUBST(no_fortify_source)
> +AC_SUBST(fortify_source)
>   
>   dnl Starting with binutils 2.35, GAS can attach multiple symbol versions
>   dnl to one symbol (PR 23840).
> diff --git a/elf/rtld-Rules b/elf/rtld-Rules
> index 56bc4543de..365a3408f3 100644
> --- a/elf/rtld-Rules
> +++ b/elf/rtld-Rules
> @@ -144,6 +144,6 @@ cpp-srcs-left := $(rtld-modules:%.os=%)
>   lib := rtld
>   include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
>   
> -rtld-CFLAGS += $(no-stack-protector)
> +rtld-CFLAGS += $(no-stack-protector) $(no-fortify-source)
>   
>   endif
> diff --git a/manual/install.texi b/manual/install.texi
> index a44a552d1f..e9c66ba499 100644
> --- a/manual/install.texi
> +++ b/manual/install.texi
> @@ -303,6 +303,14 @@ Specify the URL that users should visit if they wish to report a bug,
>   to be included in @option{--help} output from programs installed with
>   @theglibc{}.  The default value refers to the main bug-reporting
>   information for @theglibc{}.
> +
> +@item --enable-fortify-source
> +@itemx --enable-fortify-source=@var{LEVEL}
> +Use -D_FORTIFY_SOURCE=@option{LEVEL} to control hardening in the GNU C Library.
> +If not provided, @option{LEVEL} defaults to highest possible value supported by
> +the build compiler.
> +
> +Default is to disable fortification.
>   @end table
>   
>   To build the library and related programs, type @code{make}.  This will
> diff --git a/scripts/build-many-glibcs.py b/scripts/build-many-glibcs.py
> index e022abe284..e4eaec01e3 100755
> --- a/scripts/build-many-glibcs.py
> +++ b/scripts/build-many-glibcs.py
> @@ -464,7 +464,9 @@ class Context(object):
>                                         {'arch': 'i486',
>                                          'ccopts': '-m32 -march=i486'},
>                                         {'arch': 'i586',
> -                                       'ccopts': '-m32 -march=i586'}])
> +                                       'ccopts': '-m32 -march=i586'},
> +                                      {'variant': 'enable-fortify-source',
> +                                       'cfg': ['--enable-fortify-source']}])
>           self.add_config(arch='x86_64',
>                           os_name='gnu',
>                           gcc_cfg=['--disable-multilib'])
diff mbox series

Patch

diff --git a/INSTALL b/INSTALL
index fe591c7dae..51297189c0 100644
--- a/INSTALL
+++ b/INSTALL
@@ -276,6 +276,14 @@  if ‘CFLAGS’ is specified it must enable optimization.  For example:
      the GNU C Library.  The default value refers to the main
      bug-reporting information for the GNU C Library.
 
+‘--enable-fortify-source’
+‘--enable-fortify-source=LEVEL’
+     Use -D_FORTIFY_SOURCE=‘LEVEL’ to control hardening in the GNU C
+     Library.  If not provided, ‘LEVEL’ defaults to highest possible
+     value supported by the build compiler.
+
+     Default is to disable fortification.
+
    To build the library and related programs, type ‘make’.  This will
 produce a lot of output, some of which may look like errors from ‘make’
 but aren’t.  Look for error messages from ‘make’ containing ‘***’.
diff --git a/Makeconfig b/Makeconfig
index 2514db35f6..77d7fd14df 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -543,12 +543,13 @@  endif  # +link
 # ARM, gcc always produces different debugging symbols when invoked with
 # a -O greater than 0 than when invoked with -O0, regardless of anything else
 # we're using to suppress optimizations.  Therefore, we need to explicitly pass
-# -O0 to it through CFLAGS.
+# -O0 to it through CFLAGS. As a result, any fortification needs to be disabled
+# as it needs -O greater than 0.
 # Additionally, the build system will try to -include $(common-objpfx)/config.h
 # when compiling the tests, which will throw an error if some special macros
 # (such as __OPTIMIZE__ and IS_IN_build) aren't defined.  To avoid this, we
 # tell gcc to define IS_IN_build.
-CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build
+CFLAGS-printers-tests := -O0 -ggdb3 -DIS_IN_build $(no-fortify-source)
 
 ifeq (yes,$(build-shared))
 # These indicate whether to link using the built ld.so or the installed one.
@@ -901,6 +902,16 @@  define elide-stack-protector
 $(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-stack-protector))
 endef
 
+# We might want to compile with fortify-source
+ifneq ($(fortify-source),)
++fortify-source=$(fortify-source)
+endif
+
+# Some routine can't be fortified like the ones used by fortify
+define elide-fortify-source
+$(if $(filter $(@F),$(patsubst %,%$(1),$(2))), $(no-fortify-source))
+endef
+
 # The program that makes Emacs-style TAGS files.
 ETAGS	:= etags
 
@@ -961,6 +972,18 @@  endif	# $(+cflags) == ""
 	   $(+stack-protector) -fno-common
 +gcc-nowarn := -w
 
+# We must filter out elf because the early bootstrap of the dynamic loader
+# cannot be fortified. Likewise we exclude dlfcn because it is entangled
+# with the loader. We must filter out csu because early startup, like the
+# loader, cannot be fortified. Lastly debug is the fortification routines
+# themselves and they cannot be fortified.
+do-fortify = $(filter-out elf dlfcn csu debug,$(subdir))
+ifeq ($(do-fortify),$(subdir))
++cflags += $(+fortify-source)
+else
++cflags += $(no-fortify-source)
+endif
+
 # Each sysdeps directory can contain header files that both will be
 # used to compile and will be installed.  Each can also contain an
 # include/ subdirectory, whose header files will be used to compile
@@ -1010,7 +1033,7 @@  module-cppflags = $(if $(filter %.mk.i %.v.i,$(@F)),,$(module-cppflags-real))
 # Note that we can't use -std=* in CPPFLAGS, because it overrides
 # the implicit -lang-asm and breaks cpp behavior for .S files--notably
 # it causes cpp to stop predefining __ASSEMBLER__.
-CPPFLAGS = $(config-extra-cppflags) $(CPPUNDEFS) $(CPPFLAGS-config) \
+CPPFLAGS = $(config-extra-cppflags) $(CPPFLAGS-config) \
 	   $($(subdir)-CPPFLAGS) \
 	   $(+includes) $(defines) $(module-cppflags) \
 	   -include $(..)include/libc-symbols.h $(sysdep-CPPFLAGS) \
@@ -1049,6 +1072,8 @@  object-suffixes :=
 CPPFLAGS-.o = $(pic-default)
 # libc.a must be compiled with -fPIE/-fpie for static PIE.
 CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) $(pie-default)
+CFLAGS-.o += $(call elide-fortify-source,.o,$(routines_no_fortify))
+CFLAGS-.o += $(call elide-fortify-source,_chk.o,$(routines_no_fortify))
 libtype.o := lib%.a
 object-suffixes += .o
 ifeq (yes,$(build-shared))
@@ -1058,6 +1083,8 @@  object-suffixes += .os
 pic-cppflags = -DPIC -DSHARED
 CPPFLAGS-.os = $(pic-cppflags)
 CFLAGS-.os = $(filter %frame-pointer,$(+cflags)) $(pic-ccflag)
+CFLAGS-.os += $(call elide-fortify-source,.os,$(routines_no_fortify))
+CFLAGS-.os += $(call elide-fortify-source,_chk.os,$(routines_no_fortify))
 libtype.os := lib%_pic.a
 # This can be changed by a sysdep makefile
 pic-ccflag = -fPIC
@@ -1077,6 +1104,8 @@  object-suffixes += .op
 CPPFLAGS-.op = -DPROF $(pic-default)
 # libc_p.a must be compiled with -fPIE/-fpie for static PIE.
 CFLAGS-.op = -pg $(pie-default)
+CFLAGS-.op += $(call elide-fortify-source,.op,$(routines_no_fortify))
+CFLAGS-.op += $(call elide-fortify-source,_chk.op,$(routines_no_fortify))
 libtype.op = lib%_p.a
 endif
 
diff --git a/NEWS b/NEWS
index 709ee40e50..f976abccbd 100644
--- a/NEWS
+++ b/NEWS
@@ -48,6 +48,12 @@  Major new features:
 * The strlcpy and strlcat functions have been added.  They are derived
   from OpenBSD, and are expected to be added to a future POSIX version.
 
+* A new configure option, "--enable-fortify-source", can be used to build the
+  GNU C Library with _FORTIFY_SOURCE. The level of fortification can either be
+  provided, or is set to the highest value supported by the compiler. If not
+  explicitly enabled, then fortify source is forcibly disabled so to keep
+  original behavior unchanged.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * In the Linux kernel for the hppa/parisc architecture some of the
diff --git a/config.make.in b/config.make.in
index 4afd37feaf..d487a4f4e9 100644
--- a/config.make.in
+++ b/config.make.in
@@ -64,6 +64,8 @@  have-fpie = @libc_cv_fpie@
 have-ssp = @libc_cv_ssp@
 stack-protector = @stack_protector@
 no-stack-protector = @no_stack_protector@
+fortify-source = @fortify_source@
+no-fortify-source = @no_fortify_source@
 have-selinux = @have_selinux@
 have-libaudit = @have_libaudit@
 have-libcap = @have_libcap@
@@ -101,7 +103,6 @@  CXX = @CXX@
 BUILD_CC = @BUILD_CC@
 CFLAGS = @CFLAGS@
 CPPFLAGS-config = @CPPFLAGS@
-CPPUNDEFS = @CPPUNDEFS@
 extra-nonshared-cflags = @extra_nonshared_cflags@
 rtld-early-cflags = @rtld_early_cflags@
 ASFLAGS-config = @ASFLAGS_config@
diff --git a/configure b/configure
index f84040644b..1833a4ce66 100755
--- a/configure
+++ b/configure
@@ -611,7 +611,10 @@  libc_cv_gcc_unwind_find_fde
 libc_extra_cppflags
 libc_extra_cflags
 libc_cv_cxx_thread_local
-CPPUNDEFS
+fortify_source
+no_fortify_source
+libc_cv_fortify_source
+enable_fortify_source
 have_selinux
 have_libcap
 have_libaudit
@@ -782,6 +785,7 @@  enable_pt_chown
 enable_mathvec
 enable_cet
 enable_scv
+enable_fortify_source
 with_cpu
 '
       ac_precious_vars='build_alias
@@ -1452,6 +1456,10 @@  Optional Features:
                           (CET), x86 only
   --disable-scv           syscalls will not use scv instruction, even if the
                           kernel supports it, powerpc only
+  --enable-fortify-source[=1|2|3]
+                          Use -D_FORTIFY_SOURCE=[1|2|3] to control code
+                          hardening, defaults to highest possible value
+                          supported by the build compiler.
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -3717,6 +3725,18 @@  if test "$use_scv" != "no"; then :
 
 fi
 
+# Check whether --enable-fortify-source was given.
+if test "${enable_fortify_source+set}" = set; then :
+  enableval=$enable_fortify_source; enable_fortify_source=$enableval
+else
+  enable_fortify_source=no
+fi
+
+case "$enable_fortify_source" in
+1|2|3|no|yes) ;;
+*) as_fn_error $? "Not a valid argument for --enable-fortify-source: \"$enable_fortify_source\"" "$LINENO" 5;;
+esac
+
 # We keep the original values in `$config_*' and never modify them, so we
 # can write them unchanged into config.make.  Everything else uses
 # $machine, $vendor, and $os, and changes them whenever convenient.
@@ -6353,40 +6373,67 @@  $as_echo "#define HAVE_LIBCAP 1" >>confdefs.h
 fi
 
 
-CPPUNDEFS=
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FORTIFY_SOURCE predefine" >&5
-$as_echo_n "checking for _FORTIFY_SOURCE predefine... " >&6; }
-if ${libc_cv_predef_fortify_source+:} false; then :
+no_fortify_source="-Wp,-U_FORTIFY_SOURCE"
+fortify_source="${no_fortify_source}"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_dynamic_object_size" >&5
+$as_echo_n "checking for __builtin_dynamic_object_size... " >&6; }
+if ${libc_cv___builtin_dynamic_object_size+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
 main ()
 {
-
-#ifdef _FORTIFY_SOURCE
-# error bogon
-#endif
+__builtin_dynamic_object_size("", 0)
   ;
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  libc_cv_predef_fortify_source=no
+if ac_fn_c_try_link "$LINENO"; then :
+  libc_cv___builtin_dynamic_object_size=yes
+         if test "$enable_fortify_source" = yes; then :
+  enable_fortify_source=3
+fi
 else
-  libc_cv_predef_fortify_source=yes
+  libc_cv___builtin_dynamic_object_size=no
+         if test "$enable_fortify_source" = yes; then :
+  enable_fortify_source=2
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_predef_fortify_source" >&5
-$as_echo "$libc_cv_predef_fortify_source" >&6; }
-if test $libc_cv_predef_fortify_source = yes; then
-  CPPUNDEFS="${CPPUNDEFS:+$CPPUNDEFS }-U_FORTIFY_SOURCE"
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv___builtin_dynamic_object_size" >&5
+$as_echo "$libc_cv___builtin_dynamic_object_size" >&6; }
+
+case $enable_fortify_source in #(
+  1|2) :
+    libc_cv_fortify_source=yes ;; #(
+  3) :
+    if test "$libc_cv___builtin_dynamic_object_size" = yes; then :
+  libc_cv_fortify_source=yes
+else
+  as_fn_error $? "Compiler doesn't provide necessary support for _FORTIFY_SOURCE=3" "$LINENO" 5
+fi ;; #(
+  *) :
+    libc_cv_fortify_source=no ;;
+esac
+
+if test "$libc_cv_fortify_source" = yes; then :
+  fortify_source="${fortify_source},-D_FORTIFY_SOURCE=${enable_fortify_source}"
+
 fi
 
 
+
+
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the assembler requires one version per symbol" >&5
 $as_echo_n "checking whether the assembler requires one version per symbol... " >&6; }
 if ${libc_cv_symver_needs_alias+:} false; then :
diff --git a/configure.ac b/configure.ac
index 21879c933c..860109e60a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -466,6 +466,17 @@  AC_ARG_ENABLE([scv],
 
 AS_IF([[test "$use_scv" != "no"]],[AC_DEFINE(USE_PPC_SCV)])
 
+dnl Build glibc with _FORTIFY_SOURCE
+AC_ARG_ENABLE(fortify-source,
+              AS_HELP_STRING([--enable-fortify-source@<:@=1|2|3@:>@],
+                             [Use -D_FORTIFY_SOURCE=[1|2|3] to control code hardening, defaults to highest possible value supported by the build compiler.]),
+              [enable_fortify_source=$enableval],
+              [enable_fortify_source=no])
+case "$enable_fortify_source" in
+1|2|3|no|yes) ;;
+*) AC_MSG_ERROR([Not a valid argument for --enable-fortify-source: "$enable_fortify_source"]);;
+esac
+
 # We keep the original values in `$config_*' and never modify them, so we
 # can write them unchanged into config.make.  Everything else uses
 # $machine, $vendor, and $os, and changes them whenever convenient.
@@ -1559,24 +1570,37 @@  if test "x$have_selinux" = xyes; then
 fi
 AC_SUBST(have_selinux)
 
-CPPUNDEFS=
-dnl Check for silly hacked compilers predefining _FORTIFY_SOURCE.
-dnl Since we are building the implementations of the fortified functions here,
-dnl having the macro defined interacts very badly.
-dnl _FORTIFY_SOURCE requires compiler optimization level 1 (gcc -O1)
-dnl and above (see "man FEATURE_TEST_MACROS").
-dnl So do NOT replace AC_COMPILE_IFELSE with AC_PREPROC_IFELSE.
-AC_CACHE_CHECK([for _FORTIFY_SOURCE predefine], libc_cv_predef_fortify_source,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
-#ifdef _FORTIFY_SOURCE
-# error bogon
-#endif]])],
-		[libc_cv_predef_fortify_source=no],
-		[libc_cv_predef_fortify_source=yes])])
-if test $libc_cv_predef_fortify_source = yes; then
-  CPPUNDEFS="${CPPUNDEFS:+$CPPUNDEFS }-U_FORTIFY_SOURCE"
-fi
-AC_SUBST(CPPUNDEFS)
+dnl Check if we support the requested _FORTIFY_SOURCE level
+dnl If not, then don't use it.
+dnl Note that _FORTIFY_SOURCE may have been set through FLAGS too.
+dnl _FORTIFY_SOURCE value will be selectively disabled for function that can't
+dnl support it
+no_fortify_source="-Wp,-U_FORTIFY_SOURCE"
+fortify_source="${no_fortify_source}"
+
+AC_CACHE_CHECK([for __builtin_dynamic_object_size], [libc_cv___builtin_dynamic_object_size], [
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([], [__builtin_dynamic_object_size("", 0)])],
+        [libc_cv___builtin_dynamic_object_size=yes
+         AS_IF([test "$enable_fortify_source" = yes], [enable_fortify_source=3])],
+        [libc_cv___builtin_dynamic_object_size=no
+         AS_IF([test "$enable_fortify_source" = yes], [enable_fortify_source=2])])
+])
+
+AS_CASE([$enable_fortify_source],
+        [1|2], [libc_cv_fortify_source=yes],
+        [3], [AS_IF([test "$libc_cv___builtin_dynamic_object_size" = yes],
+                    [libc_cv_fortify_source=yes],
+                    [AC_MSG_ERROR([Compiler doesn't provide necessary support for _FORTIFY_SOURCE=3])])],
+        [libc_cv_fortify_source=no])
+
+AS_IF([test "$libc_cv_fortify_source" = yes],
+      [fortify_source="${fortify_source},-D_FORTIFY_SOURCE=${enable_fortify_source}"]
+      )
+
+AC_SUBST(enable_fortify_source)
+AC_SUBST(libc_cv_fortify_source)
+AC_SUBST(no_fortify_source)
+AC_SUBST(fortify_source)
 
 dnl Starting with binutils 2.35, GAS can attach multiple symbol versions
 dnl to one symbol (PR 23840).
diff --git a/elf/rtld-Rules b/elf/rtld-Rules
index 56bc4543de..365a3408f3 100644
--- a/elf/rtld-Rules
+++ b/elf/rtld-Rules
@@ -144,6 +144,6 @@  cpp-srcs-left := $(rtld-modules:%.os=%)
 lib := rtld
 include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
 
-rtld-CFLAGS += $(no-stack-protector)
+rtld-CFLAGS += $(no-stack-protector) $(no-fortify-source)
 
 endif
diff --git a/manual/install.texi b/manual/install.texi
index a44a552d1f..e9c66ba499 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -303,6 +303,14 @@  Specify the URL that users should visit if they wish to report a bug,
 to be included in @option{--help} output from programs installed with
 @theglibc{}.  The default value refers to the main bug-reporting
 information for @theglibc{}.
+
+@item --enable-fortify-source
+@itemx --enable-fortify-source=@var{LEVEL}
+Use -D_FORTIFY_SOURCE=@option{LEVEL} to control hardening in the GNU C Library.
+If not provided, @option{LEVEL} defaults to highest possible value supported by
+the build compiler.
+
+Default is to disable fortification.
 @end table
 
 To build the library and related programs, type @code{make}.  This will
diff --git a/scripts/build-many-glibcs.py b/scripts/build-many-glibcs.py
index e022abe284..e4eaec01e3 100755
--- a/scripts/build-many-glibcs.py
+++ b/scripts/build-many-glibcs.py
@@ -464,7 +464,9 @@  class Context(object):
                                       {'arch': 'i486',
                                        'ccopts': '-m32 -march=i486'},
                                       {'arch': 'i586',
-                                       'ccopts': '-m32 -march=i586'}])
+                                       'ccopts': '-m32 -march=i586'},
+                                      {'variant': 'enable-fortify-source',
+                                       'cfg': ['--enable-fortify-source']}])
         self.add_config(arch='x86_64',
                         os_name='gnu',
                         gcc_cfg=['--disable-multilib'])