From patchwork Thu Nov 16 20:51:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 165938 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9910:0:b0:403:3b70:6f57 with SMTP id i16csp108157vqn; Thu, 16 Nov 2023 12:52:04 -0800 (PST) X-Google-Smtp-Source: AGHT+IEv8E3yd7SY3t1WLslH3iSTio6+mf4/8MHpL96qDOgVSR5M43xipCZDULdwLbwSKFvIUCes X-Received: by 2002:a05:6214:326:b0:66d:630a:79b9 with SMTP id j6-20020a056214032600b0066d630a79b9mr9355317qvu.40.1700167923933; Thu, 16 Nov 2023 12:52:03 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1700167923; cv=pass; d=google.com; s=arc-20160816; b=JTQstaQ2rBxzHjrnbzNIH+y8YEp4NGBTsuSpuXD19jAxFbY/FKfMVpgV1flDB+Cbkp wbcNK8uuV13NrLOw1umQ+8qOrB9/6PAAd68/oVGSg6oOjzXxBBDOR3KIz1Niw80YEGjP OE688u1ctmKtwHHkT5Mq/jT67+5p9HBFCcrkLNh19rRFhBsQtPs3fDtUdvGpWWQE6PrD dHLsTERMNvbN0GQS7PGflZf9oXfHdx1NBIKX35Gz6nlSBmNluMia7TBwQbKAQjNKyFcY 64DvSpHQ35GkadLEgXjthHla5km9DjczN/RElIcNA9sitBey/vn0twXD/HVPopQlDc2o HmCw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-disposition:user-agent :in-reply-to:mime-version:references:message-id:subject:cc:to:from :date:dkim-signature:arc-filter:dmarc-filter:delivered-to; bh=xATfUJG8B2Z70IZJ0Tnq9vh3aRNJL4iYqCkjmro3IuU=; fh=psfp+8DgTtLrtnRIgV7/upUO6h8BOKJwhaKumhKDaRQ=; b=sbijdCyqfjulCZXlh+kbvKwHK19Yco+aCoNea3LSFF6HEO2TBpj7Gm5X8c1DMf/Pom haQxPYyvy/6rOXAoNi+crQhNI30PC+G2PDGj0C8ecpatMshj0lSUYm8OCMxlB/zWi28T h1N0clIjPnZV/QAkN4vjnkPwM51yNlzU6qrIanA+VG0eVziSgNTMCzo6wvI1smO4diep 1srsO+xwSM6c27mN57pkdGE1whKptZnrvH/4DMRGmKhAJAlV5VnleP4WMWBfDvBN8rh1 InibsY95wnv8pm9SG7vLYOdzYSL69ZXpS3Z1FoXhu2XogA35L1CZ0qhh2QoP8DNKZF6f c4Bw== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=ibfoNS6k; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id m8-20020ad45dc8000000b006708e35d522si204396qvh.200.2023.11.16.12.52.03 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 12:52:03 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=ibfoNS6k; arc=pass (i=1); spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AB39B3857BB7 for ; Thu, 16 Nov 2023 20:52:03 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 6E1EF3858CD1 for ; Thu, 16 Nov 2023 20:51:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6E1EF3858CD1 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6E1EF3858CD1 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700167895; cv=none; b=oyMxPeMHOQq6yb87NnzyMzG8jOfq+UgzCIouclCakKeq0TJxqR+zkAqL116YOQCfHJQlAJjwmb+UyDQH4pc+IkKLbqaibjebagbpG5aK/AUn0Z7mfS+/ezrhx3WvgdG/zlHmJEwkNwfluG2BN1THL8L7TzhH07fS98GX7g4omVY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700167895; c=relaxed/simple; bh=HmHgZjqTZleN48w/FwSN+ZjqzqEzG6x94U1+3mTiscs=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=LWk06F2fWPEKXvZ287CpHgb9xLpfaubF2qtW8ia4De8arAyHGw2vj6gtn6t9F0USw526sX93fex1iOFBA6f8tRsMBWlHPy1pHeJdoQhxxWDV27E6p/xIbMWfUszq/yW1vPhQQ7Ciet2uhSPxazrZyS9fAaD+n0FhYGT2Bx20ZSg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1700167889; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=xATfUJG8B2Z70IZJ0Tnq9vh3aRNJL4iYqCkjmro3IuU=; b=ibfoNS6kFoEjtkGwchYsTjHtaYGku7ToVmUJ4KxLf0wslAZNn9F0spxdXP5NEIGgTs3v6S duxdIwYzxncT8PVTEdpa2AwpDS2ErpgW4m/3uWcKcnKCckBfCpjU/EjDbD96pjyo5SlPiz xczjBkhWMEJb0qepMwpEqfamv0/LUXs= Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-650-etmwaSx1NV2lDD1F4NwG5Q-1; Thu, 16 Nov 2023 15:51:27 -0500 X-MC-Unique: etmwaSx1NV2lDD1F4NwG5Q-1 Received: by mail-qv1-f70.google.com with SMTP id 6a1803df08f44-677e7daa85fso11393106d6.2 for ; Thu, 16 Nov 2023 12:51:27 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700167887; x=1700772687; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xATfUJG8B2Z70IZJ0Tnq9vh3aRNJL4iYqCkjmro3IuU=; b=Aic14rvOZmHCVCS5CKFCnShOeE1Rw4Uc4eCF0sKI0cdgQJaS4nIpuxancRlh3ie8Wy 3xAFgggNdFth9a5RX42wDnIDv95xWB10l9xGIlKqBDisdgtwdSYtEJXox9YwgPGvNe9T PC6cfUlEZje8kfWYtQVeAWwsdV54XAXpIH0eXMl0EgR0juGe1rxNoC3LRfSxGaBeQfJ+ s10xP/M3HoOdacgPSfRni2Nwsaopw310YcGAhhI47cbbIYuQjzvaM0Gpgxbz+oObtrCs id/iUnJUbqunT8qeppewMQ5d34GFQnZ94kyZGovFuoFW2HsWA7CvLJGldub2aln+HJIr 5uYw== X-Gm-Message-State: AOJu0Yx4Dbe3Zys3p34Mn9ZFGwmfAR8dicqWYttn2/PMRcFbmBPdyxcZ mKdbCLnplLT0DkB7GU1kcql7MgLt20kP8Aqko58UzCg79BUcUNAp+1QukrA6RIJ48DLddShiRKg ySVbV+LEUVTMrFS88IQ== X-Received: by 2002:a0c:ef47:0:b0:66d:6526:d605 with SMTP id t7-20020a0cef47000000b0066d6526d605mr8988796qvs.63.1700167886035; Thu, 16 Nov 2023 12:51:26 -0800 (PST) X-Received: by 2002:a0c:ef47:0:b0:66d:6526:d605 with SMTP id t7-20020a0cef47000000b0066d6526d605mr8988767qvs.63.1700167885146; Thu, 16 Nov 2023 12:51:25 -0800 (PST) Received: from redhat.com (2603-7000-9500-34a5-0000-0000-0000-1db4.res6.spectrum.com. [2603:7000:9500:34a5::1db4]) by smtp.gmail.com with ESMTPSA id y18-20020ad45312000000b0065aff6b49afsm61430qvr.110.2023.11.16.12.51.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Nov 2023 12:51:24 -0800 (PST) Date: Thu, 16 Nov 2023 15:51:22 -0500 From: Marek Polacek To: Jakub Jelinek Cc: Richard Biener , iain@sandoe.co.uk, GCC Patches Subject: [PATCH v5] gcc: Introduce -fhardened Message-ID: References: <8A3E5AA3-0785-4C2E-B75B-9388B703FFEA@gmail.com> MIME-Version: 1.0 In-Reply-To: User-Agent: Mutt/2.2.9 (2022-11-12) X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SORBS_WEB, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1777116715325110448 X-GMAIL-MSGID: 1782755281094337558 On Wed, Nov 15, 2023 at 01:25:27PM +0100, Jakub Jelinek wrote: > On Fri, Nov 03, 2023 at 06:51:16PM -0400, Marek Polacek wrote: > > + 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"); > > + } > > I don't like the above in generic code, the fact that gcc was configured > against glibc target headers doesn't mean it is targetting glibc. > E.g. for most *-linux* targets, config/linux.opt provides the > -mbionic/-mglibc/-muclibc/-mmusl options. > > One ugly way around would be to do > #ifdef OPTION_GLIBC > if (OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) > cpp_define (parse_in, "_FORTIFY_SOURCE=3"); > else > #endif > cpp_define (parse_in, "_FORTIFY_SOURCE=2"); > (assuming OPTION_GLIBC at that point is already computed); a cleaner way > would be to introduce a target hook for that, say > fortify_source_default_level or something similar, where the default hook > would return 2 and next to linux_libc_has_function one would override it > for OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35 > to 3. That way, in the future other targets (say *BSD) can choose to do > something similar more easily. Thanks, that's a good point. In this version I've added a target hook. On my system, -D_FORTIFY_SOURCE=3 will be used, and if I remove linux_fortify_source_default_level it's =2 as expected. The only problem was that it doesn't seem to be possible to use targetm. in opts.cc -- I get an undefined reference. But since the opts.cc use is for --help only, it's not a big deal either way. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- In 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=zero -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. Currently, -fhardened is only supported on GNU/Linux. 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: Include "target.h". (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. * config/linux-protos.h (linux_fortify_source_default_level): Declare. * config/linux.cc (linux_fortify_source_default_level): New. * config/linux.h (TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL): Redefine. * configure: Regenerate. * configure.ac: Check if the linker supports '-z now' and '-z relro'. Check if -fhardened is supported on $target_os. * doc/invoke.texi: Document -fhardened and -Whardened. * doc/tm.texi: Regenerate. * doc/tm.texi.in (TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL): Add. * 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=zero and -fstack-protector-strong. (print_help_hardened): New. (print_help): Call it. * target.def (fortify_source_default_level): New target hook. * targhooks.cc (default_fortify_source_default_level): New. * targhooks.h (default_fortify_source_default_level): Declare. * 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. Don't enable -fhardened when !HAVE_FHARDENED_SUPPORT. 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 | 39 +++++++++++++ gcc/common.opt | 8 +++ gcc/config.in | 18 ++++++ gcc/config/bpf/bpf.cc | 8 ++- gcc/config/i386/i386-options.cc | 17 +++++- gcc/config/linux-protos.h | 1 + gcc/config/linux.cc | 9 +++ gcc/config/linux.h | 3 + gcc/configure | 68 +++++++++++++++++++++- gcc/configure.ac | 57 +++++++++++++++++- gcc/doc/invoke.texi | 49 +++++++++++++++- gcc/doc/tm.texi | 5 ++ gcc/doc/tm.texi.in | 2 + gcc/gcc.cc | 48 ++++++++++++++- gcc/opts.cc | 68 +++++++++++++++++++++- gcc/opts.h | 1 + gcc/target.def | 7 +++ gcc/targhooks.cc | 8 +++ gcc/targhooks.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 | 25 +++++++- 38 files changed, 588 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: a671095c208c7cf5eb934b6a31bd9fb6f6640a6b diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 10403c03bd6..d7faff10d66 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" +#include "target.h" #include "c-target.h" #include "c-common.h" #include "memmodel.h" @@ -1573,6 +1574,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++) @@ -1590,6 +1594,41 @@ 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) + cpp_define_formatted (parse_in, "_FORTIFY_SOURCE=%u", + targetm.fortify_source_default_level ()); + 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 d21db5d4a20..6dafe51e9f3 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. @@ -1819,6 +1823,10 @@ fguess-branch-probability Common Var(flag_guess_branch_prob) Optimization Enable guessing of branch probabilities. +fhardened +Common Driver Var(flag_hardened) +Enable various security-relevant flags. + fharden-compares Common Var(flag_harden_compares) Optimization Harden conditionals not used in branches, checking reversed conditions. diff --git a/gcc/config.in b/gcc/config.in index 866f9fff101..fb45b556fb0 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1326,6 +1326,12 @@ #endif +/* Define 0/1 if -fhardened is supported */ +#ifndef USED_FOR_TARGET +#undef HAVE_FHARDENED_SUPPORT +#endif + + /* Define to 1 if you have the `fileno_unlocked' function. */ #ifndef USED_FOR_TARGET #undef HAVE_FILENO_UNLOCKED @@ -1734,6 +1740,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 @@ -1777,6 +1789,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 a0956a06972..223a43cbbb3 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 df7d24352d1..76adba672b9 100644 --- a/gcc/config/i386/i386-options.cc +++ b/gcc/config/i386/i386-options.cc @@ -3072,10 +3072,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/config/linux-protos.h b/gcc/config/linux-protos.h index f2ea930ace7..834249867f7 100644 --- a/gcc/config/linux-protos.h +++ b/gcc/config/linux-protos.h @@ -22,3 +22,4 @@ extern bool linux_has_ifunc_p (void); extern bool linux_libc_has_function (enum function_class fn_class, tree); extern unsigned linux_libm_function_max_error (unsigned, machine_mode, bool); +extern unsigned linux_fortify_source_default_level (); diff --git a/gcc/config/linux.cc b/gcc/config/linux.cc index 9114e55d44e..c8df6c7d840 100644 --- a/gcc/config/linux.cc +++ b/gcc/config/linux.cc @@ -49,3 +49,12 @@ linux_libm_function_max_error (unsigned cfn, machine_mode mode, return glibc_linux_libm_function_max_error (cfn, mode, boundary_p); return default_libm_function_max_error (cfn, mode, boundary_p); } + +unsigned +linux_fortify_source_default_level () +{ + if (OPTION_GLIBC && TARGET_GLIBC_MAJOR == 2 && TARGET_GLIBC_MINOR >= 35) + return 3; + + return 2; +} diff --git a/gcc/config/linux.h b/gcc/config/linux.h index ac56816bfca..79b6537dcf1 100644 --- a/gcc/config/linux.h +++ b/gcc/config/linux.h @@ -216,3 +216,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see # define TARGET_LIBM_FUNCTION_MAX_ERROR linux_libm_function_max_error #endif + +#undef TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL +#define TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL linux_fortify_source_default_level diff --git a/gcc/configure b/gcc/configure index ee97934ac4f..a02c23ae917 100755 --- a/gcc/configure +++ b/gcc/configure @@ -34583,7 +34583,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 @@ -34712,6 +34712,72 @@ $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; } + +case $target_os in +linux* | gnu*) + # -fhardened is only supported on GNU/Linux. + fhardened_support=yes + ;; +*) + fhardened_support=no + ;; +esac + + +cat >>confdefs.h <<_ACEOF +#define HAVE_FHARDENED_SUPPORT `if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi` +_ACEOF + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fhardened_support" >&5 +$as_echo "$fhardened_support" >&6; } + # Configure the subdirectories # AC_CONFIG_SUBDIRS($subdirs) diff --git a/gcc/configure.ac b/gcc/configure.ac index d0caf820648..86f1a4b9e4c 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -7741,7 +7741,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 @@ -7842,6 +7842,61 @@ 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) + +case $target_os in +linux* | gnu*) + # -fhardened is only supported on GNU/Linux. + fhardened_support=yes + ;; +*) + fhardened_support=no + ;; +esac + +AC_DEFINE_UNQUOTED(HAVE_FHARDENED_SUPPORT, + [`if test x"$fhardened_support" = xyes; then echo 1; else echo 0; fi`], + [Define 0/1 if -fhardened is supported]) +AC_MSG_RESULT($fhardened_support) + # Configure the subdirectories # AC_CONFIG_SUBDIRS($subdirs) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1748afdbfe0..035adaa9dbf 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 @@ -641,7 +641,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 -fharden-control-flow-redundancy -fhardcfr-skip-leaf -fhardcfr-check-exceptions -fhardcfr-check-returning-calls -fhardcfr-check-noreturn-calls=@r{[}always@r{|}no-xthrow@r{|}nothrow@r{|}never@r{]} @@ -6869,6 +6869,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 @@ -17535,6 +17547,39 @@ made @option{no-xthrow} the default setting for this option: it excludes from the @code{noreturn} treatment only internal functions used to (re)raise exceptions, that are not affected by these optimizations. +@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=zero +-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. + +This option is intended to be used in production builds, not merely +in debug builds. + +Currently, @option{-fhardened} is only supported on GNU/Linux targets. + +@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/doc/tm.texi b/gcc/doc/tm.texi index d83ca73b1af..864aa210db0 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -5822,6 +5822,11 @@ This hook determines whether a function from a class of functions @code{(enum function_class)}@var{fcode} has a fast implementation. @end deftypefn +@deftypefn {Target Hook} unsigned TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL (void) +This hook determines what value _FORTIFY_SOURCE will be set to when using +the command-line option -fhardened. +@end deftypefn + @deftypefn {Target Hook} unsigned TARGET_LIBM_FUNCTION_MAX_ERROR (unsigned @var{cfn}, machine_mode @var{mode}, bool @var{boundary_p}) This hook determines expected maximum errors for math functions measured in ulps (units of the last place). 0 means 0.5ulps precision (correctly diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 3d3ae12cc2f..245058eb887 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -4043,6 +4043,8 @@ macro, a reasonable default is used. @hook TARGET_LIBC_HAS_FAST_FUNCTION +@hook TARGET_FORTIFY_SOURCE_DEFAULT_LEVEL + @hook TARGET_LIBM_FUNCTION_MAX_ERROR @defmac NEXT_OBJC_RUNTIME diff --git a/gcc/gcc.cc b/gcc/gcc.cc index 51120c1489e..9f21ad9453e 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. */ @@ -4605,10 +4612,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: @@ -4984,6 +5001,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 33165c9e74f..5d5efaf1b9e 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -42,6 +42,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 @@ -1092,6 +1096,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_ZERO; + else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO) + warning_at (loc, OPT_Whardened, + "%<-ftrivial-auto-var-init=zero%> 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 @@ -1101,7 +1116,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; } @@ -1116,9 +1132,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) { @@ -2460,6 +2496,30 @@ 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:"); + /* Unfortunately, I can't seem to use targetm.fortify_source_default_level + here. */ + printf (" %s\n", "-D_FORTIFY_SOURCE=3 (or =2 for glibc < 2.35)"); + printf (" %s\n", "-D_GLIBCXX_ASSERTIONS"); + printf (" %s\n", "-ftrivial-auto-var-init=zero"); +#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 @@ -2575,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/target.def b/gcc/target.def index 0996da0f71a..579b9325212 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -2670,6 +2670,13 @@ DEFHOOK bool, (int fcode), default_libc_has_fast_function) +DEFHOOK +(fortify_source_default_level, + "This hook determines what value _FORTIFY_SOURCE will be set to when using\n\ +the command-line option -fhardened.", + unsigned, (void), + default_fortify_source_default_level) + DEFHOOK (libm_function_max_error, "This hook determines expected maximum errors for math functions measured\n\ diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc index 4f5b240f8d6..6680e8ee1b7 100644 --- a/gcc/targhooks.cc +++ b/gcc/targhooks.cc @@ -1906,6 +1906,14 @@ bsd_libc_has_function (enum function_class fn_class, return false; } +/* By default, -fhardened will add -D_FORTIFY_SOURCE=2. */ + +unsigned +default_fortify_source_default_level () +{ + return 2; +} + unsigned default_libm_function_max_error (unsigned, machine_mode, bool) { diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 189549cb1c7..26a8297c785 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -219,6 +219,7 @@ extern bool default_libc_has_fast_function (int fcode); extern bool no_c99_libc_has_function (enum function_class, tree); extern bool gnu_libc_has_function (enum function_class, tree); extern bool bsd_libc_has_function (enum function_class, tree); +extern unsigned default_fortify_source_default_level (void); extern unsigned default_libm_function_max_error (unsigned, machine_mode, bool); extern unsigned glibc_linux_libm_function_max_error (unsigned, machine_mode, bool); 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..9d0a5772d9e --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-1.S @@ -0,0 +1,6 @@ +/* { dg-do preprocess { target { { *-*-linux* *-*-gnu* } && 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..7e6740655fe --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..badebc56440 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-10.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..d1a973d177a --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-11.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..eb128f61ba3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-12.c @@ -0,0 +1,11 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..8722e6d4b1a --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-13.c @@ -0,0 +1,6 @@ +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && 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..04d6c8ff954 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-14.c @@ -0,0 +1,6 @@ +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && 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..86dc5220159 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-15.c @@ -0,0 +1,5 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..280ff96eb15 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..f2306ca5d33 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-3.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { dg-options "-fhardened -O0" } */ +/* Test that we don't get any diagnostic coming from libc headers. */ + +#include + +/* 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..312fabb95a5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-4.c @@ -0,0 +1,4 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..eb128f61ba3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-5.c @@ -0,0 +1,11 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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..d3cb7c8b353 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-6.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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=zero. 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..b47bf43f360 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-7.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && 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..85c9ad9103f --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-8.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target { { *-*-linux* *-*-gnu* } && 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..4e4131f0bdd --- /dev/null +++ b/gcc/testsuite/c-c++-common/fhardened-9.c @@ -0,0 +1,9 @@ +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */ +/* { 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 8c3fcd337be..85450d97a1a 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -1568,6 +1568,13 @@ process_options () flag_associative_math = 0; } + if (flag_hardened && !HAVE_FHARDENED_SUPPORT) + { + warning_at (UNKNOWN_LOCATION, 0, + "%<-fhardened%> not supported for this target"); + flag_hardened = 0; + } + /* -fstack-clash-protection is not currently supported on targets where the stack grows up. */ if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD) @@ -1577,6 +1584,19 @@ process_options () "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. */ @@ -1592,8 +1612,9 @@ process_options () 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)