diff -rupN binutils.orig/bfd/elf.c binutils-2.41/bfd/elf.c --- binutils.orig/bfd/elf.c 2023-10-19 12:11:46.526939794 +0100 +++ binutils-2.41/bfd/elf.c 2023-10-19 12:11:56.514949624 +0100 @@ -7013,6 +7013,9 @@ assign_file_positions_except_relocs (bfd { if (link_info != NULL && ! link_info->no_warn_rwx_segments) { + bool warned_tls = false; + bool warned_rwx = false; + /* 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. */ @@ -7025,16 +7028,47 @@ assign_file_positions_except_relocs (bfd 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 + if (! warned_tls + && phdr->p_type == PT_TLS + && (phdr->p_flags & PF_X)) + { + if (link_info->warn_is_error_for_rwx_segments) + { + _bfd_error_handler (_("\ +error: %pB has a TLS segment with execute permission"), + abfd); + return false; + } + + _bfd_error_handler (_("\ +warning: %pB has a TLS segment with execute permission"), + abfd); + if (warned_rwx) + break; + + warned_tls = true; + } + else if (! warned_rwx + && 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 (link_info->warn_is_error_for_rwx_segments) + { + _bfd_error_handler (_("\ +error: %pB has a LOAD segment with RWX permissions"), + abfd); + return false; + } + + _bfd_error_handler (_("\ +warning: %pB has a LOAD segment with RWX permissions"), + abfd); + if (warned_tls) + break; + + warned_rwx = true; + } } } diff -rupN binutils.orig/bfd/elflink.c binutils-2.41/bfd/elflink.c --- binutils.orig/bfd/elflink.c 2023-10-19 12:11:46.523939791 +0100 +++ binutils-2.41/bfd/elflink.c 2023-10-19 12:11:56.515949625 +0100 @@ -7149,9 +7149,20 @@ bfd_elf_size_dynamic_sections (bfd *outp /* If the user has explicitly requested warnings, then generate one even though the choice is the result of another command line option. */ if (info->warn_execstack == 1) - _bfd_error_handler - (_("\ + { + if (info->error_execstack) + { + _bfd_error_handler + (_("\ +error: creating an executable stack because of -z execstack command line option")); + return false; + } + + _bfd_error_handler + (_("\ warning: enabling an executable stack because of -z execstack command line option")); + } + elf_stack_flags (output_bfd) = PF_R | PF_W | PF_X; } else if (info->noexecstack) @@ -7207,11 +7218,29 @@ warning: enabling an executable stack be being enabled despite the fact that it was not requested on the command line. */ if (noteobj) - _bfd_error_handler (_("\ + { + if (info->error_execstack) + { + _bfd_error_handler (_("\ +error: %s: is triggering the generation of an executable stack (because it has an executable .note.GNU-stack section)"), + bfd_get_filename (noteobj)); + return false; + } + + _bfd_error_handler (_("\ warning: %s: requires executable stack (because the .note.GNU-stack section is executable)"), bfd_get_filename (noteobj)); + } else if (emptyobj) { + if (info->error_execstack) + { + _bfd_error_handler (_("\ +error: %s: is triggering the generation of an executable stack because it does not have a .note.GNU-stack section"), + bfd_get_filename (emptyobj)); + return false; + } + _bfd_error_handler (_("\ warning: %s: missing .note.GNU-stack section implies executable stack"), bfd_get_filename (emptyobj)); diff -rupN binutils.orig/include/bfdlink.h binutils-2.41/include/bfdlink.h --- binutils.orig/include/bfdlink.h 2023-10-19 12:11:47.238940495 +0100 +++ binutils-2.41/include/bfdlink.h 2023-10-19 12:11:56.515949625 +0100 @@ -484,26 +484,49 @@ struct bfd_link_info --dynamic-list command line options. */ unsigned int dynamic: 1; - /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W|PF_X - flags. */ + /* Set if the "-z execstack" option has been used to request that a + PT_GNU_STACK segment should be created with PF_R, PF_W and PF_X + flags set. + + Note - if performing a relocatable link then a .note.GNU-stack + section will be created instead, if one does not exist already. + The section will have the SHF_EXECINSTR flag bit set. */ unsigned int execstack: 1; - /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W - flags. */ + /* Set if the "-z noexecstack" option has been used to request that a + PT_GNU_STACK segment should be created with PF_R and PF_W flags. Or + a non-executable .note.GNU-stack section for relocateable links. + + Note - this flag is not quite orthogonal to execstack, since both + of these flags can be 0. In this case a stack segment can still + be created, but it will only have the PF_X flag bit set if one or + more of the input files contains a .note.GNU-stack section with the + SHF_EXECINSTR flag bit set, or if the default behaviour for the + architecture is to create executable stacks. + + The execstack and noexecstack flags should never both be 1. */ unsigned int noexecstack: 1; /* Tri-state variable: 0 => do not warn when creating an executable stack. - 1 => always warn when creating an executable stack. - >1 => warn when creating an executable stack if execstack is 0. */ + 1 => always warn when creating an executable stack (for any reason). + 2 => only warn when an executable stack has been requested an object + file and execstack is 0 or noexecstack is 1. + 3 => not used. */ unsigned int warn_execstack: 2; + /* TRUE if a warning generated because of warn_execstack should be instead + be treated as an error. */ + unsigned int error_execstack: 1; - /* TRUE if warnings should not be generated for TLS segments with eXecute + /* 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 user gave either --warn-rwx-segments or - --no-warn-rwx-segments. */ + --no-warn-rwx-segments on the linker command line. */ unsigned int user_warn_rwx_segments: 1; + /* TRUE if warnings generated when no_warn_rwx_segements is 0 should + instead be treated as errors. */ + unsigned int warn_is_error_for_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 diff -rupN binutils.orig/ld/NEWS binutils-2.41/ld/NEWS --- binutils.orig/ld/NEWS 2023-10-19 12:11:47.274940530 +0100 +++ binutils-2.41/ld/NEWS 2023-10-19 12:11:56.515949625 +0100 @@ -1,5 +1,14 @@ -*- text -*- +* Added --warn-execstack-objects to warn about executable stacks only when an + input object file requests one. Also added --error-execstack and + --error-rxw-segments options to convert warnings about executable stacks and + segments into errors. + + Also added --enable-error-execstack=[yes|no] and + --enable-error-rwx-segments=[yes|no] configure options to set the default for + converting warnings into errors. + Changes in 2.41: * The linker now accepts a command line option of --remap-inputs diff -rupN binutils.orig/ld/config.in binutils-2.41/ld/config.in --- binutils.orig/ld/config.in 2023-10-19 12:11:47.607940858 +0100 +++ binutils-2.41/ld/config.in 2023-10-19 12:11:56.515949625 +0100 @@ -19,6 +19,14 @@ /* Define if you want compressed debug sections by default. */ #undef DEFAULT_FLAG_COMPRESS_DEBUG +/* Define to 1 if you want to turn executable stack warnings into errors by + default. */ +#undef DEFAULT_LD_ERROR_EXECSTACK + +/* Define to 1 if you want to turn executable segment warnings into errors by + default. */ +#undef DEFAULT_LD_ERROR_RWX_SEGMENTS + /* 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 diff -rupN binutils.orig/ld/configure binutils-2.41/ld/configure --- binutils.orig/ld/configure 2023-10-19 12:11:47.607940858 +0100 +++ binutils-2.41/ld/configure 2023-10-19 12:11:56.516949626 +0100 @@ -848,7 +848,9 @@ enable_relro enable_textrel_check enable_separate_code enable_warn_execstack +enable_error_execstack enable_warn_rwx_segments +enable_error_rwx_segments enable_default_execstack enable_error_handling_script enable_default_hash_style @@ -15638,6 +15640,16 @@ esac fi +ac_default_ld_error_execstack=0 +# Check whether --enable-error-execstack was given. +if test "${enable_error_execstack+set}" = set; then : + enableval=$enable_error_execstack; case "${enableval}" in + yes) ac_default_ld_error_execstack=1 ;; + no) ac_default_ld_error_execstack=0 ;; +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 : @@ -15648,6 +15660,16 @@ esac fi +ac_default_ld_error_rwx_segments=0 +# Check whether --enable-error-rwx-segments was given. +if test "${enable_error_rwx_segments+set}" = set; then : + enableval=$enable_error_rwx_segments; case "${enableval}" in + yes) ac_default_ld_error_rwx_segments=1 ;; + no) ac_default_ld_error_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 : @@ -17442,6 +17464,12 @@ cat >>confdefs.h <<_ACEOF _ACEOF + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_LD_ERROR_EXECSTACK $ac_default_ld_error_execstack +_ACEOF + + if test "${ac_default_ld_warn_rwx_segments}" = unset; then ac_default_ld_warn_rwx_segments=1 fi @@ -17451,6 +17479,12 @@ cat >>confdefs.h <<_ACEOF _ACEOF + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_LD_ERROR_RWX_SEGMENTS $ac_default_ld_error_rwx_segments +_ACEOF + + if test "${ac_default_ld_default_execstack}" = unset; then ac_default_ld_default_execstack=1 fi diff -rupN binutils.orig/ld/configure.ac binutils-2.41/ld/configure.ac --- binutils.orig/ld/configure.ac 2023-10-19 12:11:47.607940858 +0100 +++ binutils-2.41/ld/configure.ac 2023-10-19 12:11:56.516949626 +0100 @@ -225,6 +225,15 @@ AC_ARG_ENABLE(warn-execstack, no) ac_default_ld_warn_execstack=0 ;; esac]) +ac_default_ld_error_execstack=0 +AC_ARG_ENABLE(error-execstack, + AS_HELP_STRING([--enable-error-execstack], + [turn executable stack warnings into errors]), +[case "${enableval}" in + yes) ac_default_ld_error_execstack=1 ;; + no) ac_default_ld_error_execstack=0 ;; +esac]) + ac_default_ld_warn_rwx_segments=unset AC_ARG_ENABLE(warn-rwx-segments, AS_HELP_STRING([--enable-warn-rwx-segments], @@ -234,6 +243,15 @@ AC_ARG_ENABLE(warn-rwx-segments, no) ac_default_ld_warn_rwx_segments=0 ;; esac]) +ac_default_ld_error_rwx_segments=0 +AC_ARG_ENABLE(error-rwx-segments, + AS_HELP_STRING([--enable-error-rwx-segments], + [turn executable segment warnings into errors]), +[case "${enableval}" in + yes) ac_default_ld_error_rwx_segments=1 ;; + no) ac_default_ld_error_rwx_segments=0 ;; +esac]) + ac_default_ld_default_execstack=unset AC_ARG_ENABLE(default-execstack, AS_HELP_STRING([--enable-default-execstack], @@ -568,6 +586,10 @@ AC_DEFINE_UNQUOTED(DEFAULT_LD_WARN_EXECS $ac_default_ld_warn_execstack, [Define to 1 if you want to enable --warn-execstack in ELF linker by default.]) +AC_DEFINE_UNQUOTED(DEFAULT_LD_ERROR_EXECSTACK, + $ac_default_ld_error_execstack, + [Define to 1 if you want to turn executable stack warnings into errors by default.]) + if test "${ac_default_ld_warn_rwx_segments}" = unset; then ac_default_ld_warn_rwx_segments=1 fi @@ -575,6 +597,10 @@ AC_DEFINE_UNQUOTED(DEFAULT_LD_WARN_RWX_S $ac_default_ld_warn_rwx_segments, [Define to 0 if you want to disable --warn-rwx-segments in ELF linker by default.]) +AC_DEFINE_UNQUOTED(DEFAULT_LD_ERROR_RWX_SEGMENTS, + $ac_default_ld_error_rwx_segments, + [Define to 1 if you want to turn executable segment warnings into errors by default.]) + if test "${ac_default_ld_default_execstack}" = unset; then ac_default_ld_default_execstack=1 fi diff -rupN binutils.orig/ld/emultempl/elf.em binutils-2.41/ld/emultempl/elf.em --- binutils.orig/ld/emultempl/elf.em 2023-10-19 12:11:47.286940542 +0100 +++ binutils-2.41/ld/emultempl/elf.em 2023-10-19 12:11:56.516949626 +0100 @@ -95,6 +95,8 @@ fragment <