[v2] gcc: Introduce -fhardened
Checks
Commit Message
On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> > <gcc-patches@gcc.gnu.org> wrote:
> > >
> > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > > and aarch64-unknown-linux-gnu; ok for trunk?
> > >
> > > -- >8 --
> > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > of hardening flags. The read of the room seems to be that the option
> > > would be useful. So here's a patch implementing that option.
> > >
> > > Currently, -fhardened enables:
> > >
> > > -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > > -D_GLIBCXX_ASSERTIONS
> > > -ftrivial-auto-var-init=pattern
> > > -fPIE -pie -Wl,-z,relro,-z,now
> > > -fstack-protector-strong
> > > -fstack-clash-protection
> > > -fcf-protection=full (x86 GNU/Linux only)
> > >
> > > -fhardened will not override options that were specified on the command line
> > > (before or after -fhardened). For example,
> > >
> > > -D_FORTIFY_SOURCE=1 -fhardened
> > >
> > > means that _FORTIFY_SOURCE=1 will be used. Similarly,
> > >
> > > -fhardened -fstack-protector
> > >
> > > will not enable -fstack-protector-strong.
> > >
> > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > to anything. I think we need a better way to show what it actually
> > > enables.
> >
> > I do think we need to find a solution here to solve asserting compliance.
>
> Fair enough.
>
> > Maybe we can have -Whardened that will diagnose any altering of
> > -fhardened by other options on the command-line or by missed target
> > implementations? People might for example use -fstack-protector
> > but don't really want to make protection lower than requested with -fhardened.
> >
> > Any such conflict is much less appearant than when you use the
> > flags -fhardened composes.
>
> How about: --help=hardened says which options -fhardened attempts to
> enable, and -Whardened warns when it didn't enable an option? E.g.,
>
> -fstack-protector -fhardened -Whardened
>
> would say that it didn't enable -fstack-protector-strong because
> -fstack-protector was specified on the command line?
>
> If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
> list -z now, likewise for -z relro.
>
> Unclear if -Whardened should be enabled by default, but probably yes?
Here's v2 which adds -Whardened (enabled by default).
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
I proposed -fhardened, a new umbrella option that enables a reasonable set
of hardening flags. The read of the room seems to be that the option
would be useful. So here's a patch implementing that option.
Currently, -fhardened enables:
-D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
-D_GLIBCXX_ASSERTIONS
-ftrivial-auto-var-init=pattern
-fPIE -pie -Wl,-z,relro,-z,now
-fstack-protector-strong
-fstack-clash-protection
-fcf-protection=full (x86 GNU/Linux only)
-fhardened will not override options that were specified on the command line
(before or after -fhardened). For example,
-D_FORTIFY_SOURCE=1 -fhardened
means that _FORTIFY_SOURCE=1 will be used. Similarly,
-fhardened -fstack-protector
will not enable -fstack-protector-strong.
In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
to anything. This patch provides -Whardened, enabled by default, which
warns when -fhardened couldn't enable a particular option. I think most
often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
were not enabled.
gcc/c-family/ChangeLog:
* c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
and _GLIBCXX_ASSERTIONS.
gcc/ChangeLog:
* common.opt (Whardened, fhardened): New options.
* config.in: Regenerate.
* config/bpf/bpf.cc: Include "opts.h".
(bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
not inform that -fstack-protector does not work.
* config/i386/i386-options.cc (ix86_option_override_internal): When
-fhardened, maybe enable -fcf-protection=full.
* configure: Regenerate.
* configure.ac: Check if the linker supports '-z now' and '-z relro'.
* doc/invoke.texi: Document -fhardened and -Whardened.
* gcc.cc (driver_handle_option): Remember if any link options or -static
were specified on the command line.
(process_command): When -fhardened, maybe enable -pie and
-Wl,-z,relro,-z,now.
* opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
(finish_options): When -fhardened, enable
-ftrivial-auto-var-init=pattern and -fstack-protector-strong.
(print_help_hardened): New.
(print_help): Call it.
* toplev.cc (process_options): When -fhardened, enable
-fstack-clash-protection. If flag_stack_protector_set_by_fhardened_p,
do not warn that -fstack-protector not supported for this target.
gcc/testsuite/ChangeLog:
* gcc.misc-tests/help.exp: Test -fhardened.
* c-c++-common/fhardened-1.S: New test.
* c-c++-common/fhardened-1.c: New test.
* c-c++-common/fhardened-10.c: New test.
* c-c++-common/fhardened-11.c: New test.
* c-c++-common/fhardened-12.c: New test.
* c-c++-common/fhardened-13.c: New test.
* c-c++-common/fhardened-14.c: New test.
* c-c++-common/fhardened-15.c: New test.
* c-c++-common/fhardened-2.c: New test.
* c-c++-common/fhardened-3.c: New test.
* c-c++-common/fhardened-4.c: New test.
* c-c++-common/fhardened-5.c: New test.
* c-c++-common/fhardened-6.c: New test.
* c-c++-common/fhardened-7.c: New test.
* c-c++-common/fhardened-8.c: New test.
* c-c++-common/fhardened-9.c: New test.
* gcc.target/i386/cf_check-6.c: New test.
---
gcc/c-family/c-opts.cc | 42 ++++++++++++++
gcc/common.opt | 8 +++
gcc/config.in | 12 ++++
gcc/config/bpf/bpf.cc | 8 ++-
gcc/config/i386/i386-options.cc | 17 +++++-
gcc/configure | 50 +++++++++++++++-
gcc/configure.ac | 42 +++++++++++++-
gcc/doc/invoke.texi | 44 +++++++++++++-
gcc/gcc.cc | 48 +++++++++++++++-
gcc/opts.cc | 67 +++++++++++++++++++++-
gcc/opts.h | 1 +
gcc/testsuite/c-c++-common/fhardened-1.S | 6 ++
gcc/testsuite/c-c++-common/fhardened-1.c | 14 +++++
gcc/testsuite/c-c++-common/fhardened-10.c | 12 ++++
gcc/testsuite/c-c++-common/fhardened-11.c | 10 ++++
gcc/testsuite/c-c++-common/fhardened-12.c | 11 ++++
gcc/testsuite/c-c++-common/fhardened-13.c | 6 ++
gcc/testsuite/c-c++-common/fhardened-14.c | 6 ++
gcc/testsuite/c-c++-common/fhardened-15.c | 5 ++
gcc/testsuite/c-c++-common/fhardened-2.c | 12 ++++
gcc/testsuite/c-c++-common/fhardened-3.c | 14 +++++
gcc/testsuite/c-c++-common/fhardened-4.c | 4 ++
gcc/testsuite/c-c++-common/fhardened-5.c | 11 ++++
gcc/testsuite/c-c++-common/fhardened-6.c | 12 ++++
gcc/testsuite/c-c++-common/fhardened-7.c | 7 +++
gcc/testsuite/c-c++-common/fhardened-8.c | 7 +++
gcc/testsuite/c-c++-common/fhardened-9.c | 9 +++
gcc/testsuite/gcc.misc-tests/help.exp | 2 +
gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
gcc/toplev.cc | 18 +++++-
30 files changed, 503 insertions(+), 14 deletions(-)
create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
Comments
Marek,
Sorry for the late comment (I was just back from a long vacation immediate after Cauldron).
One question:
Is the option “-fhandened” for production build or for development build?
If it’s for development build, then adding -ftrivial-auto-var-init=pattern is reasonable since the major purpose for -ftrivial-auto-var-init=pattern is for debugging, the runtime overhead of -ftrivial-auto-var-init=pattern is higher then -ftrivial-auto-var-init=zero.
However, if it’s for production build, then adding -ftrivial-auto-var-init=zero is better since the major purpose for -ftrivial-auto-var-init=zero is for production build to eliminate all uninitialization. And the runtime overhead of =zero is smaller than =pattern.
Qing
> On Oct 11, 2023, at 4:48 PM, Marek Polacek <polacek@redhat.com> wrote:
>
> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>> On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>>> On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>>> <gcc-patches@gcc.gnu.org> wrote:
>>>>
>>>> Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
>>>> and aarch64-unknown-linux-gnu; ok for trunk?
>>>>
>>>> -- >8 --
>>>> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
>>>> I proposed -fhardened, a new umbrella option that enables a reasonable set
>>>> of hardening flags. The read of the room seems to be that the option
>>>> would be useful. So here's a patch implementing that option.
>>>>
>>>> Currently, -fhardened enables:
>>>>
>>>> -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>>>> -D_GLIBCXX_ASSERTIONS
>>>> -ftrivial-auto-var-init=pattern
>>>> -fPIE -pie -Wl,-z,relro,-z,now
>>>> -fstack-protector-strong
>>>> -fstack-clash-protection
>>>> -fcf-protection=full (x86 GNU/Linux only)
>>>>
>>>> -fhardened will not override options that were specified on the command line
>>>> (before or after -fhardened). For example,
>>>>
>>>> -D_FORTIFY_SOURCE=1 -fhardened
>>>>
>>>> means that _FORTIFY_SOURCE=1 will be used. Similarly,
>>>>
>>>> -fhardened -fstack-protector
>>>>
>>>> will not enable -fstack-protector-strong.
>>>>
>>>> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
>>>> to anything. I think we need a better way to show what it actually
>>>> enables.
>>>
>>> I do think we need to find a solution here to solve asserting compliance.
>>
>> Fair enough.
>>
>>> Maybe we can have -Whardened that will diagnose any altering of
>>> -fhardened by other options on the command-line or by missed target
>>> implementations? People might for example use -fstack-protector
>>> but don't really want to make protection lower than requested with -fhardened.
>>>
>>> Any such conflict is much less appearant than when you use the
>>> flags -fhardened composes.
>>
>> How about: --help=hardened says which options -fhardened attempts to
>> enable, and -Whardened warns when it didn't enable an option? E.g.,
>>
>> -fstack-protector -fhardened -Whardened
>>
>> would say that it didn't enable -fstack-protector-strong because
>> -fstack-protector was specified on the command line?
>>
>> If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
>> list -z now, likewise for -z relro.
>>
>> Unclear if -Whardened should be enabled by default, but probably yes?
>
> Here's v2 which adds -Whardened (enabled by default).
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags. The read of the room seems to be that the option
> would be useful. So here's a patch implementing that option.
>
> Currently, -fhardened enables:
>
> -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> -D_GLIBCXX_ASSERTIONS
> -ftrivial-auto-var-init=pattern
> -fPIE -pie -Wl,-z,relro,-z,now
> -fstack-protector-strong
> -fstack-clash-protection
> -fcf-protection=full (x86 GNU/Linux only)
>
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened). For example,
>
> -D_FORTIFY_SOURCE=1 -fhardened
>
> means that _FORTIFY_SOURCE=1 will be used. Similarly,
>
> -fhardened -fstack-protector
>
> will not enable -fstack-protector-strong.
>
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything. This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option. I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
>
> gcc/c-family/ChangeLog:
>
> * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
> and _GLIBCXX_ASSERTIONS.
>
> gcc/ChangeLog:
>
> * common.opt (Whardened, fhardened): New options.
> * config.in: Regenerate.
> * config/bpf/bpf.cc: Include "opts.h".
> (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
> not inform that -fstack-protector does not work.
> * config/i386/i386-options.cc (ix86_option_override_internal): When
> -fhardened, maybe enable -fcf-protection=full.
> * configure: Regenerate.
> * configure.ac: Check if the linker supports '-z now' and '-z relro'.
> * doc/invoke.texi: Document -fhardened and -Whardened.
> * gcc.cc (driver_handle_option): Remember if any link options or -static
> were specified on the command line.
> (process_command): When -fhardened, maybe enable -pie and
> -Wl,-z,relro,-z,now.
> * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
> (finish_options): When -fhardened, enable
> -ftrivial-auto-var-init=pattern and -fstack-protector-strong.
> (print_help_hardened): New.
> (print_help): Call it.
> * toplev.cc (process_options): When -fhardened, enable
> -fstack-clash-protection. If flag_stack_protector_set_by_fhardened_p,
> do not warn that -fstack-protector not supported for this target.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.misc-tests/help.exp: Test -fhardened.
> * c-c++-common/fhardened-1.S: New test.
> * c-c++-common/fhardened-1.c: New test.
> * c-c++-common/fhardened-10.c: New test.
> * c-c++-common/fhardened-11.c: New test.
> * c-c++-common/fhardened-12.c: New test.
> * c-c++-common/fhardened-13.c: New test.
> * c-c++-common/fhardened-14.c: New test.
> * c-c++-common/fhardened-15.c: New test.
> * c-c++-common/fhardened-2.c: New test.
> * c-c++-common/fhardened-3.c: New test.
> * c-c++-common/fhardened-4.c: New test.
> * c-c++-common/fhardened-5.c: New test.
> * c-c++-common/fhardened-6.c: New test.
> * c-c++-common/fhardened-7.c: New test.
> * c-c++-common/fhardened-8.c: New test.
> * c-c++-common/fhardened-9.c: New test.
> * gcc.target/i386/cf_check-6.c: New test.
> ---
> gcc/c-family/c-opts.cc | 42 ++++++++++++++
> gcc/common.opt | 8 +++
> gcc/config.in | 12 ++++
> gcc/config/bpf/bpf.cc | 8 ++-
> gcc/config/i386/i386-options.cc | 17 +++++-
> gcc/configure | 50 +++++++++++++++-
> gcc/configure.ac | 42 +++++++++++++-
> gcc/doc/invoke.texi | 44 +++++++++++++-
> gcc/gcc.cc | 48 +++++++++++++++-
> gcc/opts.cc | 67 +++++++++++++++++++++-
> gcc/opts.h | 1 +
> gcc/testsuite/c-c++-common/fhardened-1.S | 6 ++
> gcc/testsuite/c-c++-common/fhardened-1.c | 14 +++++
> gcc/testsuite/c-c++-common/fhardened-10.c | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-11.c | 10 ++++
> gcc/testsuite/c-c++-common/fhardened-12.c | 11 ++++
> gcc/testsuite/c-c++-common/fhardened-13.c | 6 ++
> gcc/testsuite/c-c++-common/fhardened-14.c | 6 ++
> gcc/testsuite/c-c++-common/fhardened-15.c | 5 ++
> gcc/testsuite/c-c++-common/fhardened-2.c | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-3.c | 14 +++++
> gcc/testsuite/c-c++-common/fhardened-4.c | 4 ++
> gcc/testsuite/c-c++-common/fhardened-5.c | 11 ++++
> gcc/testsuite/c-c++-common/fhardened-6.c | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-7.c | 7 +++
> gcc/testsuite/c-c++-common/fhardened-8.c | 7 +++
> gcc/testsuite/c-c++-common/fhardened-9.c | 9 +++
> gcc/testsuite/gcc.misc-tests/help.exp | 2 +
> gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
> gcc/toplev.cc | 18 +++++-
> 30 files changed, 503 insertions(+), 14 deletions(-)
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
> create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index ce2e021e69d..f5f6ba24290 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1556,6 +1556,9 @@ c_finish_options (void)
> cb_file_change (parse_in, cmd_map);
> linemap_line_start (line_table, 0, 1);
>
> + bool fortify_seen_p = false;
> + bool cxx_assert_seen_p = false;
> +
> /* All command line defines must have the same location. */
> cpp_force_token_locations (parse_in, line_table->highest_line);
> for (size_t i = 0; i < deferred_count; i++)
> @@ -1573,6 +1576,45 @@ c_finish_options (void)
> else
> cpp_assert (parse_in, opt->arg);
> }
> +
> + if (UNLIKELY (flag_hardened)
> + && (opt->code == OPT_D || opt->code == OPT_U))
> + {
> + if (!fortify_seen_p)
> + fortify_seen_p
> + = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> + && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> + if (!cxx_assert_seen_p)
> + cxx_assert_seen_p
> + = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> + && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> + }
> + }
> +
> + if (flag_hardened)
> + {
> + if (!fortify_seen_p && optimize > 0)
> + {
> + if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> + cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> + else
> + cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> + }
> + else if (optimize == 0)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> + "because optimizations are turned off");
> + else
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> + "because it was specified in %<-D%> or %<-U%>");
> + if (!cxx_assert_seen_p)
> + cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
> + else
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
> + "%<-fhardened%> because it was specified in %<-D%> "
> + "or %<-U%>");
> }
>
> cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index f137a1f81ac..60c13b9ffd2 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -634,6 +634,10 @@ Wfree-nonheap-object
> Common Var(warn_free_nonheap_object) Init(1) Warning
> Warn when attempting to free a non-heap object.
>
> +Whardened
> +Common Var(warn_hardened) Init(1) Warning
> +Warn when -fhardened did not enable an option from its set.
> +
> Whsa
> Common Ignore Warning
> Does nothing. Preserved for backward compatibility.
> @@ -1827,6 +1831,10 @@ fharden-conditional-branches
> Common Var(flag_harden_conditional_branches) Optimization
> Harden conditional branches by checking reversed conditions.
>
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
> ; Nonzero means ignore `#ident' directives. 0 means handle them.
> ; Generate position-independent code for executables if possible
> ; On SVR4 targets, it also controls whether or not to emit a
> diff --git a/gcc/config.in b/gcc/config.in
> index d04718ad128..faa941c1385 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1676,6 +1676,12 @@
> #endif
>
>
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
> /* Define if your PowerPC64 linker only needs function descriptor syms. */
> #ifndef USED_FOR_TARGET
> #undef HAVE_LD_NO_DOT_SYMS
> @@ -1719,6 +1725,12 @@
> #endif
>
>
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
> /* Define if your linker links a mix of read-only and read-write sections into
> a read-write section. */
> #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 437bd652de3..41dc7fd3dae 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3. If not see
> #include "gimplify-me.h"
>
> #include "core-builtins.h"
> +#include "opts.h"
>
> /* Per-function machine data. */
> struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
> /* Disable -fstack-protector as it is not supported in BPF. */
> if (flag_stack_protect)
> {
> - inform (input_location,
> - "%<-fstack-protector%> does not work "
> - "on this architecture");
> + if (!flag_stack_protector_set_by_fhardened_p)
> + inform (input_location,
> + "%<-fstack-protector%> does not work "
> + "on this architecture");
> flag_stack_protect = 0;
> }
>
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index 06af373ca57..22ede9e15b5 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
> = build_target_option_node (opts, opts_set);
> }
>
> + const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> + /* When -fhardened, enable -fcf-protection=full, but only when it's
> + compatible with this target, and when it wasn't already specified
> + on the command line. */
> + if (opts->x_flag_hardened && cf_okay_p)
> + {
> + if (opts->x_flag_cf_protection == CF_NONE)
> + opts->x_flag_cf_protection = CF_FULL;
> + else if (opts->x_flag_cf_protection != CF_FULL)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<-fcf-protection=full%> is not enabled by "
> + "%<-fhardened%> because it was specified on the command "
> + "line");
> + }
> +
> if (opts->x_flag_cf_protection != CF_NONE)
> {
> if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> - && !TARGET_64BIT && !TARGET_CMOV)
> + && !cf_okay_p)
> error ("%<-fcf-protection%> is not compatible with this target");
>
> opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index c43bde8174b..e2aac56edf6 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
> ld_bndplt_support=yes
> fi
> elif test x$gcc_cv_ld != x; then
> - # Check if linker supports -a bndplt option
> + # Check if linker supports -z bndplt option
> if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
> ld_bndplt_support=yes
> fi
> @@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
> ;;
> esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> + ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_now_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z now
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> + ld_now_support=yes
> + fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> + ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_relro_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z relro
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> + ld_relro_support=yes
> + fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
> # Configure the subdirectories
> # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index fb8e32f8ee5..6a090ccf3bd 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
> ld_bndplt_support=yes
> fi
> elif test x$gcc_cv_ld != x; then
> - # Check if linker supports -a bndplt option
> + # Check if linker supports -z bndplt option
> if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
> ld_bndplt_support=yes
> fi
> @@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
> ;;
> esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> + ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_now_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z now
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> + ld_now_support=yes
> + fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> + [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> + [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> + ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_relro_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z relro
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> + ld_relro_support=yes
> + fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> + [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> + [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
> # Configure the subdirectories
> # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 7c5f81d9783..48e6a3f433c 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
> -Wformat-y2k -Wframe-address
> -Wframe-larger-than=@var{byte-size} -Wno-free-nonheap-object
> -Wno-if-not-aligned -Wno-ignored-attributes
> --Wignored-qualifiers -Wno-incompatible-pointer-types
> +-Wignored-qualifiers -Wno-incompatible-pointer-types -Whardened
> -Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n}
> -Wno-implicit-function-declaration -Wno-implicit-int
> -Winfinite-recursion
> @@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
> -fasan-shadow-offset=@var{number} -fsanitize-sections=@var{s1},@var{s2},...
> -fsanitize-undefined-trap-on-error -fbounds-check
> -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches -fhardened
> -fstack-protector -fstack-protector-all -fstack-protector-strong
> -fstack-protector-explicit -fstack-check
> -fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym}
> @@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
> Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
> This warning is enabled by @option{-Wall}.
>
> +@opindex Whardened
> +@opindex Wno-hardened
> +@item -Whardened
> +Warn when @option{-fhardened} did not enable an option from its set (for
> +which see @option{-fhardened}). For instance, using @option{-fhardened}
> +and @option{-fstack-protector} at the same time on the command line causes
> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
> +not enabled by @option{-fhardened}.
> +
> +This warning is enabled by default and has effect only when @option{-fhardened}
> +is enabled.
> +
> @opindex Wimplicit-fallthrough
> @opindex Wno-implicit-fallthrough
> @item -Wimplicit-fallthrough
> @@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
> unexpected. Use with @samp{-fharden-compares} to cover all
> conditionals.
>
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI. The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@c Keep this in sync with print_help_hardened!
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=pattern
> +-fPIE -pie -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line. For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
> @opindex fstack-protector
> @item -fstack-protector
> Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index c6e600fa0d3..ed4e2400e91 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
> driver added to dumpdir after dumpbase or linker output name. */
> static bool dumpdir_trailing_dash_added = false;
>
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> + line. */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line. */
> +static bool static_p;
> +
> /* Basename of dump and aux outputs, computed from dumpbase (given or
> derived from output name), to override input_basename in non-%w %b
> et al. */
> @@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
> save_switch ("-o", 1, &arg, validated, true);
> return true;
>
> -#ifdef ENABLE_DEFAULT_PIE
> case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
> /* -pie is turned on by default. */
> + validated = true;
> #endif
> + case OPT_r:
> + case OPT_shared:
> + case OPT_no_pie:
> + any_link_options_p = true;
> + break;
> +
> + case OPT_static:
> + static_p = true;
> + break;
>
> case OPT_static_libgcc:
> case OPT_shared_libgcc:
> @@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
> #endif
> }
>
> + /* TODO: check if -static -pie works and maybe use it. */
> + if (flag_hardened)
> + {
> + if (!any_link_options_p && !static_p)
> + {
> +#ifdef HAVE_LD_PIE
> + save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> + /* These are passed straight down to collect2 so we have to break
> + it up like this. */
> + if (HAVE_LD_NOW_SUPPORT)
> + {
> + add_infile ("-z", "*");
> + add_infile ("now", "*");
> + }
> + if (HAVE_LD_RELRO_SUPPORT)
> + {
> + add_infile ("-z", "*");
> + add_infile ("relro", "*");
> + }
> + }
> + /* We can't use OPT_Whardened yet. Sigh. */
> + else if (warn_hardened)
> + warning_at (UNKNOWN_LOCATION, 0,
> + "linker hardening options not enabled by %<-fhardened%> "
> + "because other link options were specified on the command "
> + "line");
> + }
> +
> /* Handle -gtoggle as it would later in toplev.cc:process_options to
> make the debug-level-gt spec function work as expected. */
> if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 573dcf8e497..8265c5b3c1b 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3. If not see
> /* Set by -fcanon-prefix-map. */
> bool flag_canon_prefix_map;
>
> +/* Set by finish_options when flag_stack_protector was set only because of
> + -fhardened. Yuck. */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
> static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>
> /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> opts->x_flag_section_anchors = 0;
> }
>
> + if (opts->x_flag_hardened)
> + {
> + if (!opts_set->x_flag_auto_var_init)
> + opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
> + else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
> + warning_at (loc, OPT_Whardened,
> + "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
> + "%<-fhardened%> because it was specified on the command "
> + "line");
> + }
> +
> if (!opts->x_flag_opts_finished)
> {
> /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> /* We initialize opts->x_flag_pic to -1 so that we can tell if
> -fpic, -fPIC, -fno-pic or -fno-PIC is used. */
> if (opts->x_flag_pic == -1)
> - opts->x_flag_pie = DEFAULT_FLAG_PIE;
> + opts->x_flag_pie = (opts->x_flag_hardened
> + ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
> else
> opts->x_flag_pie = 0;
> }
> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> }
>
> /* We initialize opts->x_flag_stack_protect to -1 so that targets
> - can set a default value. */
> + can set a default value. With --enable-default-ssp or -fhardened
> + the default is -fstack-protector-strong. */
> if (opts->x_flag_stack_protect == -1)
> - opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> + {
> + /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> + defined in such a way that it uses flag_stack_protect which can't
> + be used here. Moreover, some targets like BPF don't support
> + -fstack-protector at all but we don't know that here. So remember
> + that flag_stack_protect was set at the behest of -fhardened. */
> + if (opts->x_flag_hardened)
> + {
> + opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> + flag_stack_protector_set_by_fhardened_p = true;
> + }
> + else
> + opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> + }
> + else if (opts->x_flag_hardened
> + && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<-fstack-protector-strong%> is not enabled by "
> + "%<-fhardened%> because it was specified on the command "
> + "line");
>
> if (opts->x_optimize == 0)
> {
> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
> free (patch_area_arg);
> }
>
> +/* Print options enabled by -fhardened. Keep this in sync with the manual! */
> +
> +static void
> +print_help_hardened ()
> +{
> + printf ("%s\n", "The following options are enabled by -fhardened:");
> + printf (" %s=%d\n", "-D_FORTIFY_SOURCE",
> + (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> + printf (" %s\n", "-D_GLIBCXX_ASSERTIONS");
> + printf (" %s\n", "-ftrivial-auto-var-init=pattern");
> +#ifdef HAVE_LD_PIE
> + printf (" %s %s\n", "-fPIE", "-pie");
> +#endif
> + if (HAVE_LD_NOW_SUPPORT)
> + printf (" %s\n", "-Wl,-z,now");
> + if (HAVE_LD_RELRO_SUPPORT)
> + printf (" %s\n", "-Wl,-z,relro");
> + printf (" %s\n", "-fstack-protector-strong");
> + printf (" %s\n", "-fstack-clash-protection");
> + printf (" %s\n", "-fcf-protection=full");
> + putchar ('\n');
> +}
> +
> /* Print help when OPT__help_ is set. */
>
> void
> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
> }
> else if (lang_flag != 0)
> *pflags |= lang_flag;
> + else if (strncasecmp (a, "hardened", len) == 0)
> + print_help_hardened ();
> else
> warning (0,
> "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
> /* Hold command-line options associated with stack limitation. */
> extern const char *opt_fstack_limit_symbol_arg;
> extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
>
> /* Input file names. */
>
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..4dd22cdfe45
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..dd3cde93805
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..8242530bc4d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..b8fd65a960c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> + int i;
> + return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..6945a6391a9
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..652ece3d4c4
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
> new file mode 100644
> index 00000000000..c6202754bf5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile } */
> +/* { dg-require-stack-check "specific" } */
> +/* { dg-options "-fhardened -O -fstack-check" } */
> +
> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..283867ca806
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> +
> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..6924ba242f0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers. */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man. */
> +
> +int
> +main ()
> +{
> +}
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
> new file mode 100644
> index 00000000000..7d44d299f19
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
> +
> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> + int i;
> + return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..a757cbf0d12
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> + int i;
> + return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> +/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..32f35eb2595
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..5b3162b4d1f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..d3b9e79b9b6
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
> # Listing only excludes gives empty results.
> check_for_options c "--help=^joined,^separate" "" "" ""
>
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
> if [ info exists prev_columns ] {
> # Reset the enviroment variable to its oriuginal value.
> set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET. */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> + bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index 8af9bf5090e..743a3a91684 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1575,6 +1575,19 @@ process_options (bool no_backend)
> "where the stack grows from lower to higher addresses");
> flag_stack_clash_protection = 0;
> }
> + else if (flag_hardened)
> + {
> + if (!flag_stack_clash_protection
> + /* Don't enable -fstack-clash-protection when -fstack-check=
> + is used: it would result in confusing errors. */
> + && flag_stack_check == NO_STACK_CHECK)
> + flag_stack_clash_protection = 1;
> + else if (flag_stack_check != NO_STACK_CHECK)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<-fstack-clash-protection%> is not enabled by "
> + "%<-fhardened%> because %<-fstack-check%> was "
> + "specified on the command line");
> + }
>
> /* We cannot support -fstack-check= and -fstack-clash-protection at
> the same time. */
> @@ -1590,8 +1603,9 @@ process_options (bool no_backend)
> target already uses a soft frame pointer, the transition is trivial. */
> if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
> {
> - warning_at (UNKNOWN_LOCATION, 0,
> - "%<-fstack-protector%> not supported for this target");
> + if (!flag_stack_protector_set_by_fhardened_p)
> + warning_at (UNKNOWN_LOCATION, 0,
> + "%<-fstack-protector%> not supported for this target");
> flag_stack_protect = 0;
> }
> if (!flag_stack_protect)
>
> base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
> --
> 2.41.0
>
On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>
> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> > > <gcc-patches@gcc.gnu.org> wrote:
> > > >
> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> > > > and aarch64-unknown-linux-gnu; ok for trunk?
> > > >
> > > > -- >8 --
> > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> > > > of hardening flags. The read of the room seems to be that the option
> > > > would be useful. So here's a patch implementing that option.
> > > >
> > > > Currently, -fhardened enables:
> > > >
> > > > -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > > > -D_GLIBCXX_ASSERTIONS
> > > > -ftrivial-auto-var-init=pattern
I think =zero is much better here given the overhead is way
cheaper and pointers get a more reliable behavior.
> > > > -fPIE -pie -Wl,-z,relro,-z,now
> > > > -fstack-protector-strong
> > > > -fstack-clash-protection
> > > > -fcf-protection=full (x86 GNU/Linux only)
> > > >
> > > > -fhardened will not override options that were specified on the command line
> > > > (before or after -fhardened). For example,
> > > >
> > > > -D_FORTIFY_SOURCE=1 -fhardened
> > > >
> > > > means that _FORTIFY_SOURCE=1 will be used. Similarly,
> > > >
> > > > -fhardened -fstack-protector
> > > >
> > > > will not enable -fstack-protector-strong.
> > > >
> > > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> > > > to anything. I think we need a better way to show what it actually
> > > > enables.
> > >
> > > I do think we need to find a solution here to solve asserting compliance.
> >
> > Fair enough.
> >
> > > Maybe we can have -Whardened that will diagnose any altering of
> > > -fhardened by other options on the command-line or by missed target
> > > implementations? People might for example use -fstack-protector
> > > but don't really want to make protection lower than requested with -fhardened.
> > >
> > > Any such conflict is much less appearant than when you use the
> > > flags -fhardened composes.
> >
> > How about: --help=hardened says which options -fhardened attempts to
> > enable, and -Whardened warns when it didn't enable an option? E.g.,
> >
> > -fstack-protector -fhardened -Whardened
> >
> > would say that it didn't enable -fstack-protector-strong because
> > -fstack-protector was specified on the command line?
> >
> > If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
> > list -z now, likewise for -z relro.
> >
> > Unclear if -Whardened should be enabled by default, but probably yes?
>
> Here's v2 which adds -Whardened (enabled by default).
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
I think it's OK but I'd like to see a second ACK here. Can you see how our
primary and secondary targets (+ host OS) behave here? I think the
documentation should elaborate a bit on expectations for non-Linux/GNU
targets, specifically I think the default configuration for a target should
with -fhardened _not_ have any -Whardened diagnostics. Maybe we can
have a testcase for this?
Thanks,
Richard.
>
> -- >8 --
> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> I proposed -fhardened, a new umbrella option that enables a reasonable set
> of hardening flags. The read of the room seems to be that the option
> would be useful. So here's a patch implementing that option.
>
> Currently, -fhardened enables:
>
> -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> -D_GLIBCXX_ASSERTIONS
> -ftrivial-auto-var-init=pattern
> -fPIE -pie -Wl,-z,relro,-z,now
> -fstack-protector-strong
> -fstack-clash-protection
> -fcf-protection=full (x86 GNU/Linux only)
>
> -fhardened will not override options that were specified on the command line
> (before or after -fhardened). For example,
>
> -D_FORTIFY_SOURCE=1 -fhardened
>
> means that _FORTIFY_SOURCE=1 will be used. Similarly,
>
> -fhardened -fstack-protector
>
> will not enable -fstack-protector-strong.
>
> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
> to anything. This patch provides -Whardened, enabled by default, which
> warns when -fhardened couldn't enable a particular option. I think most
> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
> were not enabled.
>
> gcc/c-family/ChangeLog:
>
> * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
> and _GLIBCXX_ASSERTIONS.
>
> gcc/ChangeLog:
>
> * common.opt (Whardened, fhardened): New options.
> * config.in: Regenerate.
> * config/bpf/bpf.cc: Include "opts.h".
> (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
> not inform that -fstack-protector does not work.
> * config/i386/i386-options.cc (ix86_option_override_internal): When
> -fhardened, maybe enable -fcf-protection=full.
> * configure: Regenerate.
> * configure.ac: Check if the linker supports '-z now' and '-z relro'.
> * doc/invoke.texi: Document -fhardened and -Whardened.
> * gcc.cc (driver_handle_option): Remember if any link options or -static
> were specified on the command line.
> (process_command): When -fhardened, maybe enable -pie and
> -Wl,-z,relro,-z,now.
> * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
> (finish_options): When -fhardened, enable
> -ftrivial-auto-var-init=pattern and -fstack-protector-strong.
> (print_help_hardened): New.
> (print_help): Call it.
> * toplev.cc (process_options): When -fhardened, enable
> -fstack-clash-protection. If flag_stack_protector_set_by_fhardened_p,
> do not warn that -fstack-protector not supported for this target.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.misc-tests/help.exp: Test -fhardened.
> * c-c++-common/fhardened-1.S: New test.
> * c-c++-common/fhardened-1.c: New test.
> * c-c++-common/fhardened-10.c: New test.
> * c-c++-common/fhardened-11.c: New test.
> * c-c++-common/fhardened-12.c: New test.
> * c-c++-common/fhardened-13.c: New test.
> * c-c++-common/fhardened-14.c: New test.
> * c-c++-common/fhardened-15.c: New test.
> * c-c++-common/fhardened-2.c: New test.
> * c-c++-common/fhardened-3.c: New test.
> * c-c++-common/fhardened-4.c: New test.
> * c-c++-common/fhardened-5.c: New test.
> * c-c++-common/fhardened-6.c: New test.
> * c-c++-common/fhardened-7.c: New test.
> * c-c++-common/fhardened-8.c: New test.
> * c-c++-common/fhardened-9.c: New test.
> * gcc.target/i386/cf_check-6.c: New test.
> ---
> gcc/c-family/c-opts.cc | 42 ++++++++++++++
> gcc/common.opt | 8 +++
> gcc/config.in | 12 ++++
> gcc/config/bpf/bpf.cc | 8 ++-
> gcc/config/i386/i386-options.cc | 17 +++++-
> gcc/configure | 50 +++++++++++++++-
> gcc/configure.ac | 42 +++++++++++++-
> gcc/doc/invoke.texi | 44 +++++++++++++-
> gcc/gcc.cc | 48 +++++++++++++++-
> gcc/opts.cc | 67 +++++++++++++++++++++-
> gcc/opts.h | 1 +
> gcc/testsuite/c-c++-common/fhardened-1.S | 6 ++
> gcc/testsuite/c-c++-common/fhardened-1.c | 14 +++++
> gcc/testsuite/c-c++-common/fhardened-10.c | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-11.c | 10 ++++
> gcc/testsuite/c-c++-common/fhardened-12.c | 11 ++++
> gcc/testsuite/c-c++-common/fhardened-13.c | 6 ++
> gcc/testsuite/c-c++-common/fhardened-14.c | 6 ++
> gcc/testsuite/c-c++-common/fhardened-15.c | 5 ++
> gcc/testsuite/c-c++-common/fhardened-2.c | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-3.c | 14 +++++
> gcc/testsuite/c-c++-common/fhardened-4.c | 4 ++
> gcc/testsuite/c-c++-common/fhardened-5.c | 11 ++++
> gcc/testsuite/c-c++-common/fhardened-6.c | 12 ++++
> gcc/testsuite/c-c++-common/fhardened-7.c | 7 +++
> gcc/testsuite/c-c++-common/fhardened-8.c | 7 +++
> gcc/testsuite/c-c++-common/fhardened-9.c | 9 +++
> gcc/testsuite/gcc.misc-tests/help.exp | 2 +
> gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
> gcc/toplev.cc | 18 +++++-
> 30 files changed, 503 insertions(+), 14 deletions(-)
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
> create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
> create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>
> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
> index ce2e021e69d..f5f6ba24290 100644
> --- a/gcc/c-family/c-opts.cc
> +++ b/gcc/c-family/c-opts.cc
> @@ -1556,6 +1556,9 @@ c_finish_options (void)
> cb_file_change (parse_in, cmd_map);
> linemap_line_start (line_table, 0, 1);
>
> + bool fortify_seen_p = false;
> + bool cxx_assert_seen_p = false;
> +
> /* All command line defines must have the same location. */
> cpp_force_token_locations (parse_in, line_table->highest_line);
> for (size_t i = 0; i < deferred_count; i++)
> @@ -1573,6 +1576,45 @@ c_finish_options (void)
> else
> cpp_assert (parse_in, opt->arg);
> }
> +
> + if (UNLIKELY (flag_hardened)
> + && (opt->code == OPT_D || opt->code == OPT_U))
> + {
> + if (!fortify_seen_p)
> + fortify_seen_p
> + = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
> + && (opt->arg[15] == '\0' || opt->arg[15] == '='));
> + if (!cxx_assert_seen_p)
> + cxx_assert_seen_p
> + = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
> + && (opt->arg[19] == '\0' || opt->arg[19] == '='));
> + }
> + }
> +
> + if (flag_hardened)
> + {
> + if (!fortify_seen_p && optimize > 0)
> + {
> + if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
> + cpp_define (parse_in, "_FORTIFY_SOURCE=3");
> + else
> + cpp_define (parse_in, "_FORTIFY_SOURCE=2");
> + }
> + else if (optimize == 0)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> + "because optimizations are turned off");
> + else
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
> + "because it was specified in %<-D%> or %<-U%>");
> + if (!cxx_assert_seen_p)
> + cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
> + else
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
> + "%<-fhardened%> because it was specified in %<-D%> "
> + "or %<-U%>");
> }
>
> cpp_stop_forcing_token_locations (parse_in);
> diff --git a/gcc/common.opt b/gcc/common.opt
> index f137a1f81ac..60c13b9ffd2 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -634,6 +634,10 @@ Wfree-nonheap-object
> Common Var(warn_free_nonheap_object) Init(1) Warning
> Warn when attempting to free a non-heap object.
>
> +Whardened
> +Common Var(warn_hardened) Init(1) Warning
> +Warn when -fhardened did not enable an option from its set.
> +
> Whsa
> Common Ignore Warning
> Does nothing. Preserved for backward compatibility.
> @@ -1827,6 +1831,10 @@ fharden-conditional-branches
> Common Var(flag_harden_conditional_branches) Optimization
> Harden conditional branches by checking reversed conditions.
>
> +fhardened
> +Common Driver Var(flag_hardened)
> +Enable various security-relevant flags.
> +
> ; Nonzero means ignore `#ident' directives. 0 means handle them.
> ; Generate position-independent code for executables if possible
> ; On SVR4 targets, it also controls whether or not to emit a
> diff --git a/gcc/config.in b/gcc/config.in
> index d04718ad128..faa941c1385 100644
> --- a/gcc/config.in
> +++ b/gcc/config.in
> @@ -1676,6 +1676,12 @@
> #endif
>
>
> +/* Define 0/1 if your linker supports -z now */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_NOW_SUPPORT
> +#endif
> +
> +
> /* Define if your PowerPC64 linker only needs function descriptor syms. */
> #ifndef USED_FOR_TARGET
> #undef HAVE_LD_NO_DOT_SYMS
> @@ -1719,6 +1725,12 @@
> #endif
>
>
> +/* Define 0/1 if your linker supports -z relro */
> +#ifndef USED_FOR_TARGET
> +#undef HAVE_LD_RELRO_SUPPORT
> +#endif
> +
> +
> /* Define if your linker links a mix of read-only and read-write sections into
> a read-write section. */
> #ifndef USED_FOR_TARGET
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 437bd652de3..41dc7fd3dae 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3. If not see
> #include "gimplify-me.h"
>
> #include "core-builtins.h"
> +#include "opts.h"
>
> /* Per-function machine data. */
> struct GTY(()) machine_function
> @@ -250,9 +251,10 @@ bpf_option_override (void)
> /* Disable -fstack-protector as it is not supported in BPF. */
> if (flag_stack_protect)
> {
> - inform (input_location,
> - "%<-fstack-protector%> does not work "
> - "on this architecture");
> + if (!flag_stack_protector_set_by_fhardened_p)
> + inform (input_location,
> + "%<-fstack-protector%> does not work "
> + "on this architecture");
> flag_stack_protect = 0;
> }
>
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index 06af373ca57..22ede9e15b5 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
> = build_target_option_node (opts, opts_set);
> }
>
> + const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
> + /* When -fhardened, enable -fcf-protection=full, but only when it's
> + compatible with this target, and when it wasn't already specified
> + on the command line. */
> + if (opts->x_flag_hardened && cf_okay_p)
> + {
> + if (opts->x_flag_cf_protection == CF_NONE)
> + opts->x_flag_cf_protection = CF_FULL;
> + else if (opts->x_flag_cf_protection != CF_FULL)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<-fcf-protection=full%> is not enabled by "
> + "%<-fhardened%> because it was specified on the command "
> + "line");
> + }
> +
> if (opts->x_flag_cf_protection != CF_NONE)
> {
> if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
> - && !TARGET_64BIT && !TARGET_CMOV)
> + && !cf_okay_p)
> error ("%<-fcf-protection%> is not compatible with this target");
>
> opts->x_flag_cf_protection
> diff --git a/gcc/configure b/gcc/configure
> index c43bde8174b..e2aac56edf6 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
> ld_bndplt_support=yes
> fi
> elif test x$gcc_cv_ld != x; then
> - # Check if linker supports -a bndplt option
> + # Check if linker supports -z bndplt option
> if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
> ld_bndplt_support=yes
> fi
> @@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
> ;;
> esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
> +$as_echo_n "checking linker -z now option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> + ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_now_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z now
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> + ld_now_support=yes
> + fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
> +$as_echo "$ld_now_support" >&6; }
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
> +$as_echo_n "checking linker -z relro option... " >&6; }
> +if test x"$ld_is_gold" = xyes; then
> + ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_relro_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z relro
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> + ld_relro_support=yes
> + fi
> +fi
> +
> +cat >>confdefs.h <<_ACEOF
> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
> +_ACEOF
> +
> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
> +$as_echo "$ld_relro_support" >&6; }
> +
> # Configure the subdirectories
> # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index fb8e32f8ee5..6a090ccf3bd 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
> ld_bndplt_support=yes
> fi
> elif test x$gcc_cv_ld != x; then
> - # Check if linker supports -a bndplt option
> + # Check if linker supports -z bndplt option
> if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
> ld_bndplt_support=yes
> fi
> @@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
> ;;
> esac
>
> +# Check if the linker supports '-z now'
> +ld_now_support=no
> +AC_MSG_CHECKING(linker -z now option)
> +if test x"$ld_is_gold" = xyes; then
> + ld_now_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_now_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z now
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
> + ld_now_support=yes
> + fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
> + [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
> + [Define 0/1 if your linker supports -z now])
> +AC_MSG_RESULT($ld_now_support)
> +
> +# Check if the linker supports '-z relro'
> +ld_relro_support=no
> +AC_MSG_CHECKING(linker -z relro option)
> +if test x"$ld_is_gold" = xyes; then
> + ld_relro_support=yes
> +elif test $in_tree_ld = yes ; then
> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
> + ld_relro_support=yes
> + fi
> +elif test x$gcc_cv_ld != x; then
> + # Check if linker supports -z relro
> + if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
> + ld_relro_support=yes
> + fi
> +fi
> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
> + [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
> + [Define 0/1 if your linker supports -z relro])
> +AC_MSG_RESULT($ld_relro_support)
> +
> # Configure the subdirectories
> # AC_CONFIG_SUBDIRS($subdirs)
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 7c5f81d9783..48e6a3f433c 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
> -Wformat-y2k -Wframe-address
> -Wframe-larger-than=@var{byte-size} -Wno-free-nonheap-object
> -Wno-if-not-aligned -Wno-ignored-attributes
> --Wignored-qualifiers -Wno-incompatible-pointer-types
> +-Wignored-qualifiers -Wno-incompatible-pointer-types -Whardened
> -Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n}
> -Wno-implicit-function-declaration -Wno-implicit-int
> -Winfinite-recursion
> @@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
> -fasan-shadow-offset=@var{number} -fsanitize-sections=@var{s1},@var{s2},...
> -fsanitize-undefined-trap-on-error -fbounds-check
> -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
> --fharden-compares -fharden-conditional-branches
> +-fharden-compares -fharden-conditional-branches -fhardened
> -fstack-protector -fstack-protector-all -fstack-protector-strong
> -fstack-protector-explicit -fstack-check
> -fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym}
> @@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
> Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
> This warning is enabled by @option{-Wall}.
>
> +@opindex Whardened
> +@opindex Wno-hardened
> +@item -Whardened
> +Warn when @option{-fhardened} did not enable an option from its set (for
> +which see @option{-fhardened}). For instance, using @option{-fhardened}
> +and @option{-fstack-protector} at the same time on the command line causes
> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
> +not enabled by @option{-fhardened}.
> +
> +This warning is enabled by default and has effect only when @option{-fhardened}
> +is enabled.
> +
> @opindex Wimplicit-fallthrough
> @opindex Wno-implicit-fallthrough
> @item -Wimplicit-fallthrough
> @@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
> unexpected. Use with @samp{-fharden-compares} to cover all
> conditionals.
>
> +@opindex fhardened
> +@item -fhardened
> +Enable a set of flags for C and C++ that improve the security of the
> +generated code without affecting its ABI. The precise flags enabled
> +may change between major releases of GCC, but are currently:
> +
> +@c Keep this in sync with print_help_hardened!
> +@gccoptlist{
> +-D_FORTIFY_SOURCE=3
> +-D_GLIBCXX_ASSERTIONS
> +-ftrivial-auto-var-init=pattern
> +-fPIE -pie -Wl,-z,relro,-z,now
> +-fstack-protector-strong
> +-fstack-clash-protection
> +-fcf-protection=full @r{(x86 GNU/Linux only)}
> +}
> +
> +The list of options enabled by @option{-fhardened} can be generated using
> +the @option{--help=hardened} option.
> +
> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
> +is used instead.
> +
> +@option{-fhardened} only enables a particular option if it wasn't
> +already specified anywhere on the command line. For instance,
> +@option{-fhardened} @option{-fstack-protector} will only enable
> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
> +
> @opindex fstack-protector
> @item -fstack-protector
> Emit extra code to check for buffer overflows, such as stack smashing
> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
> index c6e600fa0d3..ed4e2400e91 100644
> --- a/gcc/gcc.cc
> +++ b/gcc/gcc.cc
> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
> driver added to dumpdir after dumpbase or linker output name. */
> static bool dumpdir_trailing_dash_added = false;
>
> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
> + line. */
> +static bool any_link_options_p;
> +
> +/* True if -static was specified on the command line. */
> +static bool static_p;
> +
> /* Basename of dump and aux outputs, computed from dumpbase (given or
> derived from output name), to override input_basename in non-%w %b
> et al. */
> @@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
> save_switch ("-o", 1, &arg, validated, true);
> return true;
>
> -#ifdef ENABLE_DEFAULT_PIE
> case OPT_pie:
> +#ifdef ENABLE_DEFAULT_PIE
> /* -pie is turned on by default. */
> + validated = true;
> #endif
> + case OPT_r:
> + case OPT_shared:
> + case OPT_no_pie:
> + any_link_options_p = true;
> + break;
> +
> + case OPT_static:
> + static_p = true;
> + break;
>
> case OPT_static_libgcc:
> case OPT_shared_libgcc:
> @@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
> #endif
> }
>
> + /* TODO: check if -static -pie works and maybe use it. */
> + if (flag_hardened)
> + {
> + if (!any_link_options_p && !static_p)
> + {
> +#ifdef HAVE_LD_PIE
> + save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
> +#endif
> + /* These are passed straight down to collect2 so we have to break
> + it up like this. */
> + if (HAVE_LD_NOW_SUPPORT)
> + {
> + add_infile ("-z", "*");
> + add_infile ("now", "*");
> + }
> + if (HAVE_LD_RELRO_SUPPORT)
> + {
> + add_infile ("-z", "*");
> + add_infile ("relro", "*");
> + }
> + }
> + /* We can't use OPT_Whardened yet. Sigh. */
> + else if (warn_hardened)
> + warning_at (UNKNOWN_LOCATION, 0,
> + "linker hardening options not enabled by %<-fhardened%> "
> + "because other link options were specified on the command "
> + "line");
> + }
> +
> /* Handle -gtoggle as it would later in toplev.cc:process_options to
> make the debug-level-gt spec function work as expected. */
> if (flag_gtoggle)
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 573dcf8e497..8265c5b3c1b 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3. If not see
> /* Set by -fcanon-prefix-map. */
> bool flag_canon_prefix_map;
>
> +/* Set by finish_options when flag_stack_protector was set only because of
> + -fhardened. Yuck. */
> +bool flag_stack_protector_set_by_fhardened_p;
> +
> static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>
> /* Names of fundamental debug info formats indexed by enum
> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> opts->x_flag_section_anchors = 0;
> }
>
> + if (opts->x_flag_hardened)
> + {
> + if (!opts_set->x_flag_auto_var_init)
> + opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
> + else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
> + warning_at (loc, OPT_Whardened,
> + "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
> + "%<-fhardened%> because it was specified on the command "
> + "line");
> + }
> +
> if (!opts->x_flag_opts_finished)
> {
> /* We initialize opts->x_flag_pie to -1 so that targets can set a
> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> /* We initialize opts->x_flag_pic to -1 so that we can tell if
> -fpic, -fPIC, -fno-pic or -fno-PIC is used. */
> if (opts->x_flag_pic == -1)
> - opts->x_flag_pie = DEFAULT_FLAG_PIE;
> + opts->x_flag_pie = (opts->x_flag_hardened
> + ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
> else
> opts->x_flag_pie = 0;
> }
> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
> }
>
> /* We initialize opts->x_flag_stack_protect to -1 so that targets
> - can set a default value. */
> + can set a default value. With --enable-default-ssp or -fhardened
> + the default is -fstack-protector-strong. */
> if (opts->x_flag_stack_protect == -1)
> - opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> + {
> + /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
> + defined in such a way that it uses flag_stack_protect which can't
> + be used here. Moreover, some targets like BPF don't support
> + -fstack-protector at all but we don't know that here. So remember
> + that flag_stack_protect was set at the behest of -fhardened. */
> + if (opts->x_flag_hardened)
> + {
> + opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
> + flag_stack_protector_set_by_fhardened_p = true;
> + }
> + else
> + opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
> + }
> + else if (opts->x_flag_hardened
> + && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<-fstack-protector-strong%> is not enabled by "
> + "%<-fhardened%> because it was specified on the command "
> + "line");
>
> if (opts->x_optimize == 0)
> {
> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
> free (patch_area_arg);
> }
>
> +/* Print options enabled by -fhardened. Keep this in sync with the manual! */
> +
> +static void
> +print_help_hardened ()
> +{
> + printf ("%s\n", "The following options are enabled by -fhardened:");
> + printf (" %s=%d\n", "-D_FORTIFY_SOURCE",
> + (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
> + printf (" %s\n", "-D_GLIBCXX_ASSERTIONS");
> + printf (" %s\n", "-ftrivial-auto-var-init=pattern");
> +#ifdef HAVE_LD_PIE
> + printf (" %s %s\n", "-fPIE", "-pie");
> +#endif
> + if (HAVE_LD_NOW_SUPPORT)
> + printf (" %s\n", "-Wl,-z,now");
> + if (HAVE_LD_RELRO_SUPPORT)
> + printf (" %s\n", "-Wl,-z,relro");
> + printf (" %s\n", "-fstack-protector-strong");
> + printf (" %s\n", "-fstack-clash-protection");
> + printf (" %s\n", "-fcf-protection=full");
> + putchar ('\n');
> +}
> +
> /* Print help when OPT__help_ is set. */
>
> void
> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
> }
> else if (lang_flag != 0)
> *pflags |= lang_flag;
> + else if (strncasecmp (a, "hardened", len) == 0)
> + print_help_hardened ();
> else
> warning (0,
> "unrecognized argument to %<--help=%> option: %q.*s",
> diff --git a/gcc/opts.h b/gcc/opts.h
> index 00f377f9ca7..d89c5de8114 100644
> --- a/gcc/opts.h
> +++ b/gcc/opts.h
> @@ -344,6 +344,7 @@ struct cl_option_handlers
> /* Hold command-line options associated with stack limitation. */
> extern const char *opt_fstack_limit_symbol_arg;
> extern int opt_fstack_limit_register_no;
> +extern bool flag_stack_protector_set_by_fhardened_p;
>
> /* Input file names. */
>
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
> new file mode 100644
> index 00000000000..4dd22cdfe45
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
> @@ -0,0 +1,6 @@
> +/* { dg-do preprocess { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
> new file mode 100644
> index 00000000000..dd3cde93805
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#ifndef __SSP_STRONG__
> +# error "-fstack-protector-strong not enabled"
> +#endif
> +
> +#if _FORTIFY_SOURCE < 2
> +# error "_FORTIFY_SOURCE not enabled"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
> new file mode 100644
> index 00000000000..8242530bc4d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
> +
> +#if _FORTIFY_SOURCE != 1
> +# error "_FORTIFY_SOURCE != 1"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
> new file mode 100644
> index 00000000000..b8fd65a960c
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
> @@ -0,0 +1,10 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
> +
> +#ifndef _FORTIFY_SOURCE
> +# error "_FORTIFY_SOURCE disabled when it should not be"
> +#endif
> +
> +#ifndef _GLIBCXX_ASSERTIONS
> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> + int i;
> + return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
> new file mode 100644
> index 00000000000..6945a6391a9
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O" } */
> +
> +#if __PIE__ != 2
> +# error "-fPIE not enabled"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
> new file mode 100644
> index 00000000000..652ece3d4c4
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
> @@ -0,0 +1,6 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fno-PIE" } */
> +
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
> new file mode 100644
> index 00000000000..c6202754bf5
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
> @@ -0,0 +1,5 @@
> +/* { dg-do compile } */
> +/* { dg-require-stack-check "specific" } */
> +/* { dg-options "-fhardened -O -fstack-check" } */
> +
> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
> new file mode 100644
> index 00000000000..283867ca806
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -fstack-protector" } */
> +
> +#ifdef __SSP_STRONG__
> +# error "-fstack-protector-strong enabled when it should not be"
> +#endif
> +#ifndef __SSP__
> +# error "-fstack-protector not enabled"
> +#endif
> +
> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
> new file mode 100644
> index 00000000000..6924ba242f0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
> @@ -0,0 +1,14 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0" } */
> +/* Test that we don't get any diagnostic coming from libc headers. */
> +
> +#include <stdio.h>
> +
> +/* The most useful C program known to man. */
> +
> +int
> +main ()
> +{
> +}
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
> new file mode 100644
> index 00000000000..7d44d299f19
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
> @@ -0,0 +1,4 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
> +
> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
> new file mode 100644
> index 00000000000..42594e4c0e0
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
> @@ -0,0 +1,11 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> + int i;
> + return i;
> +}
> +
> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
> new file mode 100644
> index 00000000000..a757cbf0d12
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
> +
> +int
> +foo ()
> +{
> + int i;
> + return i;
> +}
> +
> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
> +/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
> new file mode 100644
> index 00000000000..32f35eb2595
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fpie" } */
> +
> +/* -fpie takes precedence over -fhardened */
> +#if __PIE__ != 1
> +# error "__PIE__ != 1"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
> new file mode 100644
> index 00000000000..5b3162b4d1f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
> @@ -0,0 +1,7 @@
> +/* { dg-do compile { target pie } } */
> +/* { dg-options "-fhardened -O -fPIC" } */
> +
> +/* -fPIC takes precedence over -fhardened */
> +#ifdef __PIE__
> +# error "PIE enabled when it should not be"
> +#endif
> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
> new file mode 100644
> index 00000000000..d3b9e79b9b6
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
> @@ -0,0 +1,9 @@
> +/* { dg-do compile } */
> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
> +
> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
> +# error "hardening enabled when it should not be"
> +#endif
> +
> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
> index 52b9cb0ab90..15d618a2528 100644
> --- a/gcc/testsuite/gcc.misc-tests/help.exp
> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
> # Listing only excludes gives empty results.
> check_for_options c "--help=^joined,^separate" "" "" ""
>
> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
> +
> if [ info exists prev_columns ] {
> # Reset the enviroment variable to its oriuginal value.
> set env(COLUMNS) $prev_columns
> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> new file mode 100644
> index 00000000000..73b78dce889
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
> +/* Test that -fhardened enables CET. */
> +
> +extern void bar (void) __attribute__((__cf_check__));
> +
> +void
> +foo (void)
> +{
> + bar ();
> +}
> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
> index 8af9bf5090e..743a3a91684 100644
> --- a/gcc/toplev.cc
> +++ b/gcc/toplev.cc
> @@ -1575,6 +1575,19 @@ process_options (bool no_backend)
> "where the stack grows from lower to higher addresses");
> flag_stack_clash_protection = 0;
> }
> + else if (flag_hardened)
> + {
> + if (!flag_stack_clash_protection
> + /* Don't enable -fstack-clash-protection when -fstack-check=
> + is used: it would result in confusing errors. */
> + && flag_stack_check == NO_STACK_CHECK)
> + flag_stack_clash_protection = 1;
> + else if (flag_stack_check != NO_STACK_CHECK)
> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
> + "%<-fstack-clash-protection%> is not enabled by "
> + "%<-fhardened%> because %<-fstack-check%> was "
> + "specified on the command line");
> + }
>
> /* We cannot support -fstack-check= and -fstack-clash-protection at
> the same time. */
> @@ -1590,8 +1603,9 @@ process_options (bool no_backend)
> target already uses a soft frame pointer, the transition is trivial. */
> if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
> {
> - warning_at (UNKNOWN_LOCATION, 0,
> - "%<-fstack-protector%> not supported for this target");
> + if (!flag_stack_protector_set_by_fhardened_p)
> + warning_at (UNKNOWN_LOCATION, 0,
> + "%<-fstack-protector%> not supported for this target");
> flag_stack_protect = 0;
> }
> if (!flag_stack_protect)
>
> base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
> --
> 2.41.0
>
Richard Biener <richard.guenther@gmail.com> writes:
> On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
>>
>> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
>> > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
>> > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
>> > > <gcc-patches@gcc.gnu.org> wrote:
>> > > >
>> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
>> > > > and aarch64-unknown-linux-gnu; ok for trunk?
>> > > >
>> > > > -- >8 --
>> > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
>> > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
>> > > > of hardening flags. The read of the room seems to be that the option
>> > > > would be useful. So here's a patch implementing that option.
>> > > >
>> > > > Currently, -fhardened enables:
>> > > >
>> > > > -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>> > > > -D_GLIBCXX_ASSERTIONS
>> > > > -ftrivial-auto-var-init=pattern
>
> I think =zero is much better here given the overhead is way
> cheaper and pointers get a more reliable behavior.
Yes please, as I wouldn't want us to use =pattern distro-wide.
>
>> > > > -fPIE -pie -Wl,-z,relro,-z,now
>> > > > -fstack-protector-strong
>> > > > -fstack-clash-protection
>> > > > -fcf-protection=full (x86 GNU/Linux only)
>> > > >
>> > > > -fhardened will not override options that were specified on the command line
>> > > > (before or after -fhardened). For example,
>> > > >
>> > > > -D_FORTIFY_SOURCE=1 -fhardened
>> > > >
>> > > > means that _FORTIFY_SOURCE=1 will be used. Similarly,
>> > > >
>> > > > -fhardened -fstack-protector
>> > > >
>> > > > will not enable -fstack-protector-strong.
>> > > >
>> > > > In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
>> > > > to anything. I think we need a better way to show what it actually
>> > > > enables.
>> > >
>> > > I do think we need to find a solution here to solve asserting compliance.
>> >
>> > Fair enough.
>> >
>> > > Maybe we can have -Whardened that will diagnose any altering of
>> > > -fhardened by other options on the command-line or by missed target
>> > > implementations? People might for example use -fstack-protector
>> > > but don't really want to make protection lower than requested with -fhardened.
>> > >
>> > > Any such conflict is much less appearant than when you use the
>> > > flags -fhardened composes.
>> >
>> > How about: --help=hardened says which options -fhardened attempts to
>> > enable, and -Whardened warns when it didn't enable an option? E.g.,
>> >
>> > -fstack-protector -fhardened -Whardened
>> >
>> > would say that it didn't enable -fstack-protector-strong because
>> > -fstack-protector was specified on the command line?
>> >
>> > If !HAVE_LD_NOW_SUPPORT, --help=hardened probably doesn't even have to
>> > list -z now, likewise for -z relro.
>> >
>> > Unclear if -Whardened should be enabled by default, but probably yes?
>>
>> Here's v2 which adds -Whardened (enabled by default).
>>
>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>
> I think it's OK but I'd like to see a second ACK here. Can you see how our
> primary and secondary targets (+ host OS) behave here? I think the
> documentation should elaborate a bit on expectations for non-Linux/GNU
> targets, specifically I think the default configuration for a target should
> with -fhardened _not_ have any -Whardened diagnostics. Maybe we can
> have a testcase for this?
>
> Thanks,
> Richard.
>
>>
>> -- >8 --
>> In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
>> I proposed -fhardened, a new umbrella option that enables a reasonable set
>> of hardening flags. The read of the room seems to be that the option
>> would be useful. So here's a patch implementing that option.
>>
>> Currently, -fhardened enables:
>>
>> -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>> -D_GLIBCXX_ASSERTIONS
>> -ftrivial-auto-var-init=pattern
>> -fPIE -pie -Wl,-z,relro,-z,now
>> -fstack-protector-strong
>> -fstack-clash-protection
>> -fcf-protection=full (x86 GNU/Linux only)
>>
>> -fhardened will not override options that were specified on the command line
>> (before or after -fhardened). For example,
>>
>> -D_FORTIFY_SOURCE=1 -fhardened
>>
>> means that _FORTIFY_SOURCE=1 will be used. Similarly,
>>
>> -fhardened -fstack-protector
>>
>> will not enable -fstack-protector-strong.
>>
>> In DW_AT_producer it is reflected only as -fhardened; it doesn't expand
>> to anything. This patch provides -Whardened, enabled by default, which
>> warns when -fhardened couldn't enable a particular option. I think most
>> often it will say that _FORTIFY_SOURCE wasn't enabled because optimization
>> were not enabled.
>>
>> gcc/c-family/ChangeLog:
>>
>> * c-opts.cc (c_finish_options): Maybe cpp_define _FORTIFY_SOURCE
>> and _GLIBCXX_ASSERTIONS.
>>
>> gcc/ChangeLog:
>>
>> * common.opt (Whardened, fhardened): New options.
>> * config.in: Regenerate.
>> * config/bpf/bpf.cc: Include "opts.h".
>> (bpf_option_override): If flag_stack_protector_set_by_fhardened_p, do
>> not inform that -fstack-protector does not work.
>> * config/i386/i386-options.cc (ix86_option_override_internal): When
>> -fhardened, maybe enable -fcf-protection=full.
>> * configure: Regenerate.
>> * configure.ac: Check if the linker supports '-z now' and '-z relro'.
>> * doc/invoke.texi: Document -fhardened and -Whardened.
>> * gcc.cc (driver_handle_option): Remember if any link options or -static
>> were specified on the command line.
>> (process_command): When -fhardened, maybe enable -pie and
>> -Wl,-z,relro,-z,now.
>> * opts.cc (flag_stack_protector_set_by_fhardened_p): New global.
>> (finish_options): When -fhardened, enable
>> -ftrivial-auto-var-init=pattern and -fstack-protector-strong.
>> (print_help_hardened): New.
>> (print_help): Call it.
>> * toplev.cc (process_options): When -fhardened, enable
>> -fstack-clash-protection. If flag_stack_protector_set_by_fhardened_p,
>> do not warn that -fstack-protector not supported for this target.
>>
>> gcc/testsuite/ChangeLog:
>>
>> * gcc.misc-tests/help.exp: Test -fhardened.
>> * c-c++-common/fhardened-1.S: New test.
>> * c-c++-common/fhardened-1.c: New test.
>> * c-c++-common/fhardened-10.c: New test.
>> * c-c++-common/fhardened-11.c: New test.
>> * c-c++-common/fhardened-12.c: New test.
>> * c-c++-common/fhardened-13.c: New test.
>> * c-c++-common/fhardened-14.c: New test.
>> * c-c++-common/fhardened-15.c: New test.
>> * c-c++-common/fhardened-2.c: New test.
>> * c-c++-common/fhardened-3.c: New test.
>> * c-c++-common/fhardened-4.c: New test.
>> * c-c++-common/fhardened-5.c: New test.
>> * c-c++-common/fhardened-6.c: New test.
>> * c-c++-common/fhardened-7.c: New test.
>> * c-c++-common/fhardened-8.c: New test.
>> * c-c++-common/fhardened-9.c: New test.
>> * gcc.target/i386/cf_check-6.c: New test.
>> ---
>> gcc/c-family/c-opts.cc | 42 ++++++++++++++
>> gcc/common.opt | 8 +++
>> gcc/config.in | 12 ++++
>> gcc/config/bpf/bpf.cc | 8 ++-
>> gcc/config/i386/i386-options.cc | 17 +++++-
>> gcc/configure | 50 +++++++++++++++-
>> gcc/configure.ac | 42 +++++++++++++-
>> gcc/doc/invoke.texi | 44 +++++++++++++-
>> gcc/gcc.cc | 48 +++++++++++++++-
>> gcc/opts.cc | 67 +++++++++++++++++++++-
>> gcc/opts.h | 1 +
>> gcc/testsuite/c-c++-common/fhardened-1.S | 6 ++
>> gcc/testsuite/c-c++-common/fhardened-1.c | 14 +++++
>> gcc/testsuite/c-c++-common/fhardened-10.c | 12 ++++
>> gcc/testsuite/c-c++-common/fhardened-11.c | 10 ++++
>> gcc/testsuite/c-c++-common/fhardened-12.c | 11 ++++
>> gcc/testsuite/c-c++-common/fhardened-13.c | 6 ++
>> gcc/testsuite/c-c++-common/fhardened-14.c | 6 ++
>> gcc/testsuite/c-c++-common/fhardened-15.c | 5 ++
>> gcc/testsuite/c-c++-common/fhardened-2.c | 12 ++++
>> gcc/testsuite/c-c++-common/fhardened-3.c | 14 +++++
>> gcc/testsuite/c-c++-common/fhardened-4.c | 4 ++
>> gcc/testsuite/c-c++-common/fhardened-5.c | 11 ++++
>> gcc/testsuite/c-c++-common/fhardened-6.c | 12 ++++
>> gcc/testsuite/c-c++-common/fhardened-7.c | 7 +++
>> gcc/testsuite/c-c++-common/fhardened-8.c | 7 +++
>> gcc/testsuite/c-c++-common/fhardened-9.c | 9 +++
>> gcc/testsuite/gcc.misc-tests/help.exp | 2 +
>> gcc/testsuite/gcc.target/i386/cf_check-6.c | 12 ++++
>> gcc/toplev.cc | 18 +++++-
>> 30 files changed, 503 insertions(+), 14 deletions(-)
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.S
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-1.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-10.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-11.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-12.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-13.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-14.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-15.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-2.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-3.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-4.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-5.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-6.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-7.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-8.c
>> create mode 100644 gcc/testsuite/c-c++-common/fhardened-9.c
>> create mode 100644 gcc/testsuite/gcc.target/i386/cf_check-6.c
>>
>> diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
>> index ce2e021e69d..f5f6ba24290 100644
>> --- a/gcc/c-family/c-opts.cc
>> +++ b/gcc/c-family/c-opts.cc
>> @@ -1556,6 +1556,9 @@ c_finish_options (void)
>> cb_file_change (parse_in, cmd_map);
>> linemap_line_start (line_table, 0, 1);
>>
>> + bool fortify_seen_p = false;
>> + bool cxx_assert_seen_p = false;
>> +
>> /* All command line defines must have the same location. */
>> cpp_force_token_locations (parse_in, line_table->highest_line);
>> for (size_t i = 0; i < deferred_count; i++)
>> @@ -1573,6 +1576,45 @@ c_finish_options (void)
>> else
>> cpp_assert (parse_in, opt->arg);
>> }
>> +
>> + if (UNLIKELY (flag_hardened)
>> + && (opt->code == OPT_D || opt->code == OPT_U))
>> + {
>> + if (!fortify_seen_p)
>> + fortify_seen_p
>> + = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
>> + && (opt->arg[15] == '\0' || opt->arg[15] == '='));
>> + if (!cxx_assert_seen_p)
>> + cxx_assert_seen_p
>> + = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
>> + && (opt->arg[19] == '\0' || opt->arg[19] == '='));
>> + }
>> + }
>> +
>> + if (flag_hardened)
>> + {
>> + if (!fortify_seen_p && optimize > 0)
>> + {
>> + if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
>> + cpp_define (parse_in, "_FORTIFY_SOURCE=3");
>> + else
>> + cpp_define (parse_in, "_FORTIFY_SOURCE=2");
>> + }
>> + else if (optimize == 0)
>> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> + "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
>> + "because optimizations are turned off");
>> + else
>> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> + "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
>> + "because it was specified in %<-D%> or %<-U%>");
>> + if (!cxx_assert_seen_p)
>> + cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
>> + else
>> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> + "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
>> + "%<-fhardened%> because it was specified in %<-D%> "
>> + "or %<-U%>");
>> }
>>
>> cpp_stop_forcing_token_locations (parse_in);
>> diff --git a/gcc/common.opt b/gcc/common.opt
>> index f137a1f81ac..60c13b9ffd2 100644
>> --- a/gcc/common.opt
>> +++ b/gcc/common.opt
>> @@ -634,6 +634,10 @@ Wfree-nonheap-object
>> Common Var(warn_free_nonheap_object) Init(1) Warning
>> Warn when attempting to free a non-heap object.
>>
>> +Whardened
>> +Common Var(warn_hardened) Init(1) Warning
>> +Warn when -fhardened did not enable an option from its set.
>> +
>> Whsa
>> Common Ignore Warning
>> Does nothing. Preserved for backward compatibility.
>> @@ -1827,6 +1831,10 @@ fharden-conditional-branches
>> Common Var(flag_harden_conditional_branches) Optimization
>> Harden conditional branches by checking reversed conditions.
>>
>> +fhardened
>> +Common Driver Var(flag_hardened)
>> +Enable various security-relevant flags.
>> +
>> ; Nonzero means ignore `#ident' directives. 0 means handle them.
>> ; Generate position-independent code for executables if possible
>> ; On SVR4 targets, it also controls whether or not to emit a
>> diff --git a/gcc/config.in b/gcc/config.in
>> index d04718ad128..faa941c1385 100644
>> --- a/gcc/config.in
>> +++ b/gcc/config.in
>> @@ -1676,6 +1676,12 @@
>> #endif
>>
>>
>> +/* Define 0/1 if your linker supports -z now */
>> +#ifndef USED_FOR_TARGET
>> +#undef HAVE_LD_NOW_SUPPORT
>> +#endif
>> +
>> +
>> /* Define if your PowerPC64 linker only needs function descriptor syms. */
>> #ifndef USED_FOR_TARGET
>> #undef HAVE_LD_NO_DOT_SYMS
>> @@ -1719,6 +1725,12 @@
>> #endif
>>
>>
>> +/* Define 0/1 if your linker supports -z relro */
>> +#ifndef USED_FOR_TARGET
>> +#undef HAVE_LD_RELRO_SUPPORT
>> +#endif
>> +
>> +
>> /* Define if your linker links a mix of read-only and read-write sections into
>> a read-write section. */
>> #ifndef USED_FOR_TARGET
>> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
>> index 437bd652de3..41dc7fd3dae 100644
>> --- a/gcc/config/bpf/bpf.cc
>> +++ b/gcc/config/bpf/bpf.cc
>> @@ -70,6 +70,7 @@ along with GCC; see the file COPYING3. If not see
>> #include "gimplify-me.h"
>>
>> #include "core-builtins.h"
>> +#include "opts.h"
>>
>> /* Per-function machine data. */
>> struct GTY(()) machine_function
>> @@ -250,9 +251,10 @@ bpf_option_override (void)
>> /* Disable -fstack-protector as it is not supported in BPF. */
>> if (flag_stack_protect)
>> {
>> - inform (input_location,
>> - "%<-fstack-protector%> does not work "
>> - "on this architecture");
>> + if (!flag_stack_protector_set_by_fhardened_p)
>> + inform (input_location,
>> + "%<-fstack-protector%> does not work "
>> + "on this architecture");
>> flag_stack_protect = 0;
>> }
>>
>> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
>> index 06af373ca57..22ede9e15b5 100644
>> --- a/gcc/config/i386/i386-options.cc
>> +++ b/gcc/config/i386/i386-options.cc
>> @@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
>> = build_target_option_node (opts, opts_set);
>> }
>>
>> + const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
>> + /* When -fhardened, enable -fcf-protection=full, but only when it's
>> + compatible with this target, and when it wasn't already specified
>> + on the command line. */
>> + if (opts->x_flag_hardened && cf_okay_p)
>> + {
>> + if (opts->x_flag_cf_protection == CF_NONE)
>> + opts->x_flag_cf_protection = CF_FULL;
>> + else if (opts->x_flag_cf_protection != CF_FULL)
>> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> + "%<-fcf-protection=full%> is not enabled by "
>> + "%<-fhardened%> because it was specified on the command "
>> + "line");
>> + }
>> +
>> if (opts->x_flag_cf_protection != CF_NONE)
>> {
>> if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
>> - && !TARGET_64BIT && !TARGET_CMOV)
>> + && !cf_okay_p)
>> error ("%<-fcf-protection%> is not compatible with this target");
>>
>> opts->x_flag_cf_protection
>> diff --git a/gcc/configure b/gcc/configure
>> index c43bde8174b..e2aac56edf6 100755
>> --- a/gcc/configure
>> +++ b/gcc/configure
>> @@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
>> ld_bndplt_support=yes
>> fi
>> elif test x$gcc_cv_ld != x; then
>> - # Check if linker supports -a bndplt option
>> + # Check if linker supports -z bndplt option
>> if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>> ld_bndplt_support=yes
>> fi
>> @@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
>> ;;
>> esac
>>
>> +# Check if the linker supports '-z now'
>> +ld_now_support=no
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
>> +$as_echo_n "checking linker -z now option... " >&6; }
>> +if test x"$ld_is_gold" = xyes; then
>> + ld_now_support=yes
>> +elif test $in_tree_ld = yes ; then
>> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
>> + ld_now_support=yes
>> + fi
>> +elif test x$gcc_cv_ld != x; then
>> + # Check if linker supports -z now
>> + if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
>> + ld_now_support=yes
>> + fi
>> +fi
>> +
>> +cat >>confdefs.h <<_ACEOF
>> +#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
>> +_ACEOF
>> +
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
>> +$as_echo "$ld_now_support" >&6; }
>> +
>> +# Check if the linker supports '-z relro'
>> +ld_relro_support=no
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
>> +$as_echo_n "checking linker -z relro option... " >&6; }
>> +if test x"$ld_is_gold" = xyes; then
>> + ld_relro_support=yes
>> +elif test $in_tree_ld = yes ; then
>> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
>> + ld_relro_support=yes
>> + fi
>> +elif test x$gcc_cv_ld != x; then
>> + # Check if linker supports -z relro
>> + if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
>> + ld_relro_support=yes
>> + fi
>> +fi
>> +
>> +cat >>confdefs.h <<_ACEOF
>> +#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
>> +_ACEOF
>> +
>> +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
>> +$as_echo "$ld_relro_support" >&6; }
>> +
>> # Configure the subdirectories
>> # AC_CONFIG_SUBDIRS($subdirs)
>>
>> diff --git a/gcc/configure.ac b/gcc/configure.ac
>> index fb8e32f8ee5..6a090ccf3bd 100644
>> --- a/gcc/configure.ac
>> +++ b/gcc/configure.ac
>> @@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
>> ld_bndplt_support=yes
>> fi
>> elif test x$gcc_cv_ld != x; then
>> - # Check if linker supports -a bndplt option
>> + # Check if linker supports -z bndplt option
>> if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
>> ld_bndplt_support=yes
>> fi
>> @@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
>> ;;
>> esac
>>
>> +# Check if the linker supports '-z now'
>> +ld_now_support=no
>> +AC_MSG_CHECKING(linker -z now option)
>> +if test x"$ld_is_gold" = xyes; then
>> + ld_now_support=yes
>> +elif test $in_tree_ld = yes ; then
>> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
>> + ld_now_support=yes
>> + fi
>> +elif test x$gcc_cv_ld != x; then
>> + # Check if linker supports -z now
>> + if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
>> + ld_now_support=yes
>> + fi
>> +fi
>> +AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
>> + [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
>> + [Define 0/1 if your linker supports -z now])
>> +AC_MSG_RESULT($ld_now_support)
>> +
>> +# Check if the linker supports '-z relro'
>> +ld_relro_support=no
>> +AC_MSG_CHECKING(linker -z relro option)
>> +if test x"$ld_is_gold" = xyes; then
>> + ld_relro_support=yes
>> +elif test $in_tree_ld = yes ; then
>> + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
>> + ld_relro_support=yes
>> + fi
>> +elif test x$gcc_cv_ld != x; then
>> + # Check if linker supports -z relro
>> + if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
>> + ld_relro_support=yes
>> + fi
>> +fi
>> +AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
>> + [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
>> + [Define 0/1 if your linker supports -z relro])
>> +AC_MSG_RESULT($ld_relro_support)
>> +
>> # Configure the subdirectories
>> # AC_CONFIG_SUBDIRS($subdirs)
>>
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index 7c5f81d9783..48e6a3f433c 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
>> -Wformat-y2k -Wframe-address
>> -Wframe-larger-than=@var{byte-size} -Wno-free-nonheap-object
>> -Wno-if-not-aligned -Wno-ignored-attributes
>> --Wignored-qualifiers -Wno-incompatible-pointer-types
>> +-Wignored-qualifiers -Wno-incompatible-pointer-types -Whardened
>> -Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n}
>> -Wno-implicit-function-declaration -Wno-implicit-int
>> -Winfinite-recursion
>> @@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
>> -fasan-shadow-offset=@var{number} -fsanitize-sections=@var{s1},@var{s2},...
>> -fsanitize-undefined-trap-on-error -fbounds-check
>> -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
>> --fharden-compares -fharden-conditional-branches
>> +-fharden-compares -fharden-conditional-branches -fhardened
>> -fstack-protector -fstack-protector-all -fstack-protector-strong
>> -fstack-protector-explicit -fstack-check
>> -fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym}
>> @@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
>> Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
>> This warning is enabled by @option{-Wall}.
>>
>> +@opindex Whardened
>> +@opindex Wno-hardened
>> +@item -Whardened
>> +Warn when @option{-fhardened} did not enable an option from its set (for
>> +which see @option{-fhardened}). For instance, using @option{-fhardened}
>> +and @option{-fstack-protector} at the same time on the command line causes
>> +@option{-Whardened} to warn because @option{-fstack-protector-strong} is
>> +not enabled by @option{-fhardened}.
>> +
>> +This warning is enabled by default and has effect only when @option{-fhardened}
>> +is enabled.
>> +
>> @opindex Wimplicit-fallthrough
>> @opindex Wno-implicit-fallthrough
>> @item -Wimplicit-fallthrough
>> @@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
>> unexpected. Use with @samp{-fharden-compares} to cover all
>> conditionals.
>>
>> +@opindex fhardened
>> +@item -fhardened
>> +Enable a set of flags for C and C++ that improve the security of the
>> +generated code without affecting its ABI. The precise flags enabled
>> +may change between major releases of GCC, but are currently:
>> +
>> +@c Keep this in sync with print_help_hardened!
>> +@gccoptlist{
>> +-D_FORTIFY_SOURCE=3
>> +-D_GLIBCXX_ASSERTIONS
>> +-ftrivial-auto-var-init=pattern
>> +-fPIE -pie -Wl,-z,relro,-z,now
>> +-fstack-protector-strong
>> +-fstack-clash-protection
>> +-fcf-protection=full @r{(x86 GNU/Linux only)}
>> +}
>> +
>> +The list of options enabled by @option{-fhardened} can be generated using
>> +the @option{--help=hardened} option.
>> +
>> +When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
>> +is used instead.
>> +
>> +@option{-fhardened} only enables a particular option if it wasn't
>> +already specified anywhere on the command line. For instance,
>> +@option{-fhardened} @option{-fstack-protector} will only enable
>> +@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
>> +
>> @opindex fstack-protector
>> @item -fstack-protector
>> Emit extra code to check for buffer overflows, such as stack smashing
>> diff --git a/gcc/gcc.cc b/gcc/gcc.cc
>> index c6e600fa0d3..ed4e2400e91 100644
>> --- a/gcc/gcc.cc
>> +++ b/gcc/gcc.cc
>> @@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
>> driver added to dumpdir after dumpbase or linker output name. */
>> static bool dumpdir_trailing_dash_added = false;
>>
>> +/* True if -r, -shared, -pie, or -no-pie were specified on the command
>> + line. */
>> +static bool any_link_options_p;
>> +
>> +/* True if -static was specified on the command line. */
>> +static bool static_p;
>> +
>> /* Basename of dump and aux outputs, computed from dumpbase (given or
>> derived from output name), to override input_basename in non-%w %b
>> et al. */
>> @@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
>> save_switch ("-o", 1, &arg, validated, true);
>> return true;
>>
>> -#ifdef ENABLE_DEFAULT_PIE
>> case OPT_pie:
>> +#ifdef ENABLE_DEFAULT_PIE
>> /* -pie is turned on by default. */
>> + validated = true;
>> #endif
>> + case OPT_r:
>> + case OPT_shared:
>> + case OPT_no_pie:
>> + any_link_options_p = true;
>> + break;
>> +
>> + case OPT_static:
>> + static_p = true;
>> + break;
>>
>> case OPT_static_libgcc:
>> case OPT_shared_libgcc:
>> @@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
>> #endif
>> }
>>
>> + /* TODO: check if -static -pie works and maybe use it. */
>> + if (flag_hardened)
>> + {
>> + if (!any_link_options_p && !static_p)
>> + {
>> +#ifdef HAVE_LD_PIE
>> + save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
>> +#endif
>> + /* These are passed straight down to collect2 so we have to break
>> + it up like this. */
>> + if (HAVE_LD_NOW_SUPPORT)
>> + {
>> + add_infile ("-z", "*");
>> + add_infile ("now", "*");
>> + }
>> + if (HAVE_LD_RELRO_SUPPORT)
>> + {
>> + add_infile ("-z", "*");
>> + add_infile ("relro", "*");
>> + }
>> + }
>> + /* We can't use OPT_Whardened yet. Sigh. */
>> + else if (warn_hardened)
>> + warning_at (UNKNOWN_LOCATION, 0,
>> + "linker hardening options not enabled by %<-fhardened%> "
>> + "because other link options were specified on the command "
>> + "line");
>> + }
>> +
>> /* Handle -gtoggle as it would later in toplev.cc:process_options to
>> make the debug-level-gt spec function work as expected. */
>> if (flag_gtoggle)
>> diff --git a/gcc/opts.cc b/gcc/opts.cc
>> index 573dcf8e497..8265c5b3c1b 100644
>> --- a/gcc/opts.cc
>> +++ b/gcc/opts.cc
>> @@ -43,6 +43,10 @@ along with GCC; see the file COPYING3. If not see
>> /* Set by -fcanon-prefix-map. */
>> bool flag_canon_prefix_map;
>>
>> +/* Set by finish_options when flag_stack_protector was set only because of
>> + -fhardened. Yuck. */
>> +bool flag_stack_protector_set_by_fhardened_p;
>> +
>> static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
>>
>> /* Names of fundamental debug info formats indexed by enum
>> @@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>> opts->x_flag_section_anchors = 0;
>> }
>>
>> + if (opts->x_flag_hardened)
>> + {
>> + if (!opts_set->x_flag_auto_var_init)
>> + opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
>> + else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
>> + warning_at (loc, OPT_Whardened,
>> + "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
>> + "%<-fhardened%> because it was specified on the command "
>> + "line");
>> + }
>> +
>> if (!opts->x_flag_opts_finished)
>> {
>> /* We initialize opts->x_flag_pie to -1 so that targets can set a
>> @@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>> /* We initialize opts->x_flag_pic to -1 so that we can tell if
>> -fpic, -fPIC, -fno-pic or -fno-PIC is used. */
>> if (opts->x_flag_pic == -1)
>> - opts->x_flag_pie = DEFAULT_FLAG_PIE;
>> + opts->x_flag_pie = (opts->x_flag_hardened
>> + ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
>> else
>> opts->x_flag_pie = 0;
>> }
>> @@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
>> }
>>
>> /* We initialize opts->x_flag_stack_protect to -1 so that targets
>> - can set a default value. */
>> + can set a default value. With --enable-default-ssp or -fhardened
>> + the default is -fstack-protector-strong. */
>> if (opts->x_flag_stack_protect == -1)
>> - opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
>> + {
>> + /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
>> + defined in such a way that it uses flag_stack_protect which can't
>> + be used here. Moreover, some targets like BPF don't support
>> + -fstack-protector at all but we don't know that here. So remember
>> + that flag_stack_protect was set at the behest of -fhardened. */
>> + if (opts->x_flag_hardened)
>> + {
>> + opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
>> + flag_stack_protector_set_by_fhardened_p = true;
>> + }
>> + else
>> + opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
>> + }
>> + else if (opts->x_flag_hardened
>> + && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
>> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> + "%<-fstack-protector-strong%> is not enabled by "
>> + "%<-fhardened%> because it was specified on the command "
>> + "line");
>>
>> if (opts->x_optimize == 0)
>> {
>> @@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
>> free (patch_area_arg);
>> }
>>
>> +/* Print options enabled by -fhardened. Keep this in sync with the manual! */
>> +
>> +static void
>> +print_help_hardened ()
>> +{
>> + printf ("%s\n", "The following options are enabled by -fhardened:");
>> + printf (" %s=%d\n", "-D_FORTIFY_SOURCE",
>> + (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
>> + printf (" %s\n", "-D_GLIBCXX_ASSERTIONS");
>> + printf (" %s\n", "-ftrivial-auto-var-init=pattern");
>> +#ifdef HAVE_LD_PIE
>> + printf (" %s %s\n", "-fPIE", "-pie");
>> +#endif
>> + if (HAVE_LD_NOW_SUPPORT)
>> + printf (" %s\n", "-Wl,-z,now");
>> + if (HAVE_LD_RELRO_SUPPORT)
>> + printf (" %s\n", "-Wl,-z,relro");
>> + printf (" %s\n", "-fstack-protector-strong");
>> + printf (" %s\n", "-fstack-clash-protection");
>> + printf (" %s\n", "-fcf-protection=full");
>> + putchar ('\n');
>> +}
>> +
>> /* Print help when OPT__help_ is set. */
>>
>> void
>> @@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
>> }
>> else if (lang_flag != 0)
>> *pflags |= lang_flag;
>> + else if (strncasecmp (a, "hardened", len) == 0)
>> + print_help_hardened ();
>> else
>> warning (0,
>> "unrecognized argument to %<--help=%> option: %q.*s",
>> diff --git a/gcc/opts.h b/gcc/opts.h
>> index 00f377f9ca7..d89c5de8114 100644
>> --- a/gcc/opts.h
>> +++ b/gcc/opts.h
>> @@ -344,6 +344,7 @@ struct cl_option_handlers
>> /* Hold command-line options associated with stack limitation. */
>> extern const char *opt_fstack_limit_symbol_arg;
>> extern int opt_fstack_limit_register_no;
>> +extern bool flag_stack_protector_set_by_fhardened_p;
>>
>> /* Input file names. */
>>
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.S b/gcc/testsuite/c-c++-common/fhardened-1.S
>> new file mode 100644
>> index 00000000000..4dd22cdfe45
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-1.S
>> @@ -0,0 +1,6 @@
>> +/* { dg-do preprocess { target pie } } */
>> +/* { dg-options "-fhardened -O" } */
>> +
>> +#if __PIE__ != 2
>> +# error "-fPIE not enabled"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-1.c b/gcc/testsuite/c-c++-common/fhardened-1.c
>> new file mode 100644
>> index 00000000000..dd3cde93805
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-1.c
>> @@ -0,0 +1,14 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O" } */
>> +
>> +#ifndef __SSP_STRONG__
>> +# error "-fstack-protector-strong not enabled"
>> +#endif
>> +
>> +#if _FORTIFY_SOURCE < 2
>> +# error "_FORTIFY_SOURCE not enabled"
>> +#endif
>> +
>> +#ifndef _GLIBCXX_ASSERTIONS
>> +# error "_GLIBCXX_ASSERTIONS not enabled"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-10.c b/gcc/testsuite/c-c++-common/fhardened-10.c
>> new file mode 100644
>> index 00000000000..8242530bc4d
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-10.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
>> +
>> +#if _FORTIFY_SOURCE != 1
>> +# error "_FORTIFY_SOURCE != 1"
>> +#endif
>> +
>> +#ifndef _GLIBCXX_ASSERTIONS
>> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
>> +#endif
>> +
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-11.c b/gcc/testsuite/c-c++-common/fhardened-11.c
>> new file mode 100644
>> index 00000000000..b8fd65a960c
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-11.c
>> @@ -0,0 +1,10 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
>> +
>> +#ifndef _FORTIFY_SOURCE
>> +# error "_FORTIFY_SOURCE disabled when it should not be"
>> +#endif
>> +
>> +#ifndef _GLIBCXX_ASSERTIONS
>> +# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-12.c b/gcc/testsuite/c-c++-common/fhardened-12.c
>> new file mode 100644
>> index 00000000000..42594e4c0e0
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-12.c
>> @@ -0,0 +1,11 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
>> +
>> +int
>> +foo ()
>> +{
>> + int i;
>> + return i;
>> +}
>> +
>> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-13.c b/gcc/testsuite/c-c++-common/fhardened-13.c
>> new file mode 100644
>> index 00000000000..6945a6391a9
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-13.c
>> @@ -0,0 +1,6 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O" } */
>> +
>> +#if __PIE__ != 2
>> +# error "-fPIE not enabled"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-14.c b/gcc/testsuite/c-c++-common/fhardened-14.c
>> new file mode 100644
>> index 00000000000..652ece3d4c4
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-14.c
>> @@ -0,0 +1,6 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O -fno-PIE" } */
>> +
>> +#ifdef __PIE__
>> +# error "PIE enabled when it should not be"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-15.c b/gcc/testsuite/c-c++-common/fhardened-15.c
>> new file mode 100644
>> index 00000000000..c6202754bf5
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-15.c
>> @@ -0,0 +1,5 @@
>> +/* { dg-do compile } */
>> +/* { dg-require-stack-check "specific" } */
>> +/* { dg-options "-fhardened -O -fstack-check" } */
>> +
>> +/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-2.c b/gcc/testsuite/c-c++-common/fhardened-2.c
>> new file mode 100644
>> index 00000000000..283867ca806
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-2.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -fstack-protector" } */
>> +
>> +#ifdef __SSP_STRONG__
>> +# error "-fstack-protector-strong enabled when it should not be"
>> +#endif
>> +#ifndef __SSP__
>> +# error "-fstack-protector not enabled"
>> +#endif
>> +
>> +/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-3.c b/gcc/testsuite/c-c++-common/fhardened-3.c
>> new file mode 100644
>> index 00000000000..6924ba242f0
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-3.c
>> @@ -0,0 +1,14 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O0" } */
>> +/* Test that we don't get any diagnostic coming from libc headers. */
>> +
>> +#include <stdio.h>
>> +
>> +/* The most useful C program known to man. */
>> +
>> +int
>> +main ()
>> +{
>> +}
>> +
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-4.c b/gcc/testsuite/c-c++-common/fhardened-4.c
>> new file mode 100644
>> index 00000000000..7d44d299f19
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-4.c
>> @@ -0,0 +1,4 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O0 -Wno-hardened" } */
>> +
>> +/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-5.c b/gcc/testsuite/c-c++-common/fhardened-5.c
>> new file mode 100644
>> index 00000000000..42594e4c0e0
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-5.c
>> @@ -0,0 +1,11 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
>> +
>> +int
>> +foo ()
>> +{
>> + int i;
>> + return i;
>> +}
>> +
>> +/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-6.c b/gcc/testsuite/c-c++-common/fhardened-6.c
>> new file mode 100644
>> index 00000000000..a757cbf0d12
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-6.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
>> +
>> +int
>> +foo ()
>> +{
>> + int i;
>> + return i;
>> +}
>> +
>> +/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
>> +/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-7.c b/gcc/testsuite/c-c++-common/fhardened-7.c
>> new file mode 100644
>> index 00000000000..32f35eb2595
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-7.c
>> @@ -0,0 +1,7 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O -fpie" } */
>> +
>> +/* -fpie takes precedence over -fhardened */
>> +#if __PIE__ != 1
>> +# error "__PIE__ != 1"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-8.c b/gcc/testsuite/c-c++-common/fhardened-8.c
>> new file mode 100644
>> index 00000000000..5b3162b4d1f
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-8.c
>> @@ -0,0 +1,7 @@
>> +/* { dg-do compile { target pie } } */
>> +/* { dg-options "-fhardened -O -fPIC" } */
>> +
>> +/* -fPIC takes precedence over -fhardened */
>> +#ifdef __PIE__
>> +# error "PIE enabled when it should not be"
>> +#endif
>> diff --git a/gcc/testsuite/c-c++-common/fhardened-9.c b/gcc/testsuite/c-c++-common/fhardened-9.c
>> new file mode 100644
>> index 00000000000..d3b9e79b9b6
>> --- /dev/null
>> +++ b/gcc/testsuite/c-c++-common/fhardened-9.c
>> @@ -0,0 +1,9 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
>> +
>> +#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
>> +# error "hardening enabled when it should not be"
>> +#endif
>> +
>> +/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
>> +/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
>> diff --git a/gcc/testsuite/gcc.misc-tests/help.exp b/gcc/testsuite/gcc.misc-tests/help.exp
>> index 52b9cb0ab90..15d618a2528 100644
>> --- a/gcc/testsuite/gcc.misc-tests/help.exp
>> +++ b/gcc/testsuite/gcc.misc-tests/help.exp
>> @@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
>> # Listing only excludes gives empty results.
>> check_for_options c "--help=^joined,^separate" "" "" ""
>>
>> +check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
>> +
>> if [ info exists prev_columns ] {
>> # Reset the enviroment variable to its oriuginal value.
>> set env(COLUMNS) $prev_columns
>> diff --git a/gcc/testsuite/gcc.target/i386/cf_check-6.c b/gcc/testsuite/gcc.target/i386/cf_check-6.c
>> new file mode 100644
>> index 00000000000..73b78dce889
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/i386/cf_check-6.c
>> @@ -0,0 +1,12 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
>> +/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
>> +/* Test that -fhardened enables CET. */
>> +
>> +extern void bar (void) __attribute__((__cf_check__));
>> +
>> +void
>> +foo (void)
>> +{
>> + bar ();
>> +}
>> diff --git a/gcc/toplev.cc b/gcc/toplev.cc
>> index 8af9bf5090e..743a3a91684 100644
>> --- a/gcc/toplev.cc
>> +++ b/gcc/toplev.cc
>> @@ -1575,6 +1575,19 @@ process_options (bool no_backend)
>> "where the stack grows from lower to higher addresses");
>> flag_stack_clash_protection = 0;
>> }
>> + else if (flag_hardened)
>> + {
>> + if (!flag_stack_clash_protection
>> + /* Don't enable -fstack-clash-protection when -fstack-check=
>> + is used: it would result in confusing errors. */
>> + && flag_stack_check == NO_STACK_CHECK)
>> + flag_stack_clash_protection = 1;
>> + else if (flag_stack_check != NO_STACK_CHECK)
>> + warning_at (UNKNOWN_LOCATION, OPT_Whardened,
>> + "%<-fstack-clash-protection%> is not enabled by "
>> + "%<-fhardened%> because %<-fstack-check%> was "
>> + "specified on the command line");
>> + }
>>
>> /* We cannot support -fstack-check= and -fstack-clash-protection at
>> the same time. */
>> @@ -1590,8 +1603,9 @@ process_options (bool no_backend)
>> target already uses a soft frame pointer, the transition is trivial. */
>> if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
>> {
>> - warning_at (UNKNOWN_LOCATION, 0,
>> - "%<-fstack-protector%> not supported for this target");
>> + if (!flag_stack_protector_set_by_fhardened_p)
>> + warning_at (UNKNOWN_LOCATION, 0,
>> + "%<-fstack-protector%> not supported for this target");
>> flag_stack_protect = 0;
>> }
>> if (!flag_stack_protect)
>>
>> base-commit: e8d418df3dc609f27487deece796d4aa69004b8c
>> --
>> 2.41.0
>>
On Wed, Oct 18, 2023 at 08:12:37PM +0000, Qing Zhao wrote:
> Marek,
>
> Sorry for the late comment (I was just back from a long vacation immediate after Cauldron).
No worries.
> One question:
>
> Is the option “-fhandened” for production build or for development build?
I intend -fhardened to be for production builds.
> If it’s for development build, then adding -ftrivial-auto-var-init=pattern is reasonable since the major purpose for -ftrivial-auto-var-init=pattern is for debugging, the runtime overhead of -ftrivial-auto-var-init=pattern is higher then -ftrivial-auto-var-init=zero.
>
> However, if it’s for production build, then adding -ftrivial-auto-var-init=zero is better since the major purpose for -ftrivial-auto-var-init=zero is for production build to eliminate all uninitialization. And the runtime overhead of =zero is smaller than =pattern.
Okay, I've changed the patch back to enabling -ftrivial-auto-var-init=zero.
In future C++ modes, we may have to default to -ftrivial-auto-var-init=zero
as per <http://wg21.link/P2723> anyway. On the other hand, it seems that
<https://wg21.link/p2795r3> might change that again...
Marek
On Thu, Oct 19, 2023 at 01:33:51PM +0100, Sam James wrote:
>
> Richard Biener <richard.guenther@gmail.com> writes:
>
> > On Wed, Oct 11, 2023 at 10:48 PM Marek Polacek <polacek@redhat.com> wrote:
> >>
> >> On Tue, Sep 19, 2023 at 10:58:19AM -0400, Marek Polacek wrote:
> >> > On Mon, Sep 18, 2023 at 08:57:39AM +0200, Richard Biener wrote:
> >> > > On Fri, Sep 15, 2023 at 5:09 PM Marek Polacek via Gcc-patches
> >> > > <gcc-patches@gcc.gnu.org> wrote:
> >> > > >
> >> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, powerpc64le-unknown-linux-gnu,
> >> > > > and aarch64-unknown-linux-gnu; ok for trunk?
> >> > > >
> >> > > > -- >8 --
> >> > > > In <https://gcc.gnu.org/pipermail/gcc-patches/2023-August/628748.html>
> >> > > > I proposed -fhardened, a new umbrella option that enables a reasonable set
> >> > > > of hardening flags. The read of the room seems to be that the option
> >> > > > would be useful. So here's a patch implementing that option.
> >> > > >
> >> > > > Currently, -fhardened enables:
> >> > > >
> >> > > > -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> >> > > > -D_GLIBCXX_ASSERTIONS
> >> > > > -ftrivial-auto-var-init=pattern
> >
> > I think =zero is much better here given the overhead is way
> > cheaper and pointers get a more reliable behavior.
>
> Yes please, as I wouldn't want us to use =pattern distro-wide.
Thanks for the feedback, I switched back to =zero.
Marek
@@ -1556,6 +1556,9 @@ c_finish_options (void)
cb_file_change (parse_in, cmd_map);
linemap_line_start (line_table, 0, 1);
+ bool fortify_seen_p = false;
+ bool cxx_assert_seen_p = false;
+
/* All command line defines must have the same location. */
cpp_force_token_locations (parse_in, line_table->highest_line);
for (size_t i = 0; i < deferred_count; i++)
@@ -1573,6 +1576,45 @@ c_finish_options (void)
else
cpp_assert (parse_in, opt->arg);
}
+
+ if (UNLIKELY (flag_hardened)
+ && (opt->code == OPT_D || opt->code == OPT_U))
+ {
+ if (!fortify_seen_p)
+ fortify_seen_p
+ = (!strncmp (opt->arg, "_FORTIFY_SOURCE", 15)
+ && (opt->arg[15] == '\0' || opt->arg[15] == '='));
+ if (!cxx_assert_seen_p)
+ cxx_assert_seen_p
+ = (!strncmp (opt->arg, "_GLIBCXX_ASSERTIONS", 19)
+ && (opt->arg[19] == '\0' || opt->arg[19] == '='));
+ }
+ }
+
+ if (flag_hardened)
+ {
+ if (!fortify_seen_p && optimize > 0)
+ {
+ if (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35)
+ cpp_define (parse_in, "_FORTIFY_SOURCE=3");
+ else
+ cpp_define (parse_in, "_FORTIFY_SOURCE=2");
+ }
+ else if (optimize == 0)
+ warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+ "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+ "because optimizations are turned off");
+ else
+ warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+ "%<_FORTIFY_SOURCE%> is not enabled by %<-fhardened%> "
+ "because it was specified in %<-D%> or %<-U%>");
+ if (!cxx_assert_seen_p)
+ cpp_define (parse_in, "_GLIBCXX_ASSERTIONS");
+ else
+ warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+ "%<_GLIBCXX_ASSERTIONS%> is not enabled by "
+ "%<-fhardened%> because it was specified in %<-D%> "
+ "or %<-U%>");
}
cpp_stop_forcing_token_locations (parse_in);
@@ -634,6 +634,10 @@ Wfree-nonheap-object
Common Var(warn_free_nonheap_object) Init(1) Warning
Warn when attempting to free a non-heap object.
+Whardened
+Common Var(warn_hardened) Init(1) Warning
+Warn when -fhardened did not enable an option from its set.
+
Whsa
Common Ignore Warning
Does nothing. Preserved for backward compatibility.
@@ -1827,6 +1831,10 @@ fharden-conditional-branches
Common Var(flag_harden_conditional_branches) Optimization
Harden conditional branches by checking reversed conditions.
+fhardened
+Common Driver Var(flag_hardened)
+Enable various security-relevant flags.
+
; Nonzero means ignore `#ident' directives. 0 means handle them.
; Generate position-independent code for executables if possible
; On SVR4 targets, it also controls whether or not to emit a
@@ -1676,6 +1676,12 @@
#endif
+/* Define 0/1 if your linker supports -z now */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_NOW_SUPPORT
+#endif
+
+
/* Define if your PowerPC64 linker only needs function descriptor syms. */
#ifndef USED_FOR_TARGET
#undef HAVE_LD_NO_DOT_SYMS
@@ -1719,6 +1725,12 @@
#endif
+/* Define 0/1 if your linker supports -z relro */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_RELRO_SUPPORT
+#endif
+
+
/* Define if your linker links a mix of read-only and read-write sections into
a read-write section. */
#ifndef USED_FOR_TARGET
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify-me.h"
#include "core-builtins.h"
+#include "opts.h"
/* Per-function machine data. */
struct GTY(()) machine_function
@@ -250,9 +251,10 @@ bpf_option_override (void)
/* Disable -fstack-protector as it is not supported in BPF. */
if (flag_stack_protect)
{
- inform (input_location,
- "%<-fstack-protector%> does not work "
- "on this architecture");
+ if (!flag_stack_protector_set_by_fhardened_p)
+ inform (input_location,
+ "%<-fstack-protector%> does not work "
+ "on this architecture");
flag_stack_protect = 0;
}
@@ -3061,10 +3061,25 @@ ix86_option_override_internal (bool main_args_p,
= build_target_option_node (opts, opts_set);
}
+ const bool cf_okay_p = (TARGET_64BIT || TARGET_CMOV);
+ /* When -fhardened, enable -fcf-protection=full, but only when it's
+ compatible with this target, and when it wasn't already specified
+ on the command line. */
+ if (opts->x_flag_hardened && cf_okay_p)
+ {
+ if (opts->x_flag_cf_protection == CF_NONE)
+ opts->x_flag_cf_protection = CF_FULL;
+ else if (opts->x_flag_cf_protection != CF_FULL)
+ warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+ "%<-fcf-protection=full%> is not enabled by "
+ "%<-fhardened%> because it was specified on the command "
+ "line");
+ }
+
if (opts->x_flag_cf_protection != CF_NONE)
{
if ((opts->x_flag_cf_protection & CF_BRANCH) == CF_BRANCH
- && !TARGET_64BIT && !TARGET_CMOV)
+ && !cf_okay_p)
error ("%<-fcf-protection%> is not compatible with this target");
opts->x_flag_cf_protection
@@ -32713,7 +32713,7 @@ if test x"$ld_is_gold" = xno; then
ld_bndplt_support=yes
fi
elif test x$gcc_cv_ld != x; then
- # Check if linker supports -a bndplt option
+ # Check if linker supports -z bndplt option
if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
ld_bndplt_support=yes
fi
@@ -32842,6 +32842,54 @@ $as_echo "#define ENABLE_S390_EXCESS_FLOAT_PRECISION 1" >>confdefs.h
;;
esac
+# Check if the linker supports '-z now'
+ld_now_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z now option" >&5
+$as_echo_n "checking linker -z now option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+ ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+ if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+ ld_now_support=yes
+ fi
+elif test x$gcc_cv_ld != x; then
+ # Check if linker supports -z now
+ if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+ ld_now_support=yes
+ fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_NOW_SUPPORT `if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_now_support" >&5
+$as_echo "$ld_now_support" >&6; }
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker -z relro option" >&5
+$as_echo_n "checking linker -z relro option... " >&6; }
+if test x"$ld_is_gold" = xyes; then
+ ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+ if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+ ld_relro_support=yes
+ fi
+elif test x$gcc_cv_ld != x; then
+ # Check if linker supports -z relro
+ if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+ ld_relro_support=yes
+ fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LD_RELRO_SUPPORT `if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_relro_support" >&5
+$as_echo "$ld_relro_support" >&6; }
+
# Configure the subdirectories
# AC_CONFIG_SUBDIRS($subdirs)
@@ -7678,7 +7678,7 @@ if test x"$ld_is_gold" = xno; then
ld_bndplt_support=yes
fi
elif test x$gcc_cv_ld != x; then
- # Check if linker supports -a bndplt option
+ # Check if linker supports -z bndplt option
if $gcc_cv_ld --help 2>&1 | grep -- '-z bndplt' > /dev/null; then
ld_bndplt_support=yes
fi
@@ -7779,6 +7779,46 @@ standards-compatible mode on s390 targets.])
;;
esac
+# Check if the linker supports '-z now'
+ld_now_support=no
+AC_MSG_CHECKING(linker -z now option)
+if test x"$ld_is_gold" = xyes; then
+ ld_now_support=yes
+elif test $in_tree_ld = yes ; then
+ if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 14 -o "$gcc_cv_gld_major_version" -gt 2; then
+ ld_now_support=yes
+ fi
+elif test x$gcc_cv_ld != x; then
+ # Check if linker supports -z now
+ if $gcc_cv_ld --help 2>&1 | grep -- '-z now' > /dev/null; then
+ ld_now_support=yes
+ fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_NOW_SUPPORT,
+ [`if test x"$ld_now_support" = xyes; then echo 1; else echo 0; fi`],
+ [Define 0/1 if your linker supports -z now])
+AC_MSG_RESULT($ld_now_support)
+
+# Check if the linker supports '-z relro'
+ld_relro_support=no
+AC_MSG_CHECKING(linker -z relro option)
+if test x"$ld_is_gold" = xyes; then
+ ld_relro_support=yes
+elif test $in_tree_ld = yes ; then
+ if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 15 -o "$gcc_cv_gld_major_version" -gt 2; then
+ ld_relro_support=yes
+ fi
+elif test x$gcc_cv_ld != x; then
+ # Check if linker supports -z relro
+ if $gcc_cv_ld --help 2>&1 | grep -- '-z relro' > /dev/null; then
+ ld_relro_support=yes
+ fi
+fi
+AC_DEFINE_UNQUOTED(HAVE_LD_RELRO_SUPPORT,
+ [`if test x"$ld_relro_support" = xyes; then echo 1; else echo 0; fi`],
+ [Define 0/1 if your linker supports -z relro])
+AC_MSG_RESULT($ld_relro_support)
+
# Configure the subdirectories
# AC_CONFIG_SUBDIRS($subdirs)
@@ -366,7 +366,7 @@ Objective-C and Objective-C++ Dialects}.
-Wformat-y2k -Wframe-address
-Wframe-larger-than=@var{byte-size} -Wno-free-nonheap-object
-Wno-if-not-aligned -Wno-ignored-attributes
--Wignored-qualifiers -Wno-incompatible-pointer-types
+-Wignored-qualifiers -Wno-incompatible-pointer-types -Whardened
-Wimplicit -Wimplicit-fallthrough -Wimplicit-fallthrough=@var{n}
-Wno-implicit-function-declaration -Wno-implicit-int
-Winfinite-recursion
@@ -640,7 +640,7 @@ Objective-C and Objective-C++ Dialects}.
-fasan-shadow-offset=@var{number} -fsanitize-sections=@var{s1},@var{s2},...
-fsanitize-undefined-trap-on-error -fbounds-check
-fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]}
--fharden-compares -fharden-conditional-branches
+-fharden-compares -fharden-conditional-branches -fhardened
-fstack-protector -fstack-protector-all -fstack-protector-strong
-fstack-protector-explicit -fstack-check
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym}
@@ -6842,6 +6842,18 @@ This warning is upgraded to an error by @option{-pedantic-errors}.
Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}.
This warning is enabled by @option{-Wall}.
+@opindex Whardened
+@opindex Wno-hardened
+@item -Whardened
+Warn when @option{-fhardened} did not enable an option from its set (for
+which see @option{-fhardened}). For instance, using @option{-fhardened}
+and @option{-fstack-protector} at the same time on the command line causes
+@option{-Whardened} to warn because @option{-fstack-protector-strong} is
+not enabled by @option{-fhardened}.
+
+This warning is enabled by default and has effect only when @option{-fhardened}
+is enabled.
+
@opindex Wimplicit-fallthrough
@opindex Wno-implicit-fallthrough
@item -Wimplicit-fallthrough
@@ -17427,6 +17439,34 @@ condition, and to call @code{__builtin_trap} if the result is
unexpected. Use with @samp{-fharden-compares} to cover all
conditionals.
+@opindex fhardened
+@item -fhardened
+Enable a set of flags for C and C++ that improve the security of the
+generated code without affecting its ABI. The precise flags enabled
+may change between major releases of GCC, but are currently:
+
+@c Keep this in sync with print_help_hardened!
+@gccoptlist{
+-D_FORTIFY_SOURCE=3
+-D_GLIBCXX_ASSERTIONS
+-ftrivial-auto-var-init=pattern
+-fPIE -pie -Wl,-z,relro,-z,now
+-fstack-protector-strong
+-fstack-clash-protection
+-fcf-protection=full @r{(x86 GNU/Linux only)}
+}
+
+The list of options enabled by @option{-fhardened} can be generated using
+the @option{--help=hardened} option.
+
+When the system glibc is older than 2.35, @option{-D_FORTIFY_SOURCE=2}
+is used instead.
+
+@option{-fhardened} only enables a particular option if it wasn't
+already specified anywhere on the command line. For instance,
+@option{-fhardened} @option{-fstack-protector} will only enable
+@option{-fstack-protector}, but not @option{-fstack-protector-strong}.
+
@opindex fstack-protector
@item -fstack-protector
Emit extra code to check for buffer overflows, such as stack smashing
@@ -302,6 +302,13 @@ static size_t dumpdir_length = 0;
driver added to dumpdir after dumpbase or linker output name. */
static bool dumpdir_trailing_dash_added = false;
+/* True if -r, -shared, -pie, or -no-pie were specified on the command
+ line. */
+static bool any_link_options_p;
+
+/* True if -static was specified on the command line. */
+static bool static_p;
+
/* Basename of dump and aux outputs, computed from dumpbase (given or
derived from output name), to override input_basename in non-%w %b
et al. */
@@ -4601,10 +4608,20 @@ driver_handle_option (struct gcc_options *opts,
save_switch ("-o", 1, &arg, validated, true);
return true;
-#ifdef ENABLE_DEFAULT_PIE
case OPT_pie:
+#ifdef ENABLE_DEFAULT_PIE
/* -pie is turned on by default. */
+ validated = true;
#endif
+ case OPT_r:
+ case OPT_shared:
+ case OPT_no_pie:
+ any_link_options_p = true;
+ break;
+
+ case OPT_static:
+ static_p = true;
+ break;
case OPT_static_libgcc:
case OPT_shared_libgcc:
@@ -4980,6 +4997,35 @@ process_command (unsigned int decoded_options_count,
#endif
}
+ /* TODO: check if -static -pie works and maybe use it. */
+ if (flag_hardened)
+ {
+ if (!any_link_options_p && !static_p)
+ {
+#ifdef HAVE_LD_PIE
+ save_switch (LD_PIE_SPEC, 0, NULL, /*validated=*/true, /*known=*/false);
+#endif
+ /* These are passed straight down to collect2 so we have to break
+ it up like this. */
+ if (HAVE_LD_NOW_SUPPORT)
+ {
+ add_infile ("-z", "*");
+ add_infile ("now", "*");
+ }
+ if (HAVE_LD_RELRO_SUPPORT)
+ {
+ add_infile ("-z", "*");
+ add_infile ("relro", "*");
+ }
+ }
+ /* We can't use OPT_Whardened yet. Sigh. */
+ else if (warn_hardened)
+ warning_at (UNKNOWN_LOCATION, 0,
+ "linker hardening options not enabled by %<-fhardened%> "
+ "because other link options were specified on the command "
+ "line");
+ }
+
/* Handle -gtoggle as it would later in toplev.cc:process_options to
make the debug-level-gt spec function work as expected. */
if (flag_gtoggle)
@@ -43,6 +43,10 @@ along with GCC; see the file COPYING3. If not see
/* Set by -fcanon-prefix-map. */
bool flag_canon_prefix_map;
+/* Set by finish_options when flag_stack_protector was set only because of
+ -fhardened. Yuck. */
+bool flag_stack_protector_set_by_fhardened_p;
+
static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
/* Names of fundamental debug info formats indexed by enum
@@ -1093,6 +1097,17 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
opts->x_flag_section_anchors = 0;
}
+ if (opts->x_flag_hardened)
+ {
+ if (!opts_set->x_flag_auto_var_init)
+ opts->x_flag_auto_var_init = AUTO_INIT_PATTERN;
+ else if (opts->x_flag_auto_var_init != AUTO_INIT_PATTERN)
+ warning_at (loc, OPT_Whardened,
+ "%<-ftrivial-auto-var-init=pattern%> is not enabled by "
+ "%<-fhardened%> because it was specified on the command "
+ "line");
+ }
+
if (!opts->x_flag_opts_finished)
{
/* We initialize opts->x_flag_pie to -1 so that targets can set a
@@ -1102,7 +1117,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
/* We initialize opts->x_flag_pic to -1 so that we can tell if
-fpic, -fPIC, -fno-pic or -fno-PIC is used. */
if (opts->x_flag_pic == -1)
- opts->x_flag_pie = DEFAULT_FLAG_PIE;
+ opts->x_flag_pie = (opts->x_flag_hardened
+ ? /*-fPIE*/ 2 : DEFAULT_FLAG_PIE);
else
opts->x_flag_pie = 0;
}
@@ -1117,9 +1133,29 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
}
/* We initialize opts->x_flag_stack_protect to -1 so that targets
- can set a default value. */
+ can set a default value. With --enable-default-ssp or -fhardened
+ the default is -fstack-protector-strong. */
if (opts->x_flag_stack_protect == -1)
- opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+ {
+ /* This should check FRAME_GROWS_DOWNWARD, but on some targets it's
+ defined in such a way that it uses flag_stack_protect which can't
+ be used here. Moreover, some targets like BPF don't support
+ -fstack-protector at all but we don't know that here. So remember
+ that flag_stack_protect was set at the behest of -fhardened. */
+ if (opts->x_flag_hardened)
+ {
+ opts->x_flag_stack_protect = SPCT_FLAG_STRONG;
+ flag_stack_protector_set_by_fhardened_p = true;
+ }
+ else
+ opts->x_flag_stack_protect = DEFAULT_FLAG_SSP;
+ }
+ else if (opts->x_flag_hardened
+ && opts->x_flag_stack_protect != SPCT_FLAG_STRONG)
+ warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+ "%<-fstack-protector-strong%> is not enabled by "
+ "%<-fhardened%> because it was specified on the command "
+ "line");
if (opts->x_optimize == 0)
{
@@ -2461,6 +2497,29 @@ parse_and_check_patch_area (const char *arg, bool report_error,
free (patch_area_arg);
}
+/* Print options enabled by -fhardened. Keep this in sync with the manual! */
+
+static void
+print_help_hardened ()
+{
+ printf ("%s\n", "The following options are enabled by -fhardened:");
+ printf (" %s=%d\n", "-D_FORTIFY_SOURCE",
+ (TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) ? 3 : 2);
+ printf (" %s\n", "-D_GLIBCXX_ASSERTIONS");
+ printf (" %s\n", "-ftrivial-auto-var-init=pattern");
+#ifdef HAVE_LD_PIE
+ printf (" %s %s\n", "-fPIE", "-pie");
+#endif
+ if (HAVE_LD_NOW_SUPPORT)
+ printf (" %s\n", "-Wl,-z,now");
+ if (HAVE_LD_RELRO_SUPPORT)
+ printf (" %s\n", "-Wl,-z,relro");
+ printf (" %s\n", "-fstack-protector-strong");
+ printf (" %s\n", "-fstack-clash-protection");
+ printf (" %s\n", "-fcf-protection=full");
+ putchar ('\n');
+}
+
/* Print help when OPT__help_ is set. */
void
@@ -2576,6 +2635,8 @@ print_help (struct gcc_options *opts, unsigned int lang_mask,
}
else if (lang_flag != 0)
*pflags |= lang_flag;
+ else if (strncasecmp (a, "hardened", len) == 0)
+ print_help_hardened ();
else
warning (0,
"unrecognized argument to %<--help=%> option: %q.*s",
@@ -344,6 +344,7 @@ struct cl_option_handlers
/* Hold command-line options associated with stack limitation. */
extern const char *opt_fstack_limit_symbol_arg;
extern int opt_fstack_limit_register_no;
+extern bool flag_stack_protector_set_by_fhardened_p;
/* Input file names. */
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do preprocess { target pie } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O" } */
+
+#ifndef __SSP_STRONG__
+# error "-fstack-protector-strong not enabled"
+#endif
+
+#if _FORTIFY_SOURCE < 2
+# error "_FORTIFY_SOURCE not enabled"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS not enabled"
+#endif
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -D_FORTIFY_SOURCE=1" } */
+
+#if _FORTIFY_SOURCE != 1
+# error "_FORTIFY_SOURCE != 1"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -D_FORTIFY_SOURCE_ -D_GLIBCXX_ASSERTIONS_" } */
+
+#ifndef _FORTIFY_SOURCE
+# error "_FORTIFY_SOURCE disabled when it should not be"
+#endif
+
+#ifndef _GLIBCXX_ASSERTIONS
+# error "_GLIBCXX_ASSERTIONS disabled when it should not be"
+#endif
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+ int i;
+ return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O" } */
+
+#if __PIE__ != 2
+# error "-fPIE not enabled"
+#endif
new file mode 100644
@@ -0,0 +1,6 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fno-PIE" } */
+
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-require-stack-check "specific" } */
+/* { dg-options "-fhardened -O -fstack-check" } */
+
+/* { dg-warning ".-fstack-clash-protection. is not enabled by .-fhardened. because .-fstack-check. was specified" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -fstack-protector" } */
+
+#ifdef __SSP_STRONG__
+# error "-fstack-protector-strong enabled when it should not be"
+#endif
+#ifndef __SSP__
+# error "-fstack-protector not enabled"
+#endif
+
+/* { dg-warning ".-fstack-protector-strong. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O0" } */
+/* Test that we don't get any diagnostic coming from libc headers. */
+
+#include <stdio.h>
+
+/* The most useful C program known to man. */
+
+int
+main ()
+{
+}
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O0 -Wno-hardened" } */
+
+/* { dg-bogus "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+ int i;
+ return i;
+}
+
+/* { dg-final { scan-tree-dump ".DEFERRED_INIT" "gimple" } } */
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -O -ftrivial-auto-var-init=uninitialized -fdump-tree-gimple" } */
+
+int
+foo ()
+{
+ int i;
+ return i;
+}
+
+/* { dg-final { scan-tree-dump-not ".DEFERRED_INIT" "gimple" } } */
+/* { dg-warning ".-ftrivial-auto-var-init=pattern. is not enabled" "" { target *-*-* } 0 } */
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fpie" } */
+
+/* -fpie takes precedence over -fhardened */
+#if __PIE__ != 1
+# error "__PIE__ != 1"
+#endif
new file mode 100644
@@ -0,0 +1,7 @@
+/* { dg-do compile { target pie } } */
+/* { dg-options "-fhardened -O -fPIC" } */
+
+/* -fPIC takes precedence over -fhardened */
+#ifdef __PIE__
+# error "PIE enabled when it should not be"
+#endif
new file mode 100644
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-fhardened -U_FORTIFY_SOURCE -U_GLIBCXX_ASSERTIONS" } */
+
+#if defined(_FORTIFY_SOURCE) || defined(_GLIBCXX_ASSERTIONS)
+# error "hardening enabled when it should not be"
+#endif
+
+/* { dg-warning "._FORTIFY_SOURCE. is not enabled" "" { target *-*-* } 0 } */
+/* { dg-warning "._GLIBCXX_ASSERTIONS. is not enabled" "" { target *-*-* } 0 } */
@@ -151,6 +151,8 @@ foreach cls { "ada" "c" "c++" "d" "fortran" "go" \
# Listing only excludes gives empty results.
check_for_options c "--help=^joined,^separate" "" "" ""
+check_for_options c "--help=hardened" "The following options are enabled by -fhardened" "" ""
+
if [ info exists prev_columns ] {
# Reset the enviroment variable to its oriuginal value.
set env(COLUMNS) $prev_columns
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fhardened -mno-manual-endbr" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+/* Test that -fhardened enables CET. */
+
+extern void bar (void) __attribute__((__cf_check__));
+
+void
+foo (void)
+{
+ bar ();
+}
@@ -1575,6 +1575,19 @@ process_options (bool no_backend)
"where the stack grows from lower to higher addresses");
flag_stack_clash_protection = 0;
}
+ else if (flag_hardened)
+ {
+ if (!flag_stack_clash_protection
+ /* Don't enable -fstack-clash-protection when -fstack-check=
+ is used: it would result in confusing errors. */
+ && flag_stack_check == NO_STACK_CHECK)
+ flag_stack_clash_protection = 1;
+ else if (flag_stack_check != NO_STACK_CHECK)
+ warning_at (UNKNOWN_LOCATION, OPT_Whardened,
+ "%<-fstack-clash-protection%> is not enabled by "
+ "%<-fhardened%> because %<-fstack-check%> was "
+ "specified on the command line");
+ }
/* We cannot support -fstack-check= and -fstack-clash-protection at
the same time. */
@@ -1590,8 +1603,9 @@ process_options (bool no_backend)
target already uses a soft frame pointer, the transition is trivial. */
if (!FRAME_GROWS_DOWNWARD && flag_stack_protect)
{
- warning_at (UNKNOWN_LOCATION, 0,
- "%<-fstack-protector%> not supported for this target");
+ if (!flag_stack_protector_set_by_fhardened_p)
+ warning_at (UNKNOWN_LOCATION, 0,
+ "%<-fstack-protector%> not supported for this target");
flag_stack_protect = 0;
}
if (!flag_stack_protect)