From ba951afb99912da01a6e8434126b8fac7aa75107 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 3 May 2022 11:42:24 +0100 Subject: [PATCH] Add a linker warning when creating potentially dangerous executable segments. Add tests, options to disabke and configure switches to choose defaults. --- bfd/elf.c | 23 +++ bfd/elflink.c | 2 +- binutils/testsuite/lib/binutils-common.exp | 2 + include/bfdlink.h | 19 +- ld/NEWS | 24 ++- ld/aclocal.m4 | 193 ++++++++++----------- ld/config.in | 12 ++ ld/configure | 75 +++++++- ld/configure.ac | 52 ++++++ ld/emultempl/elf.em | 3 + ld/ld.texi | 16 ++ ld/ldlex.h | 5 +- ld/lexsup.c | 31 ++++ ld/testsuite/ld-elf/changelma.d | 2 +- ld/testsuite/ld-elf/elf.exp | 50 +++++- ld/testsuite/ld-elf/flags1.d | 2 +- ld/testsuite/ld-elf/maxpage5.d | 2 +- ld/testsuite/ld-elf/note-2.d | 2 +- ld/testsuite/ld-elf/rwx-segments-1.l | 1 + ld/testsuite/ld-elf/rwx-segments-2.l | 1 + ld/testsuite/ld-elf/rwx-segments-2.t | 20 +++ 21 files changed, 413 insertions(+), 124 deletions(-) create mode 100644 ld/testsuite/ld-elf/rwx-segments-1.l create mode 100644 ld/testsuite/ld-elf/rwx-segments-2.l create mode 100644 ld/testsuite/ld-elf/rwx-segments-2.t diff --git a/bfd/elf.c b/bfd/elf.c index e9148dbecab..f046994e3a8 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -6461,6 +6461,29 @@ assign_file_positions_except_relocs (bfd *abfd, alloc = i_ehdrp->e_phnum; if (alloc != 0) { + if (link_info != NULL && ! link_info->no_warn_rwx_segments) + { + /* Memory resident segments with non-zero size and RWX permissions are a + security risk, so we generate a warning here if we are creating any. */ + unsigned int i; + + for (i = 0; i < alloc; i++) + { + const Elf_Internal_Phdr * phdr = tdata->phdr + i; + + if (phdr->p_memsz == 0) + continue; + + if (phdr->p_type == PT_TLS && (phdr->p_flags & PF_X)) + _bfd_error_handler (_("warning: %pB has a TLS segment with execute permission"), + abfd); + else if (phdr->p_type == PT_LOAD + && (phdr->p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_W | PF_X)) + _bfd_error_handler (_("warning: %pB has a LOAD segment with RWX permissions"), + abfd); + } + } + if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) != 0 || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) return false; diff --git a/bfd/elflink.c b/bfd/elflink.c index b54ee517c75..4d6fe663f68 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -7168,7 +7168,7 @@ warning: enabling an executable stack because of -z execstack command line optio break; } } - else if (bed->default_execstack) + else if (bed->default_execstack && info->default_execstack) { exec = PF_X; emptyobj = inputobj; diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp index a76a310c199..ccc33a827b4 100644 --- a/binutils/testsuite/lib/binutils-common.exp +++ b/binutils/testsuite/lib/binutils-common.exp @@ -639,6 +639,8 @@ proc prune_warnings_extra { text } { regsub -all "(^|\n)(\[^\n\]*: Warning: Gap in build notes detected from\[^\n\]*\n?)+" $text "\\1" text regsub -all "(^|\n)(\[^\n\]*: warning:\[^\n\]*missing \\.note\\.GNU-stack section\[^\n\]*\n?)+" $text "\\1" text regsub -all "(^|\n)(\[^\n\]*: NOTE: This behaviour is deprecated\[^\n\]*\n?)+" $text "\\1" text + regsub -all "(^|\n)(\[^\n\]*: warning:\[^\n\]*has a LOAD segment with RWX permissions\[^\n\]*\n?)+" $text "\\1" text + regsub -all "(^|\n)(\[^\n\]*: warning:\[^\n\]*has a TLS segment with execute permission\[^\n\]*\n?)+" $text "\\1" text return $text } diff --git a/include/bfdlink.h b/include/bfdlink.h index b16f3f44ca5..88cc8e26183 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -489,10 +489,25 @@ struct bfd_link_info flags. */ unsigned int noexecstack: 1; - /* Tri-state variable: 0 => not set by user; 1 => set, warnings - enabled; 2 => warnings disabled; 3 => unused. */ + /* Tri-state variable: + 0 => warn if the linker is creating an executable stack, but + execstack (above) is 0. + 1 => warn if the linker is creating an executable stack; ignores + the value of execstack. + 2 => do not warn. + 3 => not used. */ unsigned int warn_execstack: 2; + /* TRUE if warnings should not be generated for TLS segments with eXecute + permission or LOAD segments with RWX permissions. */ + unsigned int no_warn_rwx_segments: 1; + + /* TRUE if the stack can be made executable because of the absence of a + .note.GNU-stack section in an input file. Note - even if this field + is set, some targets may choose to ignore the setting and not create + an executable stack. */ + unsigned int default_execstack : 1; + /* TRUE if we want to produced optimized output files. This might need much more time and therefore must be explicitly selected. */ unsigned int optimize: 1; diff --git a/ld/NEWS b/ld/NEWS index b84553109d2..514d1d9f207 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -1,6 +1,6 @@ -*- text -*- -* The linker will now generate a warning message if the stack is made +* The ELF linker will now generate a warning message if the stack is made executable. By default this warning is not issued if the user has specifically requested an executable stack via the "-z execstack" command line option, but the warning can be forced via the new @@ -8,6 +8,28 @@ an executable stack can be suppressed via the "--no-warn-execstack" option. + In addition the ELF linker will also warn if it creates a memory resident + segment with all three of the Read, Write and eXecute permissions set, or + if it creates a thread local data segment with the eXecute permission set. + These warnings can be disabled via --no-warn-rwx-segments option and + re-enabled via the --warn-rwx-segments option. + + New configure options can also control these new features: + + --enable-warn-execstack=no + will disable the warnings about creating an executable stack. + + --enable-warn-execstack=yes + will make --warn-execstack enabled by default. + + --enable-warn-rwx-segments=no + will make --no-warn-rwx-segments enabled by default. + + --enable-defaul-execstack=no + will stop the creation of an executable stack simply because an input file + is missing a .note.GNU-stack section, even on architectures where this + ehaviour is the default. + * TYPE= is now supported in an output section description to set the section type value. diff --git a/ld/aclocal.m4 b/ld/aclocal.m4 index 631ead7b2ca..314969c6dd8 100644 --- a/ld/aclocal.m4 +++ b/ld/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.15.1 -*- Autoconf -*- +# generated automatically by aclocal 1.16.2 -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Copyright (C) 2002-2017 Free Software Foundation, Inc. +# Copyright (C) 2002-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.]) # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.15' +[am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.15.1], [], +m4_if([$1], [1.16.2], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.15.1])dnl +[AM_AUTOMAKE_VERSION([1.16.2])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -110,7 +110,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -141,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -332,13 +332,12 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. - # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], @@ -346,49 +345,43 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) shift - for mf + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_mf do # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named 'Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running 'make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "$am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE="gmake" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS @@ -397,18 +390,17 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each '.P' file that we will -# need in order to bootstrap the dependency handling code. +# This code is only required when automatic dependency tracking is enabled. +# This creates each '.Po' and '.Plo' makefile fragment that we'll need in +# order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) + [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -495,8 +487,8 @@ AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: -# -# +# +# AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. @@ -563,7 +555,7 @@ END Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . +that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM @@ -605,7 +597,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -626,7 +618,7 @@ if test x"${install_sh+set}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 1998-2017 Free Software Foundation, Inc. +# Copyright (C) 1998-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -647,7 +639,7 @@ fi]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -682,7 +674,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -690,49 +682,42 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) # AM_MAKE_INCLUDE() # ----------------- -# Check to see how make treats includes. +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' am__doit: - @echo this is the am__doit target + @echo this is the am__doit target >confinc.out .PHONY: am__doit END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from 'make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi -AC_SUBST([am__include]) -AC_SUBST([am__quote]) -AC_MSG_RESULT([$_am_result]) -rm -f confinc confmf -]) +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -771,7 +756,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -800,7 +785,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -847,7 +832,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -866,7 +851,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -947,7 +932,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2017 Free Software Foundation, Inc. +# Copyright (C) 2009-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1007,7 +992,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1035,7 +1020,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2017 Free Software Foundation, Inc. +# Copyright (C) 2006-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1054,7 +1039,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2017 Free Software Foundation, Inc. +# Copyright (C) 2004-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/ld/config.in b/ld/config.in index 26d55a00d47..cc5b476f009 100644 --- a/ld/config.in +++ b/ld/config.in @@ -16,12 +16,24 @@ /* Define if you want compressed debug sections by default. */ #undef DEFAULT_FLAG_COMPRESS_DEBUG +/* Define to 0 if you want to disable the generation of an executable stack + when a .note-GNU-stack section is missing. */ +#undef DEFAULT_LD_EXECSTACK + /* The default method for DT_TEXTREL check in ELF linker. */ #undef DEFAULT_LD_TEXTREL_CHECK /* Define to 1 if DT_TEXTREL check is warning in ELF linker by default. */ #undef DEFAULT_LD_TEXTREL_CHECK_WARNING +/* Define to 1 if you want to enable --warn-execstack in ELF linker by + default. */ +#undef DEFAULT_LD_WARN_EXECSTACK + +/* Define to 0 if you want to disable --warn-rwx-segments in ELF linker by + default. */ +#undef DEFAULT_LD_WARN_RWX_SEGMENTS + /* Define to 1 if you want to enable -z relro in ELF linker by default. */ #undef DEFAULT_LD_Z_RELRO diff --git a/ld/configure b/ld/configure index bab2d083ca8..b4b0ce14ed9 100755 --- a/ld/configure +++ b/ld/configure @@ -838,6 +838,9 @@ enable_new_dtags enable_relro enable_textrel_check enable_separate_code +enable_warn_execstack +enable_warn_rwx_segments +enable_default_execstack enable_error_handling_script enable_default_hash_style enable_initfini_array @@ -1510,6 +1513,13 @@ Optional Features: --enable-textrel-check=[yes|no|warning|error] enable DT_TEXTREL check in ELF linker --enable-separate-code enable -z separate-code in ELF linker by default + --enable-warn-execstack enable warnings when creating an executable stack + --enable-warn-rwx-segments + enable warnings when creating segements with RWX + permissions + --enable-default-execstack + create an executable stack if an input file is + missing a .note.GNU-stack section --enable-error-handling-script enable/disable support for the --error-handling-script option @@ -11460,7 +11470,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11463 "configure" +#line 11473 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11566,7 +11576,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11569 "configure" +#line 11579 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -15427,6 +15437,38 @@ esac fi + +ac_default_ld_warn_execstack=unset +# Check whether --enable-warn-execstack was given. +if test "${enable_warn_execstack+set}" = set; then : + enableval=$enable_warn_execstack; case "${enableval}" in + yes) ac_default_ld_warn_execstack=1 ;; + no) ac_default_ld_warn_execstack=-1 ;; +esac +fi + + +ac_default_ld_warn_rwx_segments=unset +# Check whether --enable-warn-rwx-segments was given. +if test "${enable_warn_rwx_segments+set}" = set; then : + enableval=$enable_warn_rwx_segments; case "${enableval}" in + yes) ac_default_ld_warn_rwx_segments=1 ;; + no) ac_default_ld_warn_rwx_segments=0 ;; +esac +fi + + +ac_default_ld_default_execstack=unset +# Check whether --enable-default-execstack was given. +if test "${enable_default_execstack+set}" = set; then : + enableval=$enable_default_execstack; case "${enableval}" in + yes) ac_default_ld_default_execstack=1 ;; + no) ac_default_ld_default_execstack=0 ;; +esac +fi + + + # Decide if --error-handling-script should be supported. ac_support_error_handling_script=unset # Check whether --enable-error-handling-script was given. @@ -16954,6 +16996,35 @@ cat >>confdefs.h <<_ACEOF _ACEOF + +if test "${ac_default_ld_warn_execstack}" = unset; then + ac_default_ld_warn_execstack=0 +fi + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_LD_WARN_EXECSTACK $ac_default_ld_warn_execstack +_ACEOF + + +if test "${ac_default_ld_warn_rwx_segments}" = unset; then + ac_default_ld_warn_rwx_segments=1 +fi + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_LD_WARN_RWX_SEGMENTS $ac_default_ld_warn_rwx_segments +_ACEOF + + +if test "${ac_default_ld_default_execstack}" = unset; then + ac_default_ld_default_execstack=1 +fi + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_LD_EXECSTACK $ac_default_ld_default_execstack +_ACEOF + + + if test "${ac_support_error_handling_script}" = unset; then ac_support_error_handling_script=1 fi diff --git a/ld/configure.ac b/ld/configure.ac index 7f4cff079b7..0b29e810dde 100644 --- a/ld/configure.ac +++ b/ld/configure.ac @@ -203,6 +203,35 @@ AC_ARG_ENABLE(separate-code, no) ac_default_ld_z_separate_code=0 ;; esac]) + +ac_default_ld_warn_execstack=unset +AC_ARG_ENABLE(warn-execstack, + AS_HELP_STRING([--enable-warn-execstack], + [enable warnings when creating an executable stack]), +[case "${enableval}" in + yes) ac_default_ld_warn_execstack=1 ;; + no) ac_default_ld_warn_execstack=-1 ;; +esac]) + +ac_default_ld_warn_rwx_segments=unset +AC_ARG_ENABLE(warn-rwx-segments, + AS_HELP_STRING([--enable-warn-rwx-segments], + [enable warnings when creating segements with RWX permissions]), +[case "${enableval}" in + yes) ac_default_ld_warn_rwx_segments=1 ;; + no) ac_default_ld_warn_rwx_segments=0 ;; +esac]) + +ac_default_ld_default_execstack=unset +AC_ARG_ENABLE(default-execstack, + AS_HELP_STRING([--enable-default-execstack], + [create an executable stack if an input file is missing a .note.GNU-stack section]), +[case "${enableval}" in + yes) ac_default_ld_default_execstack=1 ;; + no) ac_default_ld_default_execstack=0 ;; +esac]) + + # Decide if --error-handling-script should be supported. ac_support_error_handling_script=unset AC_ARG_ENABLE(error-handling-script, @@ -501,6 +530,29 @@ AC_DEFINE_UNQUOTED(DEFAULT_LD_Z_SEPARATE_CODE, $ac_default_ld_z_separate_code, [Define to 1 if you want to enable -z separate-code in ELF linker by default.]) + +if test "${ac_default_ld_warn_execstack}" = unset; then + ac_default_ld_warn_execstack=0 +fi +AC_DEFINE_UNQUOTED(DEFAULT_LD_WARN_EXECSTACK, + $ac_default_ld_warn_execstack, + [Define to 1 if you want to enable --warn-execstack in ELF linker by default.]) + +if test "${ac_default_ld_warn_rwx_segments}" = unset; then + ac_default_ld_warn_rwx_segments=1 +fi +AC_DEFINE_UNQUOTED(DEFAULT_LD_WARN_RWX_SEGMENTS, + $ac_default_ld_warn_rwx_segments, + [Define to 0 if you want to disable --warn-rwx-segments in ELF linker by default.]) + +if test "${ac_default_ld_default_execstack}" = unset; then + ac_default_ld_default_execstack=1 +fi +AC_DEFINE_UNQUOTED(DEFAULT_LD_EXECSTACK, + $ac_default_ld_default_execstack, + [Define to 0 if you want to disable the generation of an executable stack when a .note-GNU-stack section is missing.]) + + if test "${ac_support_error_handling_script}" = unset; then ac_support_error_handling_script=1 fi diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em index 7ae6f6d50e1..c027559908c 100644 --- a/ld/emultempl/elf.em +++ b/ld/emultempl/elf.em @@ -92,6 +92,9 @@ EOF fi fragment < 0 + fprintf (file, _("\ + --warn-execstack Generate a warning if the stack is executable (default)\n")); +#else fprintf (file, _("\ --warn-execstack Generate a warning if the stack is executable\n")); +#endif +#if DEFAULT_LD_WARN_EXECSTACK < 0 + fprintf (file, _("\ + --no-warn-execstack Do not generate a warning if the stack is executable (default)\n")); +#else fprintf (file, _("\ --no-warn-execstack Do not generate a warning if the stack is executable\n")); +#endif +#if DEFAULT_LD_WARN_RWX_SEGMENTS + fprintf (file, _("\ + --warn-rwx-segments Generate a warning if a LOAD segment has RWX permissions (default)\n")); + fprintf (file, _("\ + --no-warn-rwx-segments Do not generate a warning if a LOAD segments has RWX permissions\n")); +#else + fprintf (file, _("\ + --warn-rwx-segments Generate a warning if a LOAD segment has RWX permissions\n")); + fprintf (file, _("\ + --no-warn-rwx-segments Do not generate a warning if a LOAD segments has RWX permissions (default)\n")); +#endif fprintf (file, _("\ -z unique-symbol Avoid duplicated local symbol names\n")); fprintf (file, _("\ diff --git a/ld/testsuite/ld-elf/changelma.d b/ld/testsuite/ld-elf/changelma.d index 858a8db37ae..567e72d3301 100644 --- a/ld/testsuite/ld-elf/changelma.d +++ b/ld/testsuite/ld-elf/changelma.d @@ -1,5 +1,5 @@ #name: changelma (pr20659) -#ld: -T changelma.lnk +#ld: -T changelma.lnk --no-warn-rwx-segments #objcopy_linked_file: --change-section-lma .dynamic+0x80000000 #readelf: -l --wide #xfail: rx-*-* diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp index d56154011b3..1b300117ad1 100644 --- a/ld/testsuite/ld-elf/elf.exp +++ b/ld/testsuite/ld-elf/elf.exp @@ -182,6 +182,7 @@ if { [check_gc_sections_available] && ![istarget "v850-*-*"] } { proc target_defaults_to_execstack {} { if { [istarget "aarch64*-*-*"] + || [istarget "*-*-nacl"] || [istarget "arc*-*-*"] || [istarget "ia64*-*-*"] || [istarget "loongarch*-*-*"] @@ -226,7 +227,18 @@ if { [istarget *-*-*linux*] "" \ {pr23900-1.s} \ [list [list "readelf" {-Wl} $pr23900_1_exp]] \ - "pr23900-1.exe"] \ + "pr23900-1.exe"] \ + ] + + # Test the linker's generation of execstack and executable segment warnings. + # Since these are normally pruned from the linker's output we temporarily + # disable tha action here. + rename prune_warnings_extra old_prune_warnings_extra + proc prune_warnings_extra { text } { + return $text + } + + run_ld_link_tests [list \ [list "PR ld/29072 (warn about an executable .note.GNU-stack)" \ "-e 0" \ "" \ @@ -248,23 +260,39 @@ if { [istarget *-*-*linux*] {pr29072-a.s} \ {} \ "pr29072-d.exe"] \ - ] + [list "Ensure that a warning issued when creating a segment with RWX permissions" \ + "-e 0 -Tnobits-1.t --warn-rwx-segments" \ + "" \ + "" \ + {nobits-1.s} \ + {{ld rwx-segments-1.l}} \ + "rwx-segments-1.exe"] \ + [list "Ensure that a warning issued when creating a TLS segment with execute permission" \ + "-e 0 -T rwx-segments-2.t --warn-rwx-segments" \ + "" \ + "" \ + {size-2.s} \ + {{ld rwx-segments-2.l}} \ + "rwx-segments-2.exe"] \ + [list "Ensure that the warning can be suppressed" \ + "-e 0 -Tnobits-1.t --no-warn-rwx-segments" \ + "" \ + "" \ + {nobits-1.s} \ + {} \ + "rwx-segments-3.exe"] \ + ] + if { [target_defaults_to_execstack] } { - rename prune_warnings_extra old_prune_warnings_extra - proc prune_warnings_extra { text } { - return $text - } run_ld_link_tests [list \ [list "PR ld/29072 (warn about absent .note.GNU-stack)" \ - "-e 0 -z stack-size=0x123400" \ + "-e 0 -z stack-size=0x123400 --warn-execstack" \ "" \ "" \ {pr29072-b.s} \ {{ld pr29072.b.warn}} \ "pr29072-b.exe"] \ ] - rename prune_warnings_extra "" - rename old_prune_warnings_extra prune_warnings_extra } else { run_ld_link_tests [list \ [list "PR ld/29072 (ignore absent .note.GNU-stack)" \ @@ -276,6 +304,10 @@ if { [istarget *-*-*linux*] "pr29072-b.exe"] \ ] } + + # Restore the normal pruning behaviour. + rename prune_warnings_extra "" + rename old_prune_warnings_extra prune_warnings_extra } if [check_gc_sections_available] { diff --git a/ld/testsuite/ld-elf/flags1.d b/ld/testsuite/ld-elf/flags1.d index 6cd8b3f3832..d9034e25dc7 100644 --- a/ld/testsuite/ld-elf/flags1.d +++ b/ld/testsuite/ld-elf/flags1.d @@ -1,5 +1,5 @@ #name: --set-section-flags test 1 (sections) -#ld: -Tflags1.ld +#ld: -Tflags1.ld --no-warn-rwx-segments #objcopy_linked_file: --set-section-flags .post_text_reserve=contents,alloc,load,readonly,code #readelf: -S --wide diff --git a/ld/testsuite/ld-elf/maxpage5.d b/ld/testsuite/ld-elf/maxpage5.d index 9d9b57a853a..843a976111a 100644 --- a/ld/testsuite/ld-elf/maxpage5.d +++ b/ld/testsuite/ld-elf/maxpage5.d @@ -1,6 +1,6 @@ #source: maxpage5.s #as: --32 -#ld: -z max-page-size=0x200000 -T maxpage5.t +#ld: -z max-page-size=0x200000 -T maxpage5.t --no-warn-rwx-segments #objcopy_linked_file: -R .foo #readelf: -l --wide #target: x86_64-*-linux* i?86-*-linux-gnu i?86-*-gnu* diff --git a/ld/testsuite/ld-elf/note-2.d b/ld/testsuite/ld-elf/note-2.d index aff32406de2..ed81703dc2d 100644 --- a/ld/testsuite/ld-elf/note-2.d +++ b/ld/testsuite/ld-elf/note-2.d @@ -1,4 +1,4 @@ -#ld: -Tnote-2.t +#ld: -Tnote-2.t --no-warn-rwx-segments #objcopy_linked_file: -R .foo #readelf: -l --wide diff --git a/ld/testsuite/ld-elf/rwx-segments-1.l b/ld/testsuite/ld-elf/rwx-segments-1.l new file mode 100644 index 00000000000..432fcebd335 --- /dev/null +++ b/ld/testsuite/ld-elf/rwx-segments-1.l @@ -0,0 +1 @@ +.*warning: .* has a LOAD segment with RWX permissions diff --git a/ld/testsuite/ld-elf/rwx-segments-2.l b/ld/testsuite/ld-elf/rwx-segments-2.l new file mode 100644 index 00000000000..b830de60ea8 --- /dev/null +++ b/ld/testsuite/ld-elf/rwx-segments-2.l @@ -0,0 +1 @@ +.*: warning: .* has a TLS segment with execute permission diff --git a/ld/testsuite/ld-elf/rwx-segments-2.t b/ld/testsuite/ld-elf/rwx-segments-2.t new file mode 100644 index 00000000000..f3aef1d5d44 --- /dev/null +++ b/ld/testsuite/ld-elf/rwx-segments-2.t @@ -0,0 +1,20 @@ +PHDRS +{ + header PT_PHDR PHDRS ; + + image PT_LOAD FLAGS (5) PHDRS; + tls PT_TLS FLAGS (7); + +} +SECTIONS +{ + .text 0x100 : { *(.text) } :image + .tdata : { *(.tdata) } :image :tls + .tbss : { *(.tbss) } :image : tls + .map : { + LONG (SIZEOF (.text)) + LONG (SIZEOF (.tdata)) + LONG (SIZEOF (.tbss)) + } :image + /DISCARD/ : { *(*) } +} -- 2.30.2