[PATCH 01/21] Add --enable-fortify-source option

Frederic Berat fberat@redhat.com
Wed Jun 21 13:18:05 GMT 2023


On Tue, Jun 20, 2023 at 8:19 PM Frédéric Bérat <fberat@redhat.com> wrote:
>
> It is now possible to enable fortification.
> 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.
>
> The result of the configure checks is 2 variables, $fortify_source and
> $no_fortify_source that are used to appropriately populate CFLAGS.
>
> Since the feature needs some of the routines provided by Glibc, these
> are excluded from the fortification.
> ---
>  Makeconfig     | 33 ++++++++++++++++++++++++---
>  config.make.in |  3 ++-
>  configure.ac   | 60 +++++++++++++++++++++++++++++++++++---------------
>  elf/rtld-Rules |  2 +-
>  4 files changed, 75 insertions(+), 23 deletions(-)
>
> diff --git a/Makeconfig b/Makeconfig
> index 2514db35f6..59fbd9ebf9 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. By side effect, 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,16 @@ 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)
> +endif

This needs to be adapted to deal with compilers that define
"_FORTIFY_SOURCE" by default (checked on ubuntu 22.04):

+do-fortify = $(filter-out elf dlfcn csu debug,$(subdir))
+ifeq ($(do-fortify),$(subdir))
++cflags += $(+fortify-source)
+else
++cflags += $(no-fortify-source)
+endif

That way, we ensure that even if _FORTIFY_SOURCE is enabled at system
level, we don't build these subdirectories with it.

> +
>  # 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 +1031,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 +1070,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 +1081,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 +1102,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/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.ac b/configure.ac
> index 21879c933c..ec4de6e551 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 for your system]),
> +              [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
> +fortify_source=""
> +no_fortify_source="-Wp,-U_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="${no_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
> --
> 2.41.0
>



More information about the Libc-alpha mailing list